zoukankan      html  css  js  c++  java
  • 使用XPath查询带有命名空间(有xmlns)的XML(转)

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

    标签: xmlsilverlightwebserviceencodingwpfinclude
     分类:
     

    最近碰到一个小问题,通过调用webservice返回如下的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/">francis.fabrizzi@bayern-aix.net.bmw.fr</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/">francis.fabrizzi@bayern-aix.net.bmw.fr</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>

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

    然后去google找答案,如下部分转自帖子http://www.cnblogs.com/mgen/archive/2011/05/24/2056025.html

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

    比如下面这个XML

    <a xmlns="mgen.cnblogs.com">

        <b>ccc</b>

    </a>

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

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

    If the XPath expression does not include a prefix, it is assumed that the namespace URI is the empty namespace. If your XML includes a default namespace, you must still add a prefix and namespace URI to the XmlNamespaceManager; otherwise, you will not get any nodes selected

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

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

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

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

    <?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>

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

    <?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>

    如果识别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

                  * */

                var xmlDoc = new XmlDocument();

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

                //加入命名空间和前缀

                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);

                //输出:data in e

  • 相关阅读:
    位记录——Windows 7已安装Sublime Text 3、cynwin、SublimeClang
    尺度空间(Scale space)理论
    D3DXMatrixMultiply 函数
    素数推断算法(高效率)
    去除win7 64位系统桌面图标小箭头
    Bag标签之中的一个行代码实行中文分词实例1
    7个最好的免费杀毒软件下载
    利用Excel批量高速发送电子邮件
    Hibernate Criterion
    IOS新手教程(二)-控制流
  • 原文地址:https://www.cnblogs.com/bmaker/p/5605726.html
Copyright © 2011-2022 走看看