【问题标题】:Wrong xml node accessed when using xpath使用 xpath 时访问了错误的 xml 节点
【发布时间】:2018-10-01 10:57:40
【问题描述】:

我有一个由 Vector CANeds 生成的 xml 文件。此文件包含有关我想使用 C# 编写的工具读取的 CANopen 对象的信息。

xml的(非常基本的)结构如下:

<ISO15745ProfileContainer xmlns="http://www.canopen.org/xml/1.0">
    <ISO15745Profile>
        <ProfileHeader></ProfileHeader>
        <ProfileBody xsi:type="ProfileBody_Device_CANopen"</ProfileBody>
    </ISO15745Profile>
    <ISO15745Profile>
        <ProfileHeader></ProfileHeader>
        <ProfileBody xsi:type="ProfileBody_CommunicationNetwork_CANopen"</ProfileBody>
    </ISO15745Profile>
</ISO15745ProfileContainer>

当我创建一个包含两个 ISO15745Profile 节点的 XmlNodeList 并循环遍历时,我得到了一个奇怪的行为。通过使用显式索引访问子节点,一切都按预期进行。当我使用 xpath 时,总是使用第一个节点。

代码sn-p:

const string filepath = "CANeds1.xdd";
const string s_ns = "//ns:";
var mDataXML = new XmlDocument();
mDataXML.Load(filepath);
var root = mDataXML.DocumentElement;
XmlNamespaceManager nsm = new XmlNamespaceManager(mDataXML.NameTable);
nsm.AddNamespace("ns", root.Attributes["xmlns"].Value);

foreach (XmlNode node in root.ChildNodes) {
    Console.WriteLine("  " + node.ChildNodes[1].Attributes["xsi:type"].Value);
    Console.WriteLine("  " + node.SelectSingleNode(s_ns + "ProfileBody", nsm).Attributes["xsi:type"].Value);
}

控制台输出:

  ProfileBody_Device_CANopen
  ProfileBody_Device_CANopen
  ProfileBody_CommunicationNetwork_CANopen
  ProfileBody_Device_CANopen

由于节点引用了第二个节点,最后的输出应该是 commNetwork 到的。 有人看到我的错误吗?我已经尝试重命名“ISO15745Profile”节点之一,但这并没有改变结果。我可能把命名空间搞砸了……

【问题讨论】:

  • 能不能把不能正常工作的代码贴出来...
  • 尝试将s_ns更改为".//ns:"以选择相对于当前节点的节点。
  • 来自msdn.microsoft.com/en-us/library/ms256122(v=vs.110).aspx: // - 递归下降;在任意深度搜索指定元素。当此路径运算符出现在模式的开头时,它表示从根节点递归下降。因此您正在搜索整个文档。
  • @quanik:太好了,就这么简单。非常感谢
  • @iMattView 我在my answer添加了一些解释

标签: c# xml xpath foreach


【解决方案1】:

对cmets中给出的答案的更多解释:

重要的一点是// XPath 表达式。 from MSDN 的定义说:

递归下降;在任意深度搜索指定元素。当此路径运算符出现在模式的开头时,它表示递归下降从根节点

这意味着以// 开头的表达式将始终搜索整个文档 的出现,即使它是从特定的子注释调用的。这就是为什么SelectSingleNode 将始终返回整个文档中的第一个匹配项。

要相对于调用选择方法的节点进行搜索,可以使用. 运算符来指示当前上下文。

总之,以.// 开头的表达式将搜索以下模式的所有出现,从当前节点开始

在特定情况下,这意味着将//ns: 更改为.//ns: 以获得预期的结果。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-01-29
    • 2011-08-24
    • 1970-01-01
    • 1970-01-01
    • 2012-06-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多