如果 id 重复然后使用 xslt 更改重复的 id

If id repeats then changing the repeated id using xslt

我有一个 xml 输入,其中包含重复的 ID,如下所示

<root>
<p>text 1</p>
<text id="Read-R1">
<p>sample 1</p>
</text>
<p>text 2</p>
<text id="Read-R2">
<p>sample 2</p>
</text>
<p>text 3</p>
<text id="Read-R1">
<p>sample 3</p>
</text>
<p>text 4</p>
<text id="Read-R2">
<p>sample 3</p>
</text>
<p>text 5</p>
<text id="Read-R1">
<p>sample 5</p>
</text>
<text id="Read-R3">
<p>sample 3</p>
</text>
</root>

repeated id 我想将 append -01 更改为 repeated id only first id same as it is: 输出为:

<root>
<p>text 1</p>
<text id="Read-R1">
<p>sample 1</p>
</text>
<p>text 2</p>
<text id="Read-R2">
<p>sample 2</p>
</text>
<p>text 3</p>
<text id="Read-R1-01">
<p>sample 3</p>
</text>
<p>text 4</p>
<text id="Read-R2-01">
<p>sample 3</p>
</text>
<p>text 5</p>
<text id="Read-R1-02">
<p>sample 5</p>
</text>
<text id="Read-R3">
<p>sample 3</p>
</text>
</root>

请建议 xslt 为重复的 ID 附加 -01 提前致谢。

这会带来额外的好处,如果有更多的人使用相同的@id,它仍然会创建唯一的 id。

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

  <xsl:template match="*">
    <xsl:copy>
      <xsl:apply-templates/>
    </xsl:copy>
  </xsl:template>
    
  <xsl:template match="text[@id]">
    <xsl:variable name="sId" select="@id"/>
    <xsl:variable name="iPrecedingIdsWithSameValue" select="count(preceding-sibling::text[@id=$sId])"/>
    <xsl:copy>
      <xsl:attribute name="id" select="if($iPrecedingIdsWithSameValue gt 0) then concat(@id,'-',format-number($iPrecedingIdsWithSameValue,'00')) else @id"/>
      <xsl:apply-templates/>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

您可以使用以下密钥和模板

  <xsl:key name="id" match="text" use="@id"/>
  
  <xsl:template match="text[not(. is key('id', @id)[1])]/@id">
    <xsl:attribute 
      name="{name()}"
      select="concat(., '-', format-number(index-of(key('id', .)[position() gt 1]/generate-id(), generate-id(..)), '00'))"/>
  </xsl:template>

加上身份转换(在 XSLT 3 中由 <xsl:mode on-no-match="shallow-copy"/> 声明或拼写为

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