1500字范文,内容丰富有趣,写作好帮手!
1500字范文 > 使用XPath查询带有命名空间(有xmlns)的XML(转)

使用XPath查询带有命名空间(有xmlns)的XML(转)

时间:2020-09-02 05:17:02

相关推荐

使用XPath查询带有命名空间(有xmlns)的XML(转)

使用XPath查询带有命名空间(有xmlns)的XML

标签:xmlsilverlightwebserviceencodingwpfinclude -06-19 10:263235人阅读评论(0)收藏举报 分类: XML(7)

最近碰到一个小问题,通过调用webservice返回如下的xml,

<Seller xmlns:xsi="/2001/XMLSchema-instance" xmlns:xsd="/2001/XMLSchema">

<id xmlns="/">348388</id>

<gender xmlns="/">Monsieur</gender>

<lastName xmlns="/">FABRIZZI</lastName>

<firstName xmlns="/">FRANCIS</firstName>

<login xmlns="/">francis.fabrizzi@bayern-.bmw.fr</login>

<password xmlns="/">KUVOTFP</password>

<profile xmlns="/">Chef de vente</profile>

<email xmlns="/">francis.fabrizzi@bayern-.bmw.fr</email>

<mobilePhone xmlns="/">0600000000</mobilePhone>

<dateRec xmlns="/">-02-21T22:49:49.283</dateRec>

<dateMod xmlns="/">-02-21T22:49:49.283</dateMod>

<idDrv xmlns="/">233734</idDrv>

<drv xmlns="/">DAVID ROUSSEAU</drv>

<idCrv xmlns="/">233775</idCrv>

<crv xmlns="/">ALEXANDRA CORDIER</crv>

<idCdv xmlns="/">0</idCdv>

<dealerCode xmlns="/">FB001</dealerCode>

<dealerType xmlns="/">Premium</dealerType>

<dealerQualification xmlns="/">GOLD</dealerQualification>

<dealerName xmlns="/">BAYERN AIX</dealerName>

<dealerAddress xmlns="/">ZA La Pioline</dealerAddress>

<dealerZipCode xmlns="/">13546</dealerZipCode>

<dealerCity xmlns="/">AIX EN PROVENCE</dealerCity>

<dealerPhone1 xmlns="/">0442162070</dealerPhone1>

<dealerPhone2 xmlns="/">0442162089</dealerPhone2>

<dealerSellChannel xmlns="/">CCP BMW Mini</dealerSellChannel>

</Seller>

当时也没有多想,直接用xpath解析了,没想到死活不成功,再仔细一看,原来有命名空间,真是头大。

然后去google找答案,如下部分转自帖子/mgen/archive//05/24/2056025.html。

众所周知,XmlDocument可以进行XPath查询,但实际上这里所说的XPath查询仅限于没有命名空间(没有xmlns属性)的XML,一旦遇到有命名空间的XML,对应XPath查询都会无结果。

比如下面这个XML

<axmlns="">

<b>ccc</b>

</a>

XPath查询/a/b会返回null,而如果没有xmlns的话,会返回节点b。

为什么会这样呢?MSDN的相应函数有解释(参考:/en-us/library/system.xml.xmlnode.selectsinglenode.aspx)

意思就是如果XPath表达式没有加前缀(如a:b中前缀是a),那么所查询节点(注意属性也可以是节点)的命名空间URI就应该是空值(也是默认值),否则XPath不会返回结果。

上面的XML, 因为节点a和b都有命名空间值,自然XPath查询不会有结果。

(上面英文还提到如果节点有默认命名空间,那么还得手动向XmlNamespaceManager添加前缀和命名空间值,这个在后面会讲的)

在看解决方案前,首先需要能够辨识XML命名空间,当然辨识XML命名空间值还是很容易的,参考如下XML(这个XML在后面程序中也会用到)

<?xmlversion="1.0"encoding="utf-8"?>

<rootxmlns="dotnet"xmlns:w="wpf">

<a>data in a</a>

<w:b>data in b</w:b>

<cxmlns="silverlight">

<w:d>

<e>data in e</e>

</w:d>

</c>

</root>

它的所有XML节点的命名空间如下所示:

<?xmlversion="1.0"encoding="utf-8"?>

<rootxmlns="dotnet"xmlns:w="wpf">

<!--xmlns: dotnet-->

<a>data in a</a>

<!--xmlns: dotnet-->

<w:b>data in b</w:b>

<!--xmlns: wpf-->

<cxmlns="silverlight">

<!--xmlns: silverlight-->

<w:d>

<!--xmlns: wpf-->

<e>data in e</e>

<!--xmlns: silverlight-->

</w:d>

</c>

</root>

如果识别XML命名空间没有问题,那么后面的操作就相当简单了,你需要记住:在XmlDocument中用XPath查询某一节点时,只要它的命名空间值不是空值,那么你必须给它一个前缀,用这个前缀代表这个节点的命名空间值!这些前缀是通过XmlNamespaceManager类添加的,使用时将XmlNamespaceManager传入SelectNodes或SelectSingleNode中即可。这也是为什么上面说“如果节点有默认命名空间,那么还得手动向XmlNamespaceManager添加前缀和命名空间值”的原因。

另外构造一个XmlNamespaceManager需要XmlNameTable对象,这个对象可以从XmlDocument.NameTable和XmlReader.NameTable属性中得到。

下面我们步入代码,比如说查询上面XML中的节点e,分析位置节点e位于:root->c->d->e,然后将所需命名空间值加入到XmlNamespaceManager中(前缀名称无所谓,只要在XPath一致即可),查询即可成功,如下代码:

/*

* 假设上面XML文件在C:\a.txt中

* 下面代码会查询目标节点e,并输出数据:data in e

* */

varxmlDoc=newXmlDocument();

xmlDoc.Load(@"C:\a.txt");

//加入命名空间和前缀

varxmlnsm=newXmlNamespaceManager(xmlDoc.NameTable);

xmlnsm.AddNamespace("d","dotnet");

xmlnsm.AddNamespace("s","silverlight");

xmlnsm.AddNamespace("w","wpf");

varnode=xmlDoc.SelectSingleNode("/d:root/s:c/w:d/s:e", xmlnsm);

Console.WriteLine(node.InnerText);

//输出:data in e

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。