所以我有这个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>
订购完全正常。
但是,如果我在不同的Position
中有重复的Type
个数字,那么我会在第一个House
中排列所有Block
和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>
然后Position 5
中Type B
下的元素将从Position 5
移到TypeA
下的{{1}}下。我不希望这样。我想要安排房屋和街区,但要留在他们自己的类型和区域。
任何人都可以向我提供解决方案,我该如何更改我的XSLT以解决此问题?
P.S。出于简化原因,更改了XML标记的名称。我不能使用xslt-2.0,因为我的编辑器不支持它。
答案 0 :(得分:2)
要执行此操作,您需要一个复合键,它将是标识您的组的所有值的串联,在您的情况下是类型(父元素的),以及的位置强>
<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>
唯一要注意的是,连接中的“管道”字符可以是您喜欢的任何字符,只要它不会出现在类型和位置中的任何一个元素,确保这些元素的两种不同组合不会产生相同的键。