本文介绍了通过 XmlNamespaceManager 具有默认命名空间的 Xml-SelectNodes 未按预期工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一些带有默认命名空间的 xml

I have some xml with default namespace

<a xmlns='urn:test.Schema'><b/><b/></a>

并想统计

我必须如何定义

XmlNamespaceManager nsmgr = ????
Assert.AreEqual(2, doc.SelectNodes("//b", nsmgr).Count);

使断言变为真?

到目前为止我已经尝试过(使用 nunit):

I have tried so far (using nunit):

[Test]
[Ignore("Why does this not work?")]
public void __DoesNotWork_TestSelectWithDefaultNamespace()
{
    // xml to parse with defaultnamespace
    string xml = @"<a xmlns='urn:test.Schema'><b/><b/></a>";

    XmlDocument doc = new XmlDocument();
    doc.LoadXml(xml);

    // fails because xpath does not have the namespace
    //!!!!
    Assert.AreEqual(2, doc.SelectNodes("//b").Count);

    // using XPath defaultnamespace
    XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
    nsmgr.AddNamespace("", "urn:test.Schema");

    // This will fail with dotnet 3.5sp1. Why?
    //!!!!
    Assert.AreEqual(2, doc.SelectNodes("//b", nsmgr).Count);
}

[Test]
public void TestSelectWithoutNamespaces_Ok()
{
    // xml to parse without namespace
    string xml = @"<a><b/><b/></a>";

    XmlDocument doc = new XmlDocument();
    doc.LoadXml(xml);

    // works ok
    Assert.AreEqual(2, doc.SelectNodes("//b").Count);

    // works ok
    XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
    Assert.AreEqual(2, doc.SelectNodes("//b", nsmgr).Count);
}

[Test]
public void TestSelectWithNamespacesPrefixed_Ok()
{
    // xml to parse with defaultnamespace
    string xml = @"<a xmlns='urn:test.Schema'><b/><b/></a>";

    XmlDocument doc = new XmlDocument();
    doc.LoadXml(xml);

    // using XPath namespace via alias "t". works ok but xpath is to complicated
    XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
    nsmgr.AddNamespace("t", doc.DocumentElement.NamespaceURI);
    Assert.AreEqual(2, doc.SelectNodes("//t:b", nsmgr).Count);
}

推荐答案

// This will fail with dotnet 3.5sp1. Why?
//!!!!
Assert.AreEqual(2, doc.SelectNodes("//b", nsmgr).Count);

这是一个常见问题.在 XPath 中,任何不带前缀的名称都被假定为无命名空间".为了选择属于命名空间的元素,在任何 XPath 表达式中,它们的名称都必须以与该命名空间相关联的前缀为前缀.AddNamespace() 方法正是为了这个目的.它在特定命名空间和特定前缀之间创建绑定.然后,如果在 XPath 表达式中使用此前缀,则可以选择以它为前缀的元素.

This is a FAQ. In XPath any unprefixed name is assumed to be in "no namespace". In order to select elements that belong to a namespace, in any XPath expression their names must be prefixed with a prefix that is associated with this namespace. The AddNamespace() method serves exactly this purpose. It creates a binding between a specific namespace and a specific prefix. Then, if this prefix is used in an XPath expression, the element prefixed by it can be selected.

它写在 XPath W3C 规范: "节点测试中的 QName 使用表达式上下文中的命名空间声明扩展为扩展名称.这与对开始和结束标记中的元素类型名称进行扩展的方式相同,除了使用 xmlns 声明的默认命名空间未使用:如果 QName 没有前缀,则命名空间 URI 为空".

It is written in the XPath W3C spec: "A QName in the node test is expanded into an expanded-name using the namespace declarations from the expression context. This is the same way expansion is done for element type names in start and end-tags except that the default namespace declared with xmlns is not used: if the QName does not have a prefix, then the namespace URI is null".

参见:w3.org/TR/xpath/#node-tests .

See this at: w3.org/TR/xpath/#node-tests .

因此,任何不带前缀的名称都被视为无命名空间".在提供的 XML 文档中,无命名空间"中没有 b 元素,这就是 XPath 表达式 //b 根本不选择任何节点的原因.

So, any unprefixed name is considered to be in "no namespace". In the provided XML document there are no b elements in "no namespace" and this is why the XPath expression //b selects no nodes at all.

使用:

XmlNamespaceManager nsmanager = new XmlNamespaceManager(doc.NameTable);
nsmanager.AddNamespace("x", "urn:test.Schema");

及以后:

Assert.AreEqual(2, doc.SelectNodes("//x:b", nsmanager).Count);

记住:注册命名空间的全部目的是能够在任何 XPath 表达式中使用前缀(在本例中为 x).

Remember: The whole purpose of registering the namespace is to be able to use the prefix (in this case x) in any XPath expression.

这篇关于通过 XmlNamespaceManager 具有默认命名空间的 Xml-SelectNodes 未按预期工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-22 20:36