【问题标题】:Namespace agnostic XPath query with element content带有元素内容的命名空间不可知 XPath 查询
【发布时间】:2011-06-24 14:35:36
【问题描述】:

我见过的与命名空间无关的语法让我感到困惑。

说我有:

<root>
  <parent attribute="A">A<child>A</child></parent>
  <parent attribute="B">B<child>B</child></parent>
</root>

到目前为止,我看到了:

/root/parent/child/text()

翻译为:

/*[local-name()='root']/*[local-name()='parent']/*[local-name()='child']/text()

但我正在为这样的事情苦苦挣扎:

/root/parent[@attribute="A"]/child/text()

或:

/root/parent[text()="B"]/child/text()

或:

/root/parent[1]/child/text()

这些如何翻译?

谢谢,

编辑:还有一个:-)

<root>
        <parent>
            <childName>serverName</childName>
            <childValue>MyServer</childValue>
        </parent>
        <parent>
            <childName>ServerLocation</childName>
            <childValue>Somewhere</childValue>
         </parent>
</root>

这是怎么翻译的?

/root/parent[childName="serverName"]/childValue/text()

【问题讨论】:

  • 好问题,+1。有关所有提供的 XPath 表达式的建议、警告和完整翻译,请参阅我的答案。

标签: xpath namespaces default xml-namespaces


【解决方案1】:

我使用的与命名空间无关的语法 看到周围让我感到困惑。

首先,我建议您不要使用这种语法,尤其是当它令人困惑时。它也可能导致错误 - 有关详细信息,请参阅我的答案的结尾。

在 XPath 表达式中指定名称空间中的名称的标准方法是向您的 XPath 引擎注册名称空间(请参阅相应的供应商特定文档),然后使用绑定到已注册名称空间的前缀(例如"x") 名称类似于 x:someName

关于这个主题有很多很好的答案 - 只需使用其中一个即可。

现在,如果由于某种原因您仍然决定使用令人困惑的语法,那么:

但我正在为之类的事情苦苦挣扎 这个:

/root/parent[@attribute="A"]/child/text()

使用

/*[local-name()='root']/*[local-name()='parent' and @attribute='A']

然后:

或:

/root/parent[text()="B"]/child/text()

使用

/*[local-name()='root']/*[local-name()='parent' and text()='B']
                                    /*[local-name()='child']/text()

然后:

或:

/root/parent[1]/child/text()

使用

/*[local-name()='root']/*[local-name()='parent'][1]
                                 /*[local-name()='child']/text()

然后:

还有一个:-)

<root>
  <parent>
      <childName>serverName</childName>
      <childValue>MyServer</childValue>
  </parent>
  <parent>
      <childName>ServerLocation</childName>
      <childValue>Somewhere</childValue>
  </parent>
</root>

如何翻译?

/root/parent[childName="serverName"]/childValue/text()

使用

/*[local-name()='root']
      /*[local-name()='parent'][*[local-name()='childName"]='serverName']
                                           /*[local-name()='childValue']/text()

请注意

如果 XML 文档中存在属于两个不同名称空间的具有相同本地名称的元素,则此类表达式可能不会选择所需的节点。

【讨论】:

  • 感谢 Dimitre,请考虑您的警告 :-) 不幸的是,我不得不使用这种类型的 xpath,因为我需要在系统搜索功能的 InstallShield 中使用它。不幸的是,该功能无法定义命名空间。我正在搜索的 XML 文件只有 1 个命名空间,所以我很安全。顺便说一句,它们是 Tomcat web.xml 配置文件。谢谢!
  • @antize:我很高兴我的回答很有帮助。在 SO,表达感谢的既定方式是接受答案(为此,只需单击答案旁边的复选标记):)。
  • 抱歉,我没想到我可以选中已回答的复选框以获取多个答案。 Dimitre,我对我最初的问题进行了编辑,询问了另一种情况。你能帮我解决那个问题吗?谢谢!
  • @antize:不客气。我在回答中添加了您上次翻译请求的解决方案。
【解决方案2】:

我理解您的问题的意思是,如何使这些 XPath 表达式与命名空间无关? (这不是特殊语法,只是 local-name() 函数的典型用法。)

/root/parent[@attribute="A"]/child/text()

会变成

/*[local-name()='root']/*[local-name()='parent'][@attribute='A']/*[local-name()='child']/text()

(如果需要,您可以对属性值使用双引号,但这会使嵌入 XSLT 或任何您的环境变得更加困难。)

/root/parent[text()="B"]/child/text()

会变成

/*[local-name()='root']/*[local-name()='parent'][text() = 'B']/*[local-name()='child']/text()

/root/parent[1]/child/text()

会变成

/*[local-name()='root']/*[local-name()='parent'][1]/*[local-name()='child']/text()

【讨论】:

  • 好久不见:) 你去哪儿了?我认为这对您来说可能很有趣:dnovatchev.wordpress.com/2011/02/08/…
  • 谢谢 LarsH,这似乎很简单,因为已经有方括号过滤了从“*”返回的结果我不确定加法过滤器的外观。谢谢,我希望这对其他人也有帮助!
  • @antize: 是的......尽管正如@Dimitre 所示,您也可以在同一谓词中使用and ... 过滤结果。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-23
相关资源
最近更新 更多