Sco*_*ord 34 c# xpath linq-to-xml xml-namespaces
什么是XPath(在C#API中XDocument.XPathSelectElements(xpath,nsman),如果重要的话)查询此文档中的所有MyNode?
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<MyNode xmlns="lcmp" attr="true">
<subnode />
</MyNode>
</configuration>
Run Code Online (Sandbox Code Playgroud)
/configuration/MyNode这是错误的,因为它忽略了命名空间./configuration/lcmp:MyNode哪个是错的,因为lcmp是URI,而不是前缀./configuration/{lcmp}MyNode哪个失败了因为Additional information: '/configuration/{lcmp}MyNode' has an invalid token.编辑:我不能mgr.AddNamespace("df", "lcmp");像一些回答者所建议的那样使用.这要求XML解析程序知道我计划提前使用的所有命名空间.由于这适用于任何源文件,我不知道手动添加前缀的命名空间.它似乎{my uri}是XPath语法,但微软并没有打算实现那个......是真的吗?
Mad*_*sen 37
该configuration元素位于未命名的命名空间中,MyNode绑定到lcmp没有命名空间前缀的命名空间.
这个XPATH语句将允许您在MyNode没有声明lcmp命名空间或在XPATH中使用命名空间前缀的情况下寻址元素:
/configuration/*[namespace-uri()='lcmp' and local-name()='MyNode']
Run Code Online (Sandbox Code Playgroud)
它匹配任何子元素,configuration然后使用谓词文件管理器namespace-uri()和local-name()函数将其限制为MyNode元素.
如果你不知道哪个namespace-uri将用于元素,那么你可以使XPATH更通用,只需匹配local-name():
/configuration/*[local-name()='MyNode']
Run Code Online (Sandbox Code Playgroud)
但是,您冒着匹配碰巧使用相同名称的不同词汇表(绑定到不同名称空间 - uri)中的不同元素的风险.
Mar*_*nen 12
您需要使用XmlNamespaceManager,如下所示:
XDocument doc = XDocument.Load(@"..\..\XMLFile1.xml");
XmlNamespaceManager mgr = new XmlNamespaceManager(new NameTable());
mgr.AddNamespace("df", "lcmp");
foreach (XElement myNode in doc.XPathSelectElements("configuration/df:MyNode", mgr))
{
Console.WriteLine(myNode.Attribute("attr").Value);
}
Run Code Online (Sandbox Code Playgroud)
XPath(故意)不适用于您希望对仅存在于XML文档中的某些未知命名空间使用相同XPath表达式的情况.您需要提前知道命名空间,将命名空间声明为XPath处理器,并在表达式中使用该名称.Martin和Dan的答案显示了如何在C#中做到这一点.
这种困难的原因最好在XML命名空间规范中表达:
我们设想了可扩展标记语言(XML)的应用,其中单个XML文档可以包含为多个软件模块定义和使用的元素和属性(这里称为"标记词汇表").这样做的一个动机是模块化:如果存在这样一个易于理解的标记词汇表并且有可用的软件,那么最好重新使用这个标记而不是重新发明它.
这些包含多个标记词汇表的文档会带来识别和冲突的问题.软件模块需要能够识别它们设计要处理的元素和属性,即使面对当某些其他软件包的标记使用相同的元素名称或属性名称时发生的"冲突".
这些注意事项要求文档构造应该构造名称,以避免来自不同标记词汇表的名称之间的冲突.该规范描述了一种机制,即XML命名空间,它通过为元素和属性分配扩展名来实现这一点.
也就是说,命名空间应该用于确保您知道您的文档正在讨论的内容:该<head>元素是在谈论XHTML文档的序言还是在AnatomyML文档中的某些主题?你永远不会"假定"对命名空间不可知,它几乎是你应该在任何XML词汇表中定义的第一件事.
它应该可以做你想要的,但我不认为它可以在一个XPath表达式中完成.首先,您需要在文档中翻找并提取所有namespaceURI,然后将这些添加到命名空间管理器,然后运行您想要的实际XPath表达式(并且您需要了解文档中命名空间的分布情况)点,或者你有很多表达式要运行).我认为你可能最好使用XPath以外的东西(例如DOM或类似SAX的API)来查找namespaceURI,但你也可以探索XPath命名空间轴(在XPath 1.0中),使用该namespace-uri-from-QName函数(在XPath 2.0中)或使用像Oleg这样的表达"configuration/*[local-name() = 'MyNode']".无论如何,我认为你最好的办法是尽量避免编写名称空间无关的XPath!你为什么不提前知道你的命名空间?你怎么避免匹配你不打算匹配的东西?
编辑 - 你知道namespaceURI吗?
事实证明,你的问题困扰了我们所有人.显然你知道命名空间URI,但是你不知道XML文档中使用的命名空间前缀.实际上,在这种情况下,不使用名称空间前缀,并且URI成为定义它的默认namspace.要知道的关键是所选择的前缀(或缺少前缀)与XPath表达式(以及一般的XML解析)无关.当文档表示为文本时,前缀/ xmlns属性只是将节点与名称空间URI相关联的一种方法.您可能想看看这个答案,我尝试澄清名称空间前缀.
您应该尝试以与解析器相同的方式来考虑XML文档 - 每个节点都有一个名称空间URI和一个本地名称.命名空间前缀/继承规则只是省去了很多次输入URI.写下来的一种方法是用Clark表示法:也就是说,你写{ http://www.example.com/namespace/example } LocalNodeName,但这种表示法通常只用于文档 - XPath对这种表示法一无所知.
相反,XPath使用自己的名称空间前缀/ns1:root/ns2:node.类似于.但这些与原始XML文档中可能使用的任何前缀完全分开,并且没有任何关系.任何XPath实现都可以使用命名空间URI映射它自己的前缀.对于C#实现,您XmlNamespaceManager在Perl中使用了一个散列,xmllint接受命令行参数......所以您需要做的就是为您知道的命名空间URI创建一些任意前缀,并在XPath表达式中使用此前缀.使用什么前缀并不重要,在XML中你只关心URI和localName的组合.
要记住的另一件事(通常是一个惊喜)是XPath不执行命名空间继承.无论命名空间是来自继承,xmlns属性还是命名空间前缀,都需要为每个具有命名空间的前缀添加前缀.此外,尽管您应该始终考虑URI和localNames,但也有一些方法可以从XML文档中访问前缀.很难使用这些.
| 归档时间: |
|
| 查看次数: |
28141 次 |
| 最近记录: |