XSLT过滤器重复结果

时间:2012-02-20 19:14:08

标签: xslt

我试图弄清楚如何避免结果集中的重复 在应用XSLT转换时(我正在使用XSLT 1.0)

这是XML源:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<?xml-stylesheet type="text/xsl" href="1.xsl"?>
<root>
<item>
<code>AA</code>
<included-code>XX</included-code>
<included-code>YY</included-code>
<included-code>WW</included-code>
</item>
<item>
<code>BB</code>
<included-code>ZZ</included-code>
<included-code>XX</included-code>
<included-code>YY</included-code>
</item>
<item>
<code>CC</code>
<included-code>VV</included-code>
<included-code>XX</included-code>
<included-code>WW</included-code>
</item>
</root>

这是样式表:

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="/">

  <result>
    <xsl:apply-templates/>
  </result>

</xsl:template>

<xsl:template match="item">
    <new-item>
      <code><xsl:value-of select="code"/></code>
      <xsl:variable name="main_code"><xsl:value-of select="code"/></xsl:variable>
      <xsl:for-each select="included-code">
        <xsl:variable name="current_code"><xsl:value-of select="text()"/></xsl:variable>
        <included-code><xsl:value-of select="$current_code"/></included-code>
        <xsl:for-each select="/root/item[included-code=$current_code and code!=$main_code]">
          <included-code><xsl:value-of select="code"/></included-code>
        </xsl:for-each>
      </xsl:for-each>
    </new-item>
</xsl:template>

</xsl:stylesheet>

结果如下:

<?xml version="1.0" encoding="UTF-8"?><result>
<new-item>
<code>AA</code>
<included-code>XX</included-code>
<included-code>BB</included-code>
<included-code>CC</included-code>
<included-code>YY</included-code>
<included-code>BB</included-code>
<included-code>WW</included-code>
<included-code>CC</included-code>
</new-item>
<new-item>
<code>BB</code>
<included-code>ZZ</included-code>
<included-code>XX</included-code>
<included-code>AA</included-code>
<included-code>CC</included-code>
<included-code>YY</included-code>
<included-code>AA</included-code>
</new-item>
<new-item>
<code>CC</code>
<included-code>VV</included-code>
<included-code>XX</included-code>
<included-code>AA</included-code>
<included-code>BB</included-code>
<included-code>WW</included-code>
<included-code>AA</included-code>
</new-item>
</result>

问题是 - 如何避免结果中出现重复值。即这是预期的:

<?xml version="1.0" encoding="UTF-8"?><result>
<new-item>
<code>AA</code>
<included-code>XX</included-code>
<included-code>BB</included-code>
<included-code>CC</included-code>
<included-code>YY</included-code>
<included-code>WW</included-code>
</new-item>
<new-item>
<code>BB</code>
<included-code>ZZ</included-code>
<included-code>XX</included-code>
<included-code>AA</included-code>
<included-code>CC</included-code>
<included-code>YY</included-code>
</new-item>
<new-item>
<code>CC</code>
<included-code>VV</included-code>
<included-code>XX</included-code>
<included-code>AA</included-code>
<included-code>BB</included-code>
<included-code>WW</included-code>
</new-item>
</result>

谢谢LarsH!看起来以下脚本可以解决问题: (我对XSLT比较陌生,所以不确定是否有更优雅的方法来保存已输出值的列表)

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="/">

  <result>
    <xsl:apply-templates/>
  </result>

</xsl:template>

<xsl:template match="item">
  <new-item>
    <code><xsl:value-of select="code"/></code>
    <xsl:variable name="main_code"><xsl:value-of select="code"/></xsl:variable>
    <xsl:call-template name="processIncludedCodes">
      <xsl:with-param name="main_code" select="./code"/>
      <xsl:with-param name="codes" select="./included-code"/>
    </xsl:call-template>
  </new-item>
</xsl:template>

<xsl:template name="processIncludedCodes">
  <xsl:param name="main_code"/>
  <xsl:param name="codes"/>
  <xsl:param name="outputCodes"/>
  <xsl:if test="$codes">
    <xsl:variable name="current_code"><xsl:value-of select="$codes[1]"/></xsl:variable>
    <xsl:variable name="outputCode" select="concat(':', $codes[1], ':')"/>
    <xsl:if test="not(contains($outputCodes, $outputCode))">
      <included-code><xsl:value-of select="$codes[1]"/></included-code>
    </xsl:if>
    <xsl:for-each select="/root/item[included-code=$current_code and code!=$main_code]">
      <xsl:if test="not(contains($outputCodes, ./code))">
        <included-code><xsl:value-of select="code"/></included-code>
      </xsl:if>
    </xsl:for-each>
    <xsl:variable name="outputCodes2">
      <xsl:for-each select="/root/item[included-code=$current_code and code!=$main_code]">
        <xsl:value-of select="concat(':', code, ':')"/>
      </xsl:for-each>
    </xsl:variable>
    <xsl:variable name="newOutputCodes" select="concat($outputCodes, $outputCode, $outputCodes2)"/>
    <xsl:call-template name="processIncludedCodes">
      <xsl:with-param name="main_code" select="$main_code"/>
      <xsl:with-param name="codes" select="$codes[position() > 1]"/>
      <xsl:with-param name="outputCodes" select="$newOutputCodes"/>
    </xsl:call-template>
  </xsl:if>
</xsl:template>

</xsl:stylesheet>

1 个答案:

答案 0 :(得分:1)

没有任何递归:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">

    <xsl:output method="xml" indent="yes"/>

    <xsl:template match="/root">
        <root>
            <xsl:apply-templates select="item"/>
        </root>
    </xsl:template>

    <xsl:template match="item">
        <new-item>
            <xsl:copy-of select="code"/>
            <xsl:for-each select="included-code | /root/item[included-code = current()/included-code]/code[. != current()/included-code and . != current()/code]">
                <included-code>
                    <xsl:value-of select="."/>
                </included-code>
            </xsl:for-each>
        </new-item>
    </xsl:template>
</xsl:stylesheet>

它会选择任何当前的<included-code>,加上任何共同<included-code>的项目,如果尚未包含<code>,它会选择<?xml version="1.0" encoding="utf-8"?> <root> <new-item> <code>AA</code> <included-code>XX</included-code> <included-code>YY</included-code> <included-code>WW</included-code> <included-code>BB</included-code> <included-code>CC</included-code> </new-item> <new-item> <code>BB</code> <included-code>AA</included-code> <included-code>ZZ</included-code> <included-code>XX</included-code> <included-code>YY</included-code> <included-code>CC</included-code> </new-item> <new-item> <code>CC</code> <included-code>AA</included-code> <included-code>BB</included-code> <included-code>VV</included-code> <included-code>XX</included-code> <included-code>WW</included-code> </new-item> </root>

<强>输出:

{{1}}