2

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

所以我有 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

4

3 回答 3

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()直接使用,但是如果您确实需要序列号(并且您可以保证这本身不会导致重复,例如,如果原始文档已经同时具有和)那么你可以使用类似的技巧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本质上是在共享相同属性值的节点集中找到当前书籍的文档顺序位置。

于 2013-11-14T15:24:44.897 回答
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>
于 2013-11-14T15:17:06.260 回答
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>

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

<?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>

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

于 2013-11-14T15:36:34.450 回答