所以我有这个XML:
<Main>
<TB>
--> some elements - not relevant
<Area>
<Type>A</Type>
<Street>
<Position>5</Position>
<House>
--> some elements
</House>
</Street>
<Street>
<Position>5</Position>
<Block>
--> some elements
</Block>
</Street>
<Street>
<Position>6</Position>
<House>
--> some elements
</House>
</Street>
<Street>
<Position>6</Position>
<Block>
--> some elements
</Block>
</Street>
</Area>
<Area>
<Type>B</Type>
--> same structure but with several repetitions of Position 7 and 8.
</Area>
</TB>
</Main>
我想这样排序:
<Area>
<Type>A</Type>
<Street>
<Position>5</Position>
<House>
--> some elements
</House>
<Block>
--> some elements
</Block>
</Street>
<Street>
<Position>6</Position>
<House>
--> some elements
</House>
<Block>
--> some elements
</Block>
</Street>
</Area>
<Area>
<Type>B</Type>
--> same structure for Position 7 and 8.
</Area>
我用这个XSLT来转换它:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:strip-space elements="*" />
<xsl:output method="xml" indent="yes" />
<xsl:key name="streetByPosition" match="Street" use="Position" />
<xsl:template match="@*|node()">
<xsl:copy><xsl:apply-templates select="@*|node()" /></xsl:copy>
</xsl:template>
<!-- for the first Street in each Position -->
<xsl:template match="Street[generate-id() =
generate-id(key('streetByPosition', Position)[1])]">
<Street>
<!-- copy in the Position element once only -->
<xsl:apply-templates select="Position" />
<!-- copy in all sub-elements except Position from all matching Streets-->
<xsl:apply-templates select="
key('streetByPosition', Position)/*[not(self::Position)]" />
</Street>
</xsl:template>
<!-- ignore all other Street elements -->
<xsl:template match="Street" />
</xsl:stylesheet>
排序工作完全正常。但是如果我在不同的Type
中有重复的Position
数字那么我得到所有的House
s和Block
s排列在第一个Type
中我有重复的Position
数字。例如:
<Area>
<Type>A</Type>
<Street>
<Position>5</Position>
<House>
--> some elements
</House>
</Street>
<Street>
<Position>5</Position>
<Block>
--> some elements
</Block>
</Street>
....
<Area>
<Type>B</Type>
<Street>
<Position>5</Position>
<House>
--> some elements
</House>
</Street>
则Type B
中Position 5
下的元素将从那里移动到TypeA
中的Position 5
下。我不希望那样。我想把房子和街区安排在各自的类型和区域内。
谁能给我提供解决方案,我必须如何改变我的XSLT,以解决这个问题?
注:为了简化,更改了XML标记的名称。我不能使用xslt-2.0,因为我的编辑器不支持它。
要做到这一点,您需要您将需要一个复合键,它将是标识您的组的所有值的连接,在您的情况下,类型(父元素)和位置
<xsl:key name="streetByPosition" match="Street" use="concat(../Type, '|', Position)" />
然后您可以按正常方式使用该键
key('streetByPosition', concat(../Type, '|', Position))
尝试下面的XSLT:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:strip-space elements="*" />
<xsl:output method="xml" indent="yes" />
<xsl:key name="streetByPosition" match="Street" use="concat(../Type, '|', Position)" />
<xsl:template match="@*|node()">
<xsl:copy><xsl:apply-templates select="@*|node()" /></xsl:copy>
</xsl:template>
<!-- for the first Street in each Position -->
<xsl:template match="Street[generate-id() =
generate-id(key('streetByPosition', concat(../Type, '|', Position))[1])]">
<Street>
<!-- copy in the Position element once only -->
<xsl:apply-templates select="Position" />
<!-- copy in all sub-elements except Position from all matching Streets-->
<xsl:apply-templates select="
key('streetByPosition', concat(../Type, '|', Position))/*[not(self::Position)]" />
</Street>
</xsl:template>
<!-- ignore all other Street elements -->
<xsl:template match="Street" />
</xsl:stylesheet>
唯一需要注意的是,连接中的'pipe'字符可以是您喜欢的任何字符,只要它不出现在Type和Position元素中,以确保这类元素的两个不同组合不会产生相同的键。