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

F.P*_*F.P 5 .net c# xml xpath xml-namespaces

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

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>
Run Code Online (Sandbox Code Playgroud)

现在,从我在本文档中看到的"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");
Run Code Online (Sandbox Code Playgroud)

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

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

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

但是,因为它是在规定AddNamespace的方法:

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

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

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

JLR*_*she 6

XPath 1.0规范:

使用表达式上下文中的名称空间声明,将节点测试中的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))
Run Code Online (Sandbox Code Playgroud)


关于这个问题:

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

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


Mat*_*att 4

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

从您的引用( MSDN XmlNamespaceManager.AddNamespace )中读取链接的整个上下文,发现 XPath 表达式中不使用默认的“空”前缀。

前缀 类型:System.String

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

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