11

我有以下简单的 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 表达式来实现这一点?

4

2 回答 2

15

XPath 返回您要到达的任何节点-在您的情况下,您将要到达data,这就是您要返回的内容。如果您愿意car,请将您的谓词放在car.

/cars/car[data/@attrib='Model' and data/text='855']

或者,稍微短一点

/cars/car[data[@attrib='Model' and text='855']]

您可以在这个 XMLPlayground上运行它。

XQuery 以产生所需的输出:

<cars>
  {/cars/car[data[@attrib='Model' and text='855']]}
</cars>
于 2012-07-05T08:36:25.470 回答
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>

但是,使用众所周知的恒等规则的以下转换既更容易编写,又提供了最大的灵活性、可扩展性和可维护性:

   <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>

说明

  1. 第一个转换生成顶部元素cars,然后简单地选择想要的car元素并将其复制为 的主体cars

  2. 第二个转换基于最基本和最强大的 XSLT 设计模式之一——使用和覆盖标识规则。

  3. 身份模板“按原样”复制每个匹配的节点(选择对其进行处理)。

  4. 有一个模板覆盖了身份规则。此模板匹配任何car不正确的data[@attrib='Model' and text='855']. 模板的主体是空的,这不会导致匹配car元素被复制到输出中——换句话说,我们可以说 amy 匹配car元素被“删除”了。

于 2012-07-06T12:21:18.320 回答