xquery 过滤属性和元素
Posted
技术标签:
【中文标题】xquery 过滤属性和元素【英文标题】:xquery filter on attribute and element 【发布时间】:2012-07-05 15:04:58 【问题描述】:我有以下简单的 XML 文档:
<?xml version="1.0" encoding="UTF-8"?>
<cars>
<car>
<data attrib="Make">
<text>Volvo</text>
</data>
<data attrib="Model">
<text>855</text>
</data>
</car>
<car>
<data attrib="Make">
<text>Volvo</text>
</data>
<data attrib="Model">
<text>745</text>
</data>
</car>
<car>
<data attrib="Make">
<text>Volvo</text>
</data>
<data attrib="Model">
<text>V70R</text>
</data>
</car>
</cars>
还有以下 XPath:
/cars/car/data[(@attrib='Model') and (text='855')]
这将返回以下结果:
<data attrib="Model"><text>855</text></data>
我希望 XPath 为匹配返回整个 <car>
块。
所以返回数据应该是这样的:
<cars>
<car>
<data attrib="Make">
<text>Volvo</text>
</data>
<data attrib="Model">
<text>855</text>
</data>
</car>
</cars>
如何修改上面的 XPath 表达式来实现这一点?
【问题讨论】:
【参考方案1】:XPath 返回您到达的任何节点 - 在您的情况下,您将前往 data
,这就是您要返回的内容。如果您想要 car
,请将谓词放在 car
之后。
/cars/car[data/@attrib='Model' and data/text='855']
或者,稍微短一点
/cars/car[data[@attrib='Model' and text='855']]
您可以在this XMLPlayground 运行它。
XQuery 产生所需的输出:
<cars>
/cars/car[data[@attrib='Model' and text='855']]
</cars>
【讨论】:
只是添加到此响应中:这将返回选定的“汽车”元素。它不会按照要求将其包装在“汽车”元素中。因为输入不包含现有的只有一个子元素的“cars”元素,所以您只能通过构造一个新的“cars”元素来实现此输出,为此您需要 XQuery 而不是 XPath。 添加到@MichaelKay 的评论中,使用 XSLT 而不是使用 XQuery 进行此类处理更加容易和自然。 @DimitreNovaatchev 你能举一个 XSLT 的例子吗?【参考方案2】:这是一个完整的并且可能是最短的 XSLT 解决方案之一:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" />
<xsl:template match="/*">
<cars>
<xsl:copy-of select="car[data[@attrib='Model' and text='855']]"/>
</cars>
</xsl:template>
</xsl:stylesheet>
但是,使用众所周知的 identity rule 进行以下转换既更容易编写,又提供了最大的灵活性、可扩展性和可维护性:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="car[not(data[@attrib='Model' and text='855'])]"/>
</xsl:stylesheet>
当这两种转换中的任何一种应用于提供的 XML 文档时:
<cars>
<car>
<data attrib="Make">
<text>Volvo</text>
</data>
<data attrib="Model">
<text>855</text>
</data>
</car>
<car>
<data attrib="Make">
<text>Volvo</text>
</data>
<data attrib="Model">
<text>745</text>
</data>
</car>
<car>
<data attrib="Make">
<text>Volvo</text>
</data>
<data attrib="Model">
<text>V70R</text>
</data>
</car>
</cars>
产生了想要的正确结果:
<cars>
<car>
<data attrib="Make">
<text>Volvo</text>
</data>
<data attrib="Model">
<text>855</text>
</data>
</car>
</cars>
说明:
第一个转换生成顶部元素cars
,然后简单地选择想要的car
元素并将其复制为cars
的主体。
第二个转换基于最基本和最强大的 XSLT 设计模式之一 - 使用和覆盖标识规则。
身份模板“按原样”复制每个匹配的节点(选择对其进行处理)。
有一个模板覆盖了身份规则。此模板匹配任何car
不正确的data[@attrib='Model' and text='855']
。模板的主体是空的,这不会导致匹配的 car
元素被复制到输出中——换句话说,我们可以说匹配的 car
元素被“删除”了。
【讨论】:
以上是关于xquery 过滤属性和元素的主要内容,如果未能解决你的问题,请参考以下文章