如何使用XSLT比较(部分)XML文档的子树,将基于比较的布尔值作为单个标记返回?

时间:2013-07-29 14:40:52

标签: xslt xslt-2.0

假设存在一个软件系统,该系统允许使用XSLT在XML消息上指定某个谓词。具体来说:将输入文档转换为以下格式的输出文档:<predicate>true</predicate>(或<predicate>false</predicate>)。

对于一些简单的情况(如 message contains XPath ),这是相当简单的,但我现在需要为以下内容编写一个XSLT:

<change>

  <!-- state before change -->
  <item>
    <name>
      <first>...</first>
      <last>...</last>
    </name>
    <something>
       ...
    </something>
  </item>

  <!-- state after change -->
  <item>
    <name>
      <first>...</first>
      <last>...</last>
    </name>
    <something>
       ...
    </something>
  </item>

</change>

如果符合以下情况,我想返回<predicate>true</predicate>来获取变异的定义:

  • 之前或之后的状态(或两者)实际上包含something数据的子树(因为此部分是可选的),所以基本上change/item[1]/something | change/item[2]/something
  • 删除了something数据的前后状态并不相同。

第二部分可能类似于以下伪代码:$before变量change/item[1]/something,其中已删除任何现有的something子树,$after变量为{{1}从任何现有的change/item[2]/something子树中删除它,然后可能像something ......?

任何人都知道如何使用XSLT 2.0来实现这一点,因为我怀疑在XSLT 1.0中完全不可能这样做?

1 个答案:

答案 0 :(得分:0)

尝试

<xsl:template match="change">
  <xsl:choose>
    <xsl:when test="item[1]/something | item[2]/something">
      <xsl:variable name="before" as="element(item)">
        <xsl:apply-templates select="item[1]" mode="rs"/>
      </xsl:variable>
      <xsl:variable name="after" as="element(item)">
        <xsl:apply-templates select="item[2]" mode="rs"/>
      </xsl:variable>
      <predicate><xsl:value-of select="not(deep-equal($before,$after))"/></predicate>
    </xsl:when>
    <xsl:otherwise>
      <predicate>false</predicate>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<xsl:template match="@* | node()" mode="rs">
  <xsl:copy>
    <xsl:apply-templates select="@* , node()" mode="rs"/>
  </xsl:copy>
</xsl:template>

<xsl:template match="something" mode="rs"/>

未经测试但应该给你一个想法。它基本上在mode="rs"remove-something)上对两个item元素进行转换,以剥离something元素,然后执行您发布的比较(not(deep-equal($before,$after)) )。