使用xslt重命名重复的属性

时间:2013-11-14 15:02:27

标签: xml xslt

我今天再次遇到一个问题。我有xml 1000个标签名为book。每个标签都有自己的属性,但有些属性是重复的。

所以我有XML:

... some other not duplicated attribute data ...
<book attribute="attr1"></book>
<book attribute="attr1"></book>
<book attribute="attr1"></book>
... some other not duplicated attribute data ...
<book attribute="attr2"></book>
<book attribute="attr2"></book>
<book attribute="attr2"></book>
... some other not duplicated attribute data ...

有没有办法使用xslt所以我可以让xml中的属性多次重命名:

... some other not duplicated attribute data...
<book attribute="attr1-1"></book>
<book attribute="attr1-2"></book>
<book attribute="attr1-3"></book>
... some other not duplicated attribute data ...
<book attribute="attr2-1"></book>
<book attribute="attr2-2"></book>
<book attribute="attr2-3"></book>
... some other not duplicated attribute data ...

希望xslt可以实现这一点,并且没有重复的属性保持不变? 非常感谢所有答案, eoglasi

3 个答案:

答案 0 :(得分:3)

检查属性是否重复的一种方法是定义以按book值查找attribute元素,然后对案例进行特殊处理键查找为您提供了多个结果:

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

  <xsl:key name="bookByAttribute" match="book" use="@attribute" />

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

  <xsl:template match="book/@attribute[key('bookByAttribute', .)[2]]">
    <xsl:attribute name="attribute">
      <!-- logic to create a de-duplicated value -->
    </xsl:attribute>
  </xsl:template>
</xsl:stylesheet>

不重复attribute的图书不会受此模板的影响。生成重复数据删除值的最简单方法是直接使用generate-id() as Vincent suggests,但如果确实需要序列号(并且您可以保证不会本身导致重复,例如,如果原始文档已同时具有foofoo-1),那么您可以使用类似的技巧

  <xsl:template match="book/@attribute[key('bookByAttribute', .)[2]]">
    <xsl:variable name="myId" select="generate-id(..)" />
    <xsl:attribute name="attribute">
      <xsl:value-of select="." />
      <xsl:text>-</xsl:text>
      <xsl:for-each select="key('bookByAttribute', .)">
        <xsl:if test="generate-id() = $myId">
          <xsl:value-of select="position()" />
        </xsl:if>
      </xsl:for-each>
    </xsl:attribute>
  </xsl:template>

for-each实际上是在共享相同属性值的节点集中找到当前图书的文档顺序位置。

答案 1 :(得分:1)

如果您没有为属性的特定模式绑定,则可以使用专用函数为输入文件中的每个特定节点集创建唯一ID:generate-id。在您的情况下,您可以这样使用它:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="book/@attribute">
        <xsl:attribute name="attribute">
            <xsl:value-of select="concat(., '-', generate-id())"/>
        </xsl:attribute>
    </xsl:template>
</xsl:stylesheet>

这个XML:

<test>
    ... some other not duplicated attribute data ...
    <book attribute="attr1"></book>
    <book attribute="attr1"></book>
    <book attribute="attr1"></book>
    ... some other not duplicated attribute data ...
    <book attribute="attr2"></book>
    <book attribute="attr2"></book>
    <book attribute="attr2"></book>
    ... some other not duplicated attribute data ...
</test>

你会得到类似的东西:

<test>
    ... some other not duplicated attribute data ...
    <book attribute="attr1-d0e3_a0"/>
    <book attribute="attr1-d0e5_a1"/>
    <book attribute="attr1-d0e7_a2"/>
    ... some other not duplicated attribute data ...
    <book attribute="attr2-d0e9_a3"/>
    <book attribute="attr2-d0e11_a4"/>
    <book attribute="attr2-d0e13_a5"/>
    ... some other not duplicated attribute data ...
</test>

答案 2 :(得分:1)

输入XML:

<?xml version="1.0" encoding="utf-8"?>
<test>
 <book attribute="attr1"></book>
 <book attribute="attr1"></book>
 <book attribute="attr1"></book>
 <book attribute="attr2"></book>
 <book attribute="attr2"></book>
 <book attribute="attr2"></book>
 <book attribute="attr5"></book>
</test>

以下样式表应该完成这项工作。 本质上,它检查一个组(按属性分组,称为“属性”)是否仅包含1个项目(即,如果属性值是唯一的)。

<?xml version="1.0" encoding="utf-8"?>

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

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

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

<xsl:template match="test">
  <xsl:copy>
     <xsl:for-each-group select="book" group-by="@attribute">
        <xsl:choose>
           <xsl:when test="count(current-group()) = 1">
              <xsl:element name="book">
                 <xsl:attribute name="attribute">
                    <xsl:value-of select="@attribute"/>
                 </xsl:attribute>
              </xsl:element>
           </xsl:when>
           <xsl:otherwise>
              <xsl:for-each select="current-group()">
                 <xsl:element name="book">
                    <xsl:attribute name="attribute">
                       <xsl:value-of select="concat(current-grouping-key(), '-', position())"/>
                    </xsl:attribute>
                 </xsl:element>
              </xsl:for-each>
           </xsl:otherwise>
        </xsl:choose>
     </xsl:for-each-group>
  </xsl:copy>
</xsl:template>

</xsl:stylesheet>

您获得以下输出(我在输入文件中包含了1个唯一属性值):

<test>
 <book attribute="attr1-1"/>
 <book attribute="attr1-2"/>
 <book attribute="attr1-3"/>
 <book attribute="attr2-1"/>
 <book attribute="attr2-2"/>
 <book attribute="attr2-3"/>
 <book attribute="attr5"/>
</test>

编辑:请注意,这会重新排序具有相同属性值的非相邻图书元素。