querying XML with Namespaces (with xmlns) using XPathTags: xmlsilverlightwebserviceencodingwpfinclude2012-06-19 10:26 3235 People read comments (0) favorite reports Classification:XML (7)
Recently encountered a small problem, by calling WebService to return the following XML,
<seller xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd= "Http://www.w3.org/2001/XMLSchema" >
<id xmlns= "http://www.aaa.com/" >348388</id>
<gender xmlns= "http://www.aaa.com/" >Monsieur</gender>
<lastname xmlns= "http://www.aaa.com/" >FABRIZZI</lastName>
<firstname xmlns= "http://www.aaa.com/" >FRANCIS</firstName>
<login xmlns= "http://www.aaa.com/" >[email protected]</login>
<password xmlns= "http://www.aaa.com/" >KUVOTFP</password>
<profile xmlns= "http://www.aaa.com/" >chef de vente</profile>
<email xmlns= "http://www.aaa.com/" >[email protected]</email>
<mobilephone xmlns= "http://www.aaa.com/" >0600000000</mobilePhone>
<daterec xmlns= "http://www.aaa.com/" >2012-02-21T22:49:49.283</dateRec>
<datemod xmlns= "http://www.aaa.com/" >2012-02-21T22:49:49.283</dateMod>
<iddrv xmlns= "http://www.aaa.com/" >233734</idDrv>
<drv xmlns= "http://www.aaa.com/" >david rousseau</drv>
<IDCRV xmlns= "http://www.aaa.com/" >233775</idCrv>
<CRV xmlns= "http://www.aaa.com/" >alexandra cordier</crv>
<IDCDV xmlns= "http://www.aaa.com/" >0</idCdv>
<dealercode xmlns= "http://www.aaa.com/" >FB001</dealerCode>
<dealertype xmlns= "http://www.aaa.com/" >Premium</dealerType>
<dealerqualification xmlns= "http://www.aaa.com/" >GOLD</dealerQualification>
<dealername xmlns= "http://www.aaa.com/" >bayern aix</dealername>
<dealeraddress xmlns= "http://www.aaa.com/" >za La pioline</dealeraddress>
<dealerzipcode xmlns= "http://www.aaa.com/" >13546</dealerZipCode>
<dealercity xmlns= "http://www.aaa.com/" >aix EN provence</dealercity>
<dealerphone1 xmlns= "http://www.aaa.com/" >0442162070</dealerPhone1>
<dealerphone2 xmlns= "http://www.aaa.com/" >0442162089</dealerPhone2>
<dealersellchannel xmlns= "http://www.aaa.com/" >CCP BMW mini</dealersellchannel>
</Seller>
At that time also did not think, directly with the XPath parsing, did not think alive or dead unsuccessful, and then carefully look, the original has a name space, really head big.
Then go to Google to find the answer, the following section is transferred from the post http://www.cnblogs.com/mgen/archive/2011/05/24/2056025.html.
As is well known, XmlDocument can make XPath queries, but in fact the XPath query described here is limited to XML with no namespace (no xmlns attribute), and once the namespace XML is encountered, the corresponding XPath query will have no result.
For example, the following XML
<a xmlns= "mgen.cnblogs.com" >
<b>ccc</b>
</a>
The XPath query/a/b returns NULL, and if there is no xmlns, it returns Node B.
Why is that? The corresponding function of MSDN is explained (ref.: http://msdn.microsoft.com/en-us/library/system.xml.xmlnode.selectsinglenode.aspx)
If The XPath expression does not include a prefix, it's assumed that the namespace URI is the empty namespace. If your XML includes a default namespace, you must still add a prefix and namespace URIs to the XmlNamespaceManager; Otherwise, you'll not get any nodes selected |
This means that if the XPath expression is not prefixed (such as the prefix in A:B is a), then the namespace URI of the queried node (which can also be a node) should be null (and the default value), otherwise the XPath will not return the result.
The XML above, because both nodes A and B have namespace values, the natural XPath query will have no results.
(The above English also mentions that if the node has a default namespace, then you have to manually add the prefix and namespace values to the XmlNamespaceManager, which will be said later)
Before looking at the solution, you need to be able to identify the XML namespace, and of course it is easy to identify the XML namespace values, as in the following XML (which is also used in later programs)
<?xml version= "1.0" encoding= "Utf-8"?>
<root xmlns= "dotnet" xmlns:w= "WPF" >
<a>data in A</a>
<w:b>data in B</w:b>
<c xmlns= "Silverlight" >
<w:d>
<e>data in E</e>
</w:d>
</c>
</root>
The namespaces for all of its XML nodes are as follows:
<?xml version= "1.0" encoding= "Utf-8"?>
<root xmlns= "dotnet" xmlns:w= "WPF" >
<!--xmlns:dotnet--
<a>data in A</a>
<!--xmlns:dotnet--
<w:b>data in B</w:b>
<!--XMLNS:WPF--
<c xmlns= "Silverlight" >
<!--Xmlns:silverlight--
<w:d>
<!--XMLNS:WPF--
<e>data in E</e>
<!--Xmlns:silverlight--
</w:d>
</c>
</root>
If there is no problem in identifying the XML namespace, then the subsequent operation is fairly straightforward, and you need to remember that when querying a node with XPath in XmlDocument, you must give it a prefix as long as its namespace value is not a null value . Use this prefix to represent the namespace value of this node! These prefixes are added through the XmlNamespaceManager class and are xmlnamespacemanager into selectnodes or selectSingleNode when used. That's why it says, "If the node has a default namespace, you have to manually add the prefix and namespace value to XmlNamespaceManager."
In addition, constructing a XmlNamespaceManager requires a XmlNameTable object, which can be obtained from the xmldocument.nametable and xmlreader.nametable attributes.
Below we step into the code, for example, query the XML above the node E, the analysis location node E is located in: Root->c->d->e, and then add the required namespace values into the XmlNamespaceManager (the prefix name does not matter, As long as the XPath is consistent, the query succeeds with the following code:
/*
* Assuming that the above XML file is in C:\a.txt
* The code below will query the target node E and output the data:
* */
var xmldoc = new XmlDocument ();
Xmldoc.load (@ "C:\a.txt");
Join Namespaces and prefixes
var xmlnsm = new XmlNamespaceManager (xmldoc.nametable);
Xmlnsm. AddNamespace ("D", "dotnet");
Xmlnsm. AddNamespace ("s", "Silverlight");
Xmlnsm. AddNamespace ("W", "WPF");
var node = xmldoc.selectsinglenode ("/d:root/s:c/w:d/s:e", XMLNSM);
Console.WriteLine (node. InnerText);
Output: Data in E
Querying XML with namespaces (with xmlns) using XPath (GO)