为什么NamespaceManager在XPath中不使用前缀时不使用DefaultNamespace

时间:2014-10-29 12:57:25

标签: c# .net xml xpath xml-namespaces

当我想使用XPath遍历我的XmlDocument时,我遇到了文档中有许多丑陋的命名空间的问题,所以我开始使用NamespaceManager和XPath。

XML看起来像这样

<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet"
 xmlns:o="urn:schemas-microsoft-com:office:office"
 xmlns:x="urn:schemas-microsoft-com:office:excel"
 xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
 xmlns:html="http://www.w3.org/TR/REC-html40">
    <Worksheet ss:Name="KA0100401">
        <Table>
            <Row>
                <Cell>Data</Cell>
            </Row>
            <!-- more rows... -->
        </Table>
    </Worksheet>
    <Worksheet ss:Name="KA0100402">
        <!-- .... --->
    </Worksheet>
</Workbook>

现在,根据我在本文档中看到的,"urn:schemas-microsoft-com:office:spreadsheet"是默认命名空间,因为它位于根元素上。

所以天真地,我像我这样配置NamespaceManager

XmlDocument document = new XmlDocument();
document.Load(reader);
XmlNamespaceManager manager = new XmlNamespaceManager(document.NameTable);
manager.AddNamespace(String.Empty, "urn:schemas-microsoft-com:office:spreadsheet");
manager.AddNamespace("o", "urn:schemas-microsoft-com:office:office");
manager.AddNamespace("x", "urn:schemas-microsoft-com:office:excel");
manager.AddNamespace("ss", "urn:schemas-microsoft-com:office:spreadsheet");
manager.AddNamespace("html", "http://www.w3.org/TR/REC-html40");

但是,当我尝试访问节点时

foreach (XmlNode row in document.SelectNodes("/Workbook/Worksheet[1]/Table/Row", manager))

我从未得到任何结果。我的印象是,通过使用空前缀设置第一个命名空间,在搜索该工作空间中的节点时,我不需要设置它。

但是,因为它是stated on the AddNamespace method

  

如果XPath表达式不包含前缀,则假定名称空间统一资源标识符(URI)是空名称空间。

为什么?而且,更重要的是:如何访问默认命名空间中的节点,如果不使用前缀将它们设置为空命名空间?

如果我在搜索节点时甚至无法访问它,那么在管理器上设置默认命名空间有什么用呢?

4 个答案:

答案 0 :(得分:5)

来自XPath 1.0 spec

  

使用表达式上下文中的名称空间声明,将节点测试中的QName扩展为扩展名。 这与开始和结束标记中的元素类型名称的扩展相同,除了未使用xmlns声明的默认命名空间:如果QName没有前缀,则名称空间URI为null(这与扩展属性名称的方式相同)。如果QName具有在表达式上下文中没有名称空间声明的前缀,则会出错。

所以这不是关于NamespaceManager的问题,而是定义XPath的工作方式。


您缺少的一点是您在NamespaceManager中使用的前缀不一定与XML文档中的前缀类似。如果需要,您可以使用xcel urn:schemas-microsoft-com:office:excel前缀,sp使用urn:schemas-microsoft-com:office:spreadsheet前缀。实际上,您已经在命名空间管理器中为该URN分配了一个前缀,因此您可以使用它:

foreach (XmlNode row in 
       document.SelectNodes("/ss:Workbook/ss:Worksheet[1]/ss:Table/ss:Row", manager))


关于这个问题:

  

如果我在搜索节点时甚至无法访问它,那么在管理器上设置默认命名空间有什么用?

好处是XmlNamespaceManager不仅用于评估XPath。例如,它可用于跟踪XML文档中的命名空间,其中存在默认命名空间的概念。

答案 1 :(得分:2)

我无法回答你的最后一个问题(&#34;有什么好处......&#34;)除非它可能有助于非XPath情况。但关于&#34;如何访问默认命名空间中的节点,如果不使用前缀将它们设置为空命名空间?&#34;,答案是你必须使用前缀。

因此,在这种情况下,由于您将前缀ss声明为绑定到URI为urn:schemas-microsoft-com:office:spreadsheet的命名空间(与默认命名空间相同的命名空间),因此您可以使用{{ XPath表达式中的1}}前缀:

ss

答案 2 :(得分:2)

@ JLRishe的答案对于访问默认命名空间中的节点是正确的(即始终将前缀映射到XmlNamespaceManager中的默认命名空间)。

从引号(MSDN XmlNamespaceManager.AddNamespace)中读取链接的整个上下文,声明在XPath表达式中不使用默认的“empty”前缀。

  

前缀      键入:System.String

     

与要添加的命名空间关联的前缀。使用String.Empty添加默认命名空间。&gt;

     

注意如果XmlNamespaceManager将用于解析XML路径语言(XPath)表达式中的名称空间,则必须指定前缀。如果XPath表达式不包含前缀,则假定名称空间统一资源标识符(URI)是空名称空间。有关XPath表达式和XmlNamespaceManager的更多信息,请参阅XmlNode.SelectNodes和XPathExpression.SetContext方法。

答案 3 :(得分:0)

我发现如果删除默认命名空间

  

的xmlns =&#34;瓮:架构 - 微软-COM:办公室:电子表格&#34; &lt; -delete it

或使默认命名空间为null

  

的xmlns =&#34;&#34;

使用XPath进行搜索时,它不需要在没有名称空间&#34;之前添加名称空间到XPath。

那么,默认名称空间声明是否非常重要,?

如果没有,我可能会删除默认的命名空间声明,它使得使用XPath更容易搜索,因为不需要像往常一样添加命名空间。

我尝试过另一种方法是添加名称为&#34;默认&#34;的默认命名空间。由我自己提供,

我写了一个方法,可以自动添加&#34;默认&#34;没有其他命名空间的元素:

public static string XPathAddDeafultNameSpaceProccess(this string XPathProcess)
        {
            string[] XPSplit = XPathProcess.Split('/');

            for (int i = 0; i < XPSplit.Length; i++)//if element no namespace, add default
            {
                if (!XPSplit[i].Contains(':') && !XPSplit[i].Contains('@'))
                    XPSplit[i] = "default:" + XPSplit[i];
            }
            for (int i = 0; i < XPSplit.Length; i++)
            {
                if (i != XPSplit.Length - 1)//if not the last, add"/"                       
                XPSplit[i] += "/";
            }

            string output = "";
            foreach (string s in XPSplit)//combine
                output += s;
            return output;
        }

它可以转

  

AA / XX:立方厘米/ DD / HH:GG / BB&#34;

  

&#34;默认:AA / XX:CC /默认:DD / HH:GG /默认:BB&#34;

相关问题