xpath evaluation  
Author Message
jss3426





PostPosted: XML and the .NET Framework, xpath evaluation Top

I have the result stream from a third party webservice as such

< xml version="1.0" encoding="utf-8" >
<soap:Envelope xmlns:soap=" http://www.hide-link.com/ " xmlns:xsi=" http://www.hide-link.com/ " xmlns:xsd=" http://www.hide-link.com/ ">
<soap:Body>
<CompanyName xmlns="somehowhere">
<Date>10/10/2006</Date>
<SubCompany>
<Company id="3490561" serviceid="112233"><OnLine Code="OK">OK</OnLine></Company>
</SubCompany>
</CompanyName>
</soap:Body></soap:Envelope>

I tried using the xpathnavigator method but to no avail. Am trying to evaluate the value of Online[Code="OK"] but have been unable to

my expression is

)

any help would be appreciated.



.NET Development10  
 
 
Dimitre_Novatchev





PostPosted: XML and the .NET Framework, xpath evaluation Top

This is a FAQ.

The "CompanyName" and all of its descendents belong to the (default) namespace "somehowhere" and cannot be accessed if in an XPath expression their names are not prefixed.

Therefore, one way to solve this problem is to bind some prefix (let say "xxx") to the "somehowhere" namespace (to do this use the XmlNamespaceManager class).

Then the XPath Expression will be something like this:

Cheers,
Dimitre Novatchev


 
 
jss3426





PostPosted: XML and the .NET Framework, xpath evaluation Top

Dimitre,

This is what I did

XPathNavigator xPathNavigator = xPathDocument.CreateNavigator();

XmlNamespaceManager manager = new XmlNamespaceManager(xPathNavigator.NameTable);

manager.AddNamespace("sp","somewhere");

expression = (/soap:Envelope/soap:Body/xxx:CompanyName /xxx:SubCompany/xxx:Company /xxx:OnLine

value = (string)xPathNavigator.Evaluate(expression);

throws an exception

"System.Xml.XPath.XPathException: Namespace Manager or XsltContext needed. This query has a prefix, variable, or user-defined function.\r\n at System.Xml.XPath.CompiledXpathExpr.get_QueryTree()\r\n at System.Xml.XPath.XPathNavigator.Evaluate(XPathExpression expr, XPathNodeIterator context)\r\n at System.Xml.XPath.XPathNavigator.Evaluate(String xpath)\r\n


 
 
Dimitre_Novatchev





PostPosted: XML and the .NET Framework, xpath evaluation Top

XmlNamespaceManager is passed as the second parameter to the

XmlNode.SelectNodes () method

The XPathNavigator.Evaluate() method requires an IXmlNamespaceResolver object specified to resolve namespace prefixes in the XPath expression.

You can use one or the other, the former seems more simple.

Cheers,
Dimitre Novatchev


 
 
jss3426





PostPosted: XML and the .NET Framework, xpath evaluation Top

Dimitry,

Solved my issue. I had to add

XmlNamespaceManager.AddNameSpace("soap","http://schemas.xmlsoap.org/soap/envelope/")

and then used the expression as such.

(/soap:Envelope/soap:Body/xxx:CompanyName /xxx:SubCompany/xxx:Company /xxx:OnLine ).

Now my question is I want to build a generic AddNAmeSpaceManager which will ad all the namespaces by viewing the document. Is there an easy way out for this

Thanks


 
 
Dimitre_Novatchev





PostPosted: XML and the .NET Framework, xpath evaluation Top

Yes -- using XSLT

Could you ask this as a separate question, though

And mark one of the replies as the answer to this question :o)

Seriously, it doesn't look good if we still seem to have unanswered questions (not just few) -- and on the other side we have really answered a big part of them, but the original posters didn't mark their questions as answered.

Cheers,
Dimitre Novatchev


 
 
Dimitre_Novatchev





PostPosted: XML and the .NET Framework, xpath evaluation Top

> Now my question is I want to build a generic AddNAmeSpaceManager which will ad all the namespaces by

> viewing the document. Is there an easy way out for this

Here's one example how this is being done in C# (not using XSLT).

Here's some working code that may be used as a base:

private void setNamespaces()

{

XPathNodeIterator itNameSpaces =

xmlSource.CreateNavigator().Select("//namespace::*");

int numNamespaces = itNameSpaces.Count;

string strNamespace = "";

if (numNamespaces > 0)

{

while (itNameSpaces.MoveNext())

{

XPathNavigator thisNamespace = itNameSpaces.Current;

string strName = "xmlns:" + thisNamespace.Name;

string strURI = thisNamespace.Value;

string strKey = strName + strDelim[0] + strURI;

if (!ReservedURIs.Contains(strURI)

&&

!dict_usrNamespaces.ContainsKey(strKey)

)

{

dict_usrNamespaces.Add(strKey, "");

}

}

}

}

What remains to be done is to add all namespaces collected in this way to the XmlNamespaceManager.

In case there are default namespaces, then the program must autogenerate some prefix names.

Hope this helped.

Cheers,
Dimitre Novatchev


 
 
jss3426





PostPosted: XML and the .NET Framework, xpath evaluation Top

Thank You Dimitre. Will shout out once i try it out. Out of curiosity could you pointy me in direction if I were to use XSLT If you wish i can start a new thread for it :)
 
 
Dimitre_Novatchev





PostPosted: XML and the .NET Framework, xpath evaluation Top

Here's how to find all namespace bindings in an xml document with XSLT.

The following XSLT stylesheet:

<xsl:stylesheet version="1.0"

xmlns:xsl="http://www.w3.org/1999/XSL/Transform"

xmlns:msxsl="urn:schemas-microsoft-com:xslt"

exclude-result-prefixes="msxsl"

>

<xsl:output omit-xml-declaration="yes" indent="yes"/>

<xsl:key name="kNS" match="namespace"

use=" "/>

<xsl:template match="/">

<xsl:variable name="vrtfNamespaces">

<xsl:for-each select="//namespace::*">

<namespace pref="{name()}" uri="{.}"/>

</xsl:for-each>

</xsl:variable>

<xsl:for-each select="msxsl:node-set($vrtfNamespaces)">

<xsl:for-each select=

"namespace[generate-id()

=

generate-id(key('kNS',

)[1]

)

]"

>

<xsl:copy-of select=" "/>

</xsl:for-each>

</xsl:for-each>

</xsl:template>

</xsl:stylesheet>

when applied against this xml document

< xml version="1.0" >

<!-- This is a sample XML document -->

< x PI="5" >

<!DOCTYPE Items [

<!ENTITY number "123">

]>

<ttt:Items xmlns="sfsfsf" xmlns:ttt="ddzdzdf">

<Item a1 = "1" a2="2" ax="x">Test with an entity:

&number;</Item>

&number;

<Item>

test with a child element <more/> stuff

</Item>&#65;

<Item a3 = "3" /><Item a4 = "4" />

<x/>

<Item>test with a CDATA section <![CDATA[<456>]]> def</Item>

<Item>Test with an char entity: &#65;</Item>

<!-- Four**** chars in this element.-->

<Item>1234567890ABCD</Item>

</ttt:Items>

< x PI="5" >

<!-- This is the end of the sample XML document -->

< x PI="5" >

produces the wanted result:

<namespace pref="" uri="sfsfsf" />
<
namespace pref="ttt" uri="ddzdzdf" />

Cheers,
Dimitre Novatchev