通过保留第一次出现的节点来删除 XSLT 属性中的重复项

Posted

技术标签:

【中文标题】通过保留第一次出现的节点来删除 XSLT 属性中的重复项【英文标题】:Remove duplicate in the attribute of an XSLT by keeping first occurrence of the node 【发布时间】:2021-11-12 00:46:53 【问题描述】:

我正在尝试获取 XML 的唯一值并删除重复项。我想第一次出现属性 id 相同的标签。还要注意其他不重复的射频标签不会被删除。

我的 XML 是-

<rfs>
  <rf id="key_1_fam_1">
        <data>
            <entry>
                <key>a</key>
                <value>2</value>
            </entry>
        </data>
        <cc>ccid1</cc>
        <name>as</name>
        <ref>21</ref>
         <recs>
            <rec id="key_1_fam_1_rec1">
                <data>
                    <entry>
                        <key>a</key>
                        <value>2</value>
                    </entry>
                </data>
                <type>VALID</type>
             </rec>
           </recs>

        <colour>false</colour>
    </rf>
  <rf id="key_1_fam_1">
        <data>
            <entry>
                <key>a</key>
                <value>2</value>
            </entry>
        </data>
        <cc>ccid1</cc>
        <name>as</name>
        <ref>21</ref>
         <recs>
            <rec id="key_1_fam_1_rec1">
                <data>
                    <entry>
                        <key>a</key>
                        <value>2</value>
                    </entry>
                </data>
                <type>VALID</type>
             </rec>
           </recs>

        <colour>false</colour>
    </rf> 
  <rf id="fam_2">
        <data>
            <entry>
                <key>cb</key>
                <value>2</value>
            </entry>
        </data>
        <costCentre>ccd2</costCentre>
        <name>V</name>
        <reference>31</reference>
        <recs>
            <rec id="fam_2_rec2">
                <data>
                    <entry>
                        <key>cs</key>
                        <value>aa</value>
                    </entry>
                </data>
            </rec>
        </recs>
        <colour>false</colour>
        </rf>
  <rf id="fam_3">
        <data>
            <entry>
                <key>csb</key>
                <value>2</value>
            </entry>
        </data>
        <costCentre>ccd2</costCentre>
        <name>V</name>
        <reference>34</reference>
        <recs>
            <rec id="fam_3_rec12">
                <data>
                    <entry>
                        <key>crs</key>
                        <value>aa</value>
                    </entry>
                </data>
            </rec>
        </recs>
        <colour>false</colour>
        </rf>
</rfs>

我希望输出像 -

<?xml version="1.0" encoding="UTF-8"?><rfs>
  <rf id="key_1_fam_1">
        <data>
            <entry>
                <key>a</key>
                <value>2</value>
            </entry>
        </data>
        <cc>ccid1</cc>
        <name>as</name>
        <ref>21</ref>
         <recs>
            <rec id="key_1_fam_1_rec1">
                <data>
                    <entry>
                        <key>a</key>
                        <value>2</value>
                    </entry>
                </data>
                <type>VALID</type>
             </rec>
           </recs>

        <colour>false</colour>
    </rf>
   <rf id="fam_2">
        <data>
            <entry>
                <key>cb</key>
                <value>2</value>
            </entry>
        </data>
        <costCentre>ccd2</costCentre>
        <name>V</name>
        <reference>31</reference>
        <recs>
            <rec id="fam_2_rec2">
                <data>
                    <entry>
                        <key>cs</key>
                        <value>aa</value>
                    </entry>
                </data>
            </rec>
        </recs>
        <colour>false</colour>
        </rf>
  <rf id="fam_3">
        <data>
            <entry>
                <key>csb</key>
                <value>2</value>
            </entry>
        </data>
        <costCentre>ccd2</costCentre>
        <name>V</name>
        <reference>34</reference>
        <recs>
            <rec id="fam_3_rec12">
                <data>
                    <entry>
                        <key>crs</key>
                        <value>aa</value>
                    </entry>
                </data>
            </rec>
        </recs>
        <colour>false</colour>
        </rf>
</rfs>

我尝试了以下 XSLT 并尝试了不同的值,但不确定我缺少什么。

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

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


<xsl:template name="removeDups">
<xsl:if test="not(. = preceding::node())">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:if>
</xsl:template>

<xsl:template match="rfs">
<xsl:call-template name="removeDups">
</xsl:call-template>
</xsl:template>
    
</xsl:stylesheet>

非常感谢任何帮助,因为我是 XSLT 的新手。

【问题讨论】:

【参考方案1】:

您的样式表显示version="2.0"。在 XSLT 2.0 或更高版本中,您最好的选择是使用grouping:

XSLT 2.0

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

<xsl:template match="/rfs">
    <xsl:copy>
        <xsl:for-each-group select="rf" group-by="@id">
            <!-- copy the first item of current group -->
            <xsl:copy-of select="."/>
        </xsl:for-each-group>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

演示:https://xsltfiddle.liberty-development.net/pNEj9ea

【讨论】:

以上是关于通过保留第一次出现的节点来删除 XSLT 属性中的重复项的主要内容,如果未能解决你的问题,请参考以下文章

XSLT:分析字符串并保留子节点

XSLT 替换属性值和文本节点中的文本

如何使用 XSLT 从 XML 中删除名称空间

线性表练习之Example040-删除单链表中数据域绝对值相等节点,仅保留第一次出现的节点而删除其余绝对值相等的节点

XSLT筛选器节点多个条件

将 xml 中的节点与 xslt 进行比较