我有以下简单的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表达式来实现这个目标?
答案 0 :(得分:13)
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>
答案 1 :(得分:3)
以下是最简单的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设计模式之一 - 使用和覆盖身份规则。
身份模板复制每个匹配的节点(为其选择要处理的节点)&#34;原样&#34;。
有一个模板会覆盖身份规则。此模板与car
不符合的任何data[@attrib='Model' and text='855']
匹配。模板的主体是空的,这不会导致匹配的car
元素被复制到输出中 - 换句话说,我们可以说amy匹配car
元素是&#34;删除&# 34;