我有几个XML文档,所有这些文档都具有相同的结构(元素名称,属性名称和层次结构)。
但是,某些元素和属性在每个XML文档中都有自定义命名空间,这些命名空间在设计时是未知的。他们改变了,不要问......
如何在使用一组XPath遍历文档时处理此问题?
我应该在处理之前删除所有名称空间吗?
我可以使用XmlNamespaceManager自动注册所有名称空间吗?
有什么想法吗?
更新:一些示例(为清晰起见,省略了名称空间声明):
<root>
<child attr="val" />
</root>
<root>
<x:child attr="val" />
</root>
<root>
<y:child z:attr="val" />
</root>
由于
答案 0 :(得分:2)
假设你有以下xml:
<root xmlns="first">
<el1 xmlns="second">
<el2 xmlns="third">...
您可以通过以下方式编写查询以忽略名称空间:
/*[local-name()='root']/*[local-name()='el1']/*[local-name()='el2']
等等
当然,您可以遍历整个文档以获取命名空间并将其加载到nsmanager中。但在一般情况下,这将导致您评估文档中的每个节点。在这种情况下,将文档视为对象树并且不使用XPath会更快。
答案 1 :(得分:1)
我相信你会在这个Stackoverflow线程中找到一些很好的见解
XPath + Namespace Driving me crazy
在我看来,你有两种解决方案之一:
1-如果事先了解了所有可能的命名空间的集合,那么在开始解析之前,您可以在XmlNamespaceManager中将它们全部注册
2-使用Xpath命名空间无关的选择器
当然,您总是可以从任何内联命名空间中清除xml文档,并在没有命名空间的干净的uniorm xml上开始解析..但老实说,我没有看到添加此开销步骤的好处。
答案 2 :(得分:0)
Scott Hanselman有一个nice article关于提取XML文档中的所有XML命名空间。据推测,当您获得所有XML命名空间时,您可以迭代所有这些命名空间并在命名空间管理器中注册它们。
答案 3 :(得分:0)
您可以尝试使用这样的方法去除名称空间:
//Implemented based on interface, not part of algorithm
public string RemoveAllNamespaces(string xmlDocument)
{
return RemoveAllNamespaces(XElement.Parse(xmlDocument)).ToString();
}
//Core recursion function
private XElement RemoveAllNamespaces(XElement xmlDocument)
{
if (!xmlDocument.HasElements)
{
XElement xElement = new XElement(xmlDocument.Name.LocalName);
xElement.Value = xmlDocument.Value;
return xElement;
}
return new XElement(xmlDocument.Name.LocalName, xmlDocument.Elements().Select(el => RemoveAllNamespaces(el)));
}
有关详细信息,请参阅Peter Stegnar的回答:
How to remove all namespaces from XML with C#?
答案 4 :(得分:0)
您还可以使用带有通配符的直接节点测试,它将匹配任何命名空间(或缺少命名空间):
$your-document/*:root/*:child/@*:attr