【问题标题】:Remove Duplicate values from the concatenated string in XSLT从 XSLT 中的连接字符串中删除重复值
【发布时间】:2017-02-06 14:25:39
【问题描述】:

我想从连接的字符串中删除重复的值。

输入是:

 <?xml version="1.0" encoding="ISO-8859-1"?>    
    <QL>
        <QITEM>
            <SERIAL>123</SERIAL>
            <PROD_NAME>User/Device</PROD_NAME>
        </QITEM>
        <QITEM>
            <SERIAL>123</SERIAL>
            <PROD_NAME>User/Dev</PROD_NAME>
        </QITEM>
        <QITEM>
            <SERIAL>123</SERIAL>
            <PROD_NAME>User/Device</PROD_NAME>
        </QITEM>
        <QITEM>
            <SERIAL>1234</SERIAL>
            <PROD_NAME>45 Mbps</PROD_NAME>
        </QITEM>
    </QL>
     <QL>
        <QITEM>
            <SERIAL>123</SERIAL>
            <PROD_NAME>User/Device</PROD_NAME>
        </QITEM>
        <QITEM>
            <SERIAL>123</SERIAL>
            <PROD_NAME>User/Dev</PROD_NAME>
        </QITEM>
        <QITEM>
            <SERIAL>123</SERIAL>
            <PROD_NAME>User/Device</PROD_NAME>
        </QITEM>
        <QITEM>
            <SERIAL>1234</SERIAL>
            <PROD_NAME>45 Mbps</PROD_NAME>
        </QITEM>
    </QL>

我想连接这些值,输出应该是这样的:

<Result>
  <SERIAL>123,1234</SERIAL>
  <PROD_NAME>User/Dev,User/Device,45 Mbps</PROD_NAME>
</Result>
<Result>
  <SERIAL>123,1234</SERIAL>
  <PROD_NAME>User/Dev,User/Device,45 Mbps</PROD_NAME>
</Result>

到目前为止,我已经尝试使用以下模板来实现这一点:

<xsl:template name="join">
    <xsl:param name="list"/>
    <xsl:param name="separator"/>
    <xsl:for-each select="$list">
      <xsl:value-of select="."/>
      <xsl:if test="position() != last()">
        <xsl:value-of select="$separator"/>
      </xsl:if>
    </xsl:for-each>
</xsl:template>

这是用逗号分隔的值。
但我想获得独特的价值。

【问题讨论】:

  • 那么&lt;PROD_NAME&gt;User/Dev&lt;/PROD_NAME&gt; 值发生了什么,为什么会被消除?
  • 抱歉打错了。我现在正在更新问题
  • 那么你在纠结什么?例如,distinct-values(//SERIAL) 会给你序列123,1234
  • 我已经更新了 Question.Distinct-values 函数这里不支持
  • 如果不支持distinct-values 函数,您将被困在XSLT-1.0 函数中。所以this SO answer 可能是重复的。

标签: xslt xslt-1.0


【解决方案1】:

在纯 XSLT 1.0 中唯一/不同的值最好通过使用Muenchian Method 分组来实现。

在下面的示例中,我们为我们希望拥有一组的每个项目创建一个xsl:key

例如,键serial 是所有SERIAL 元素的组,使用自身的值作为分组键。

然后我们遍历每个组 (xsl:for-each) 并只选择该组的第一次出现。

完整示例...

XML 输入

<QL>
    <QITEM>
        <SERIAL>123</SERIAL>
        <PROD_NAME>User/Device</PROD_NAME>
    </QITEM>
    <QITEM>
        <SERIAL>123</SERIAL>
        <PROD_NAME>User/Dev</PROD_NAME>
    </QITEM>
    <QITEM>
        <SERIAL>123</SERIAL>
        <PROD_NAME>User/Device</PROD_NAME>
    </QITEM>
    <QITEM>
        <SERIAL>1234</SERIAL>
        <PROD_NAME>45 Mbps</PROD_NAME>
    </QITEM>
</QL>

XSLT 1.0

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output indent="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:key name="serial" match="SERIAL" use="."/>
  <xsl:key name="prodname" match="PROD_NAME" use="."/>

  <xsl:template match="/*">
    <Result>
      <SERIAL>
        <xsl:for-each select="QITEM/SERIAL[count(.|key('serial',.)[1])=1]">
          <xsl:if test="position() > 1">,</xsl:if>
          <xsl:value-of select="."/>
        </xsl:for-each>
      </SERIAL>
      <PROD_NAME>
        <xsl:for-each select="QITEM/PROD_NAME[count(.|key('prodname',.)[1])=1]">
          <xsl:if test="position() > 1">,</xsl:if>
          <xsl:value-of select="."/>
        </xsl:for-each>
      </PROD_NAME>
    </Result>
  </xsl:template>

</xsl:stylesheet>

XML 输出

<Result>
   <SERIAL>123,1234</SERIAL>
   <PROD_NAME>User/Device,User/Dev,45 Mbps</PROD_NAME>
</Result>

更新

我不确定我是否完全理解您的更新,但我认为您可以做的是使用生成的祖先 ID QL 创建一个复合键。

XML 输入(包装在 doc 中以使其格式正确。)

<doc>
    <QL>
        <QITEM>
            <SERIAL>123</SERIAL>
            <PROD_NAME>User/Device</PROD_NAME>
        </QITEM>
        <QITEM>
            <SERIAL>123</SERIAL>
            <PROD_NAME>User/Dev</PROD_NAME>
        </QITEM>
        <QITEM>
            <SERIAL>123</SERIAL>
            <PROD_NAME>User/Device</PROD_NAME>
        </QITEM>
        <QITEM>
            <SERIAL>1234</SERIAL>
            <PROD_NAME>45 Mbps</PROD_NAME>
        </QITEM>
    </QL>
    <QL>
        <QITEM>
            <SERIAL>123</SERIAL>
            <PROD_NAME>User/Device</PROD_NAME>
        </QITEM>
        <QITEM>
            <SERIAL>123</SERIAL>
            <PROD_NAME>User/Dev</PROD_NAME>
        </QITEM>
        <QITEM>
            <SERIAL>123</SERIAL>
            <PROD_NAME>User/Device</PROD_NAME>
        </QITEM>
        <QITEM>
            <SERIAL>1234</SERIAL>
            <PROD_NAME>45 Mbps</PROD_NAME>
        </QITEM>
    </QL>
</doc>

XSLT 1.0

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output indent="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:key name="serial" match="SERIAL" use="concat(generate-id(ancestor::QL),'|',.)"/>
  <xsl:key name="prodname" match="PROD_NAME" use="concat(generate-id(ancestor::QL),'|',.)"/>

  <xsl:template match="QL">
    <Result>
      <SERIAL>        
        <xsl:for-each select="QITEM/SERIAL[count(.|key('serial',concat(generate-id(ancestor::QL),'|',.))[1])=1]">
          <xsl:if test="position() > 1">,</xsl:if>
          <xsl:value-of select="."/>
        </xsl:for-each>
      </SERIAL>
      <PROD_NAME>
        <xsl:for-each select="QITEM/PROD_NAME[count(.|key('prodname',concat(generate-id(ancestor::QL),'|',.))[1])=1]">
          <xsl:if test="position() > 1">,</xsl:if>
          <xsl:value-of select="."/>
        </xsl:for-each>
      </PROD_NAME>
    </Result>
  </xsl:template>

</xsl:stylesheet>

XML 输出

<Result>
   <SERIAL>123,1234</SERIAL>
   <PROD_NAME>User/Device,User/Dev,45 Mbps</PROD_NAME>
</Result>
<Result>
   <SERIAL>123,1234</SERIAL>
   <PROD_NAME>User/Device,User/Dev,45 Mbps</PROD_NAME>
</Result>

【讨论】:

  • 是的,这工作正常,但事实是我在重复上述输入时......如果它们再次进入下一个循环,则值 123,1234 将不可见。
  • 我已更新问题。请查看。我也添加了输入和输出。
  • @srinivaskalyan - 请查看我的更新。如果这不能回答您的问题,您可能希望不接受我的回答,以便其他人会查看您的问题。现在它有一个公认的答案,所以大多数人会跳过它。
  • @DanielHaley - 感谢您的解决方案。更新后的效果很好。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-05
  • 2015-11-14
  • 2011-10-11
  • 2017-04-03
  • 1970-01-01
  • 2020-03-30
相关资源
最近更新 更多