【问题标题】:Difference between XPath & XQuery when selecting attribute value选择属性值时 XPath 和 XQuery 的区别
【发布时间】:2020-03-10 08:34:36
【问题描述】:

XPath 和 XQuery 选择属性的方式似乎有所不同。 这是一个从 W3Schools 被盗的玩具示例:

<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
    <book category="cooking">
        <title lang="en">Everyday Italian</title>
        <author>Giada De Laurentiis</author>
        <year>2005</year>
        <price>30.00</price>
    </book>
    <book category="children">
        <title lang="en">Harry Potter</title>
        <author>J K. Rowling</author>
        <year>2005</year>
        <price>29.99</price>
    </book>
</bookstore> 

我想检索lang 属性的值。 所以,我天真地做: //title/@lang 在 XPath 求值器上完美运行,但在 XQuery 求值器上不是

需要知道的:我应该如何编写我的 XPath 表达式以在 XQuery 求值器上工作?

知道的:发生了什么?!

这里是 TL 部分:

我在一个没有这些功能的旧平台上,所以我将 XML 和我的查询表达式发送到一个外部服务,我相信它是一个基于 Saxon 的 XQuery 评估器。我的语法在 CodeBeautify's XPath Tester 上按预期工作。

我还在xpathtester.com 上验证了这种差异:它在 XPath 模式下按预期工作,但在 XQuery 模式下却不行。 (注意:链接未加密。)。

xpathtester.com 返回以下错误消息:ERROR - Cannot create an attribute node (lang) whose parent is a document node

【问题讨论】:

  • 当 XQuery 不能工作时,您会得到哪个错误或结果?关于无法序列化不属于元素的属性节点的一些消息?
  • @Martin Honnen:xpathtester.com 抱怨“错误 - 无法创建其父节点是文档节点的属性节点 (lang)”,但我们的外部服务只是没有返回任何命中而没有抱怨。
  • 我认为你得到的结果很大程度上取决于 XQuery 工具及其使用的 API,可以在 XPath 和 XQuery 中选择一个属性节点,但 XQuery 的通常结果是一些新建然后序列化的结果和独立属性不能使用 XML 序列化的通常默认值进行序列化。在 XQuery 3.1 中,您可以使用adaptive 输出方法对它们进行序列化:xqueryfiddle.liberty-development.net/3Nzd8bR
  • 默认情况下,如果 XQuery 无法生成有效的 XML 输出,它将引发错误。属性节点序列不是有效的 XML 输出(XML 属性必须由元素节点保存,这是您的错误消息所抱怨的)。如果您想生成一个包含输入 XML 的所有 lang 属性而不使用其他输出方法 (try it here) 的 XML,则可以使用 &lt;ul&gt;{for $l in //title/@lang return &lt;li&gt;{$l}&lt;/li&gt;}&lt;/ul&gt;
  • @Aaron:感谢 XQuery 返回完整元素所需的信息。我不知道。我真的不明白你的sn-p的意义。结果不是和XPath//title一样吗?

标签: xpath xquery


【解决方案1】:

表达式//title/@lang在XPath和XQuery下都有效,返回两个属性节点的序列。

您看到的不同之处在于不同的 XPath 和 XQuery 客户端如何处理由两个属性节点组成的结果。

如果工具尝试将结果序列化为 XML,它将失败,因为 XML 序列化尝试构造文档节点并将属性附加到文档。

因此,您需要查看您的 XPath 或 XQuery 工具为显示结果提供了哪些选项。

【讨论】:

    【解决方案2】:

    在真正理解了 @Martin Honnen 和 @Aaron 所谈论的内容并深入了解了教程之后,我想我想出了一个我很满意的解决方案:

    string-join((for $l in //title/@lang return string($l)) , ',')

    https://xqueryfiddle.liberty-development.net/3Nzd8bR/2

    【讨论】:

    • 不错,请注意,您可以将其简化为string-join(//title/@lang, ','),因为string-join 会自动将其输入的元素转换为字符串。
    猜你喜欢
    • 2010-10-29
    • 1970-01-01
    • 2016-12-28
    • 1970-01-01
    • 1970-01-01
    • 2012-12-24
    • 2013-04-09
    • 1970-01-01
    • 2018-09-12
    相关资源
    最近更新 更多