选择唯一属性组

时间:2013-03-05 08:47:37

标签: xml xslt

我的xslt背景很差,我需要转换看起来像这样的XML:

<row attribute1="1" attribute2="something" attribute3="somevalue">
<row attribute1="1" attribute2="something" attribute3="somevalue">
<row attribute1="2" attribute2="anotherthing" attribute3="somevalue">

看起来像这样:

<row attribute1="1">
<row attribute1="2">

转换任务还有两个要求。我想得到与上面相同的结果,但我想更改属性名称,例如:

<row new_name_for_attribute1="1">
<row new_name_for_attribute1="2">

最后一个要求是该方法可以应用于单个属性(如前面的示例),它们的一个子集(attribute1和attribute3),或行元素的所有属性

提前致谢。

2 个答案:

答案 0 :(得分:2)

如果您希望了解有关XSLT错综复杂的更多信息,您可能有兴趣了解一种名为Muenchian Grouping的技术,可用于解决您的问题。要获得不同的行,请通过 attribute1 对其进行有效分组,然后为每个组选择组中的第一个元素。 (或丢弃不是第一个的元素)。 Muenchian Grouping是在XSLT 1.0中实现这一目标的最有效方法。

在这种情况下,您首先要定义一个键来表示您的组,在您的情况下是元素,按 attribute1 分组

<xsl:key name="row" match="row" use="@attribute1" />

如果您之后想要选择不同的元素,则应选择元素,这些元素首先出现在其给定 attribute1

<xsl:apply-templates select="row[generate-id() = generate-id(key('row', @attribute1)[1])]" />

或者,您可以使用模板忽略重复的元素(即不是组中的第一个)

<xsl:template match="row[generate-id() != generate-id(key('row', @attribute1)[1])]" />

试试这个XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="xml" indent="yes"/>
   <xsl:key name="row" match="row" use="@attribute1" />

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

   <xsl:template match="row[generate-id() != generate-id(key('row', @attribute1)[1])]" />   
</xsl:stylesheet>

应用于以下XML

<rows>
   <row attribute1="1" attribute2="something" attribute3="somevalue" />
   <row attribute1="1" attribute2="something" attribute3="somevalue" />
   <row attribute1="2" attribute2="anotherthing" attribute3="somevalue" />
</rows>

以下是输出

<rows>
   <row attribute1="1" attribute2="something" attribute3="somevalue"></row>
   <row attribute1="2" attribute2="anotherthing" attribute3="somevalue"></row>
</rows>

可以轻松扩展XSLT以重命名属性或排除它们,如ljdelight的答案中所述。此外,如果您想在测试中包含第二个属性,可以像这样扩展您的密钥:

<xsl:key name="row" match="row" use="concat(@attribute1, '|', @attribute3)" />

要忽略重复项,模板会看起来像这个

<xsl:template match="row
     [generate-id() != generate-id(key('row', concat(@attribute1, '|', @attribute3))[1])]" />  

这里唯一需要注意的是使用管道字符|作为分隔符。如果需要,这可以是任何其他字符,只要它不在属性值中出现。

答案 1 :(得分:1)

您可以轻松转换XML。这里有一些代码,你可以学习和学习一些xsl。

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="xml" indent="yes" />
   <xsl:template match="@*|node()">
       <xsl:copy>
           <xsl:apply-templates select="@*|node()"/>
       </xsl:copy>
   </xsl:template>

   <!-- drop a row that matches a previous row of the same id -->
   <xsl:template match="row[ preceding-sibling::row/@attribute1 = @attribute1 ]" />

   <!-- do stuff with the row. this template is equivalent to the default template copy. -->
   <xsl:template match="row">
      <xsl:copy>
         <xsl:apply-templates select="@*|node()" />
      </xsl:copy>
   </xsl:template>

   <!-- drop attribute2 attributes -->
   <xsl:template match="@attribute2" />

   <!-- rename attribute1 -->
   <xsl:template match="@attribute1">
      <xsl:attribute name="new_name_for_attribute1">
         <xsl:value-of select="."/>
      </xsl:attribute>
   </xsl:template>
</xsl:stylesheet>

使用此输入:

<table>
   <row attribute1="1" attribute2="something" attribute3="somevalue">
      <p>foo</p>
   </row>
   <row attribute1="1" attribute2="something" attribute3="somevalue">
      <p>bar</p>
   </row>
   <row attribute1="2" attribute2="anotherthing" attribute3="somevalue">
      <p>bazinga</p>
   </row>
</table>

获取此输出:

<table>
   <row new_name_for_attribute1="1" attribute3="somevalue">
      <p>foo</p>
   </row>
   <row new_name_for_attribute1="2" attribute3="somevalue">
      <p>bazinga</p>
   </row>
</table>