【问题标题】:Compare two xml tree nodes and find if a node with a value exists in another using xslt比较两个 xml 树节点并使用 xslt 查找具有值的节点是否存在于另一个节点中
【发布时间】:2020-10-20 12:13:20
【问题描述】:

我有一个 XML 输入,它是两个 xml 的合并格式:

<DATA>
<RECORDS1>
    <RECORD>
        <id>11</id>
        <value>123</value>
    </RECORD>
    <RECORD>
        <id>33</id>
        <value>321</value>
    </RECORD>
    <RECORD>
        <id>55</id>
        <value>121113</value>
    </RECORD>
    ...
</RECORDS1>
<RECORDS2>
    <RECORD>
        <id>11</id>
        <value>123</value>
    </RECORD>
    <RECORD>
        <id>33</id>
        <value>323</value>
    </RECORD>
    <RECORD>
        <id>44</id>
        <value>12333</value>
    </RECORD>
    ...
</RECORDS2>

我需要在输出中复制 RECORDS1 中提供的记录:

  1. RECORDS1 中的记录在 RECORDS2 中不存在
  2. RECORDS1 中的记录存在于 RECORDS2 中,但值不同

另外,如果输出可以扩展,例如使用一个额外的字段,其值为 NEW(当不存在时)作为 CHANGE(当存在但值不同时)

输出

<DATA>
<RECORDS>
    <RECORD>
        <id>33</id>
        <value>321</value>
        <kind>Change</kind>
    </RECORD>
    <RECORD>
        <id>55</id>
        <value>121113</value>
        <kind>New</kind>
    </RECORD>
    ...
</RECORDS>

我已经应用了 FOR 循环,但由于 xslt 中的变量无法重置,因此它不起作用。

有什么想法吗?

【问题讨论】:

  • 这听起来像是任何分组问题的变体,因此 XSLT 2 或更高版本中的常用方法 for-each-group 或 XSLT 1 中的 Muenchian 分组应该会有所帮助。或者也许只使用一个键并检查是否缺少匹配项就足以复制您想要的节点。
  • 任何参考资料?
  • 好吧,首先告诉我们您使用的是哪个 XSLT 版本。通常,您可以使用例如声明密钥&lt;xsl:key name="rec2" match="RECORDS2/RECORD" use="id"/&gt; 然后只处理RECORDS1/RECORD[not(key('rec2', id))]。如果value 也很重要,则组合键值,在 XSLT 3 中最简单的方法是使用 &lt;xsl:key name="rec2" match="RECORDS2/RECORD" composite="yes" use="id, value"/&gt;,然后仅处理 RECORDS1/RECORD[not(key('rec2', (id, value))]。通过您的编辑来区分不匹配和不同的值,您也许可以再寻找一个键。
  • 我使用的是 xslt 版本 2
  • 试试键,如果我没记错的话,XSLT 2 不支持composite,但您可以使用两个键,也可以在use="concat(id, '|', value)" 中连接两个值。

标签: xslt tree compare nodes


【解决方案1】:

也许

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="#all"
    version="2.0">
    
  <xsl:output indent="yes"/>

  <xsl:key name="rec2-complete" match="RECORDS2/RECORD" use="concat(id, '|', value)"/>
  <xsl:key name="rec2-id" match="RECORDS2/RECORD" use="id"/>
  
  <xsl:template match="DATA">
      <xsl:apply-templates select="RECORDS1/RECORD[not(key('rec2-complete', concat(id, '|', value)))]"/>
  </xsl:template>
  
  <xsl:template match="RECORDS1/RECORD">
      <xsl:copy>
          <xsl:copy-of select="node()"/>
          <merged>
              <xsl:value-of select="if (key('rec2-id', id)/value != value) then 'changed' else 'new'"/>
          </merged>
      </xsl:copy>
  </xsl:template>
  
</xsl:stylesheet>

实现需求。

或者,要构建您现在显示的完整结果,请使用

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="#all"
    version="2.0">
    
  <xsl:output indent="yes"/>

  <xsl:key name="rec2-complete" match="RECORDS2/RECORD" use="concat(id, '|', value)"/>
  <xsl:key name="rec2-id" match="RECORDS2/RECORD" use="id"/>
  
  <xsl:template match="DATA">
      <xsl:copy>
          <RECORDS>
              <xsl:apply-templates select="RECORDS1/RECORD[not(key('rec2-complete', concat(id, '|', value)))]"/>
          </RECORDS>
      </xsl:copy>
  </xsl:template>
  
  <xsl:template match="RECORDS1/RECORD">
      <xsl:copy>
          <xsl:copy-of select="node()"/>
          <kind>
              <xsl:value-of select="if (key('rec2-id', id)/value != value) then 'change' else 'new'"/>
          </kind>
      </xsl:copy>
  </xsl:template>
  
</xsl:stylesheet>

【讨论】:

    猜你喜欢
    • 2015-09-13
    • 1970-01-01
    • 2021-02-04
    • 1970-01-01
    • 1970-01-01
    • 2021-03-21
    • 2018-10-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多