【问题标题】:Use XPath to find a node by name attribute value使用 XPath 按名称属性值查找节点
【发布时间】:2011-11-15 17:15:49
【问题描述】:

我正在尝试通过 name 属性值查找节点。

这里是 xml 文档的示例:

<?xml version="1.0" encoding="utf-8" standalone="no"?>
<!DOCTYPE kfx:XMLRELEASE SYSTEM "K000A004.dtd">
<kfx:XMLRELEASE xmlns:kfx="http://www.kofax.com/dtd/">
  <kfx:KOFAXXML>
    <kfx:BATCHCLASS ID="00000008" NAME="CertficateOfLiability">
      <kfx:DOCUMENTS>
        <kfx:DOCUMENT DOCID="00000006" DOCUMENTCLASSNAME="COL">
          <kfx:DOCUMENTDATA>
            <kfx:DOCUMENTFIELD NAME="Producer Name" VALUE="Howalt+McDowell Insurance" />
           ...
           ....

这是我尝试的表达方式:

 var xml = XDocument.Load(new StreamReader("C:\\Users\\Matthew_cox\\Documents\\test.xml"));
 XNamespace ns = "http://www.kofax.com/dtd/";
 XmlNamespaceManager nsm = new XmlNamespaceManager(xml.CreateNavigator().NameTable);
 nsm.AddNamespace("kfx", ns.NamespaceName);

 var docs = xml.Descendants(ns + "DOCUMENT");
 foreach(var doc in docs)
 {
      doc.XPathSelectElement("/DOCUMENTDATA/DOCUMENTFIELD/[@name='Producer Name']", nsm); //this line produces this exception: Expression must evaluate to a node-set.
 }

【问题讨论】:

    标签: c# .net xml xpath


    【解决方案1】:

    XML 区分大小写。在提供的 XML kfx:DOCUMENTFIELD 中具有 NAME 属性。此外,您的 XPath 没有对命名空间的引用。

    试试这个 XPath:

    kfx:DOCUMENTDATA/kfx:DOCUMENTFIELD[@NAME = 'Producer Name']
    

    【讨论】:

    • 我确实提供了一个 XmlNamespaceManger 对象,正如您将在上面提到的。我认为这将处理命名空间部分,但显然不是。但是,即使使用您的版本,我的编译器仍然会抛出相同的异常,就好像我没有生成旨在返回结果集或其他内容的表达式一样。
    • 如果您在 Xpath 中包含前缀,则可以。 SelectNode("kfx:SomeNodeName/kfx:SomeChildName",SomeNameSpaceManager)
    • @Kirill Polishchuk 我去掉了命名空间以简化学习曲线(如果您没有注意到这是我第一次使用 XML 或 XPath)。如果我像这样构造我的查询,我可以获得我想要的项目:doc.XPathSelectElements("XMLRELEASE/KOFAXXML/BATCHCLASS/DOCUMENTS/DOCUMENT/DOCUMENTDATA/DOCUMENTFIELD[@NAME='Producer Name']") 不过,必须有更好的方法,必须从根开始并一直向下工作是荒谬的。
    • @MatthewCox,试试这个://DOCUMENTFIELD[@NAME='Producer Name']
    • @Kirill Polishchuk 这是一种更简洁的方法。我必须道歉。我的实际代码与我发布的示例大不相同,试图压缩它以使问题更容易识别。然而,我主要是从头开始编写问题中的示例代码,我只是注意到我的实际代码是从原始 XML 根节点执行我的搜索......难怪许多这些尝试都失败了。非常感谢您的帮助
    【解决方案2】:

    我发现有两件事不对。

    首先你选择以“/”开头,这是从文档根目录中选择的,所以去掉前导斜杠。

    其次,表达式有点奇怪。我会直接在 DOCUMENTFIELD 中包含条件。 (我不确定节点轴上是否没有表达式实际上意味着什么。如 .../[..] 等价于 .../node()[..] 甚至 .../*[.. ]?)

    正如 Kirill 所说,您还应该注意大小写和命名空间,但这应该可以解决 c# 抱怨表达式未对节点集求值的问题:

    kfx:DOCUMENTDATA/kfx:DOCUMENTFIELD[@NAME = 'Producer Name']
    

    【讨论】:

    • 朝着正确方向迈出的一步(不再例外)。但是,显然我的查询不正确,因为它没有产生任何结果。对这个问题有什么想法吗?
    • 我个人从不打扰命名空间管理器。你试过删除它吗?哦,刚刚注意到我做了一个 typeo 顺便说一句...第一个命名空间应该是 kfx 而不是 kxf,也许就是这样。如果这不起作用,则剥离所有位置的所有名称空间(源、ns-manager 和查询)并逐步添加它们。这最终为我解决了问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多