2013-03-05 82 views
0

我有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"> 

最后要求是,该方法可以适用于单一的属性(如先前实例中),它们的子集(属性1和属性3)或行元素的所有属性

在此先感谢。

回答

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> 
+0

非常感谢,它的工作。如果我想过滤多个属性,我应该将它们添加到'之前的兄弟姐妹'表达式中? – sblandin 2013-03-05 10:49:54

+0

对。如果您想按不同的属性1和属性3对进行过滤,那么应该是 row [prior-sibling :: row/\ @ attribute1 = \ @ attribute1 and preceding-sibling :: row/\ @ attribute3 = \ @ attribute3] – ljdelight 2013-03-05 11:54:21

+0

(忽略反斜杠...所以抱怨说,我试图通知太多的用户) – ljdelight 2013-03-05 11:55:01

2

如果你是热衷于了解XSLT的复杂性,你可能有兴趣知道的一种叫做Muenchian Grouping的技术可以用来解决你的问题。要获得不同的行,可以通过attribute1将它们有效地分组,然后为每个组选择组中的第一个元素。 (或丢弃不是第一个的元素)。 Muenchian分组是在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])]" /> 

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

+0

好主意! +1我从来没有想过与Muenchian组合使用连接 – ljdelight 2013-03-05 22:59:17

+0

坦克对于这个建议。当我回到我的xslt活动时,我也会尝试这个:-) – sblandin 2013-03-06 16:01:11