在封闭元素下排列节点 - XSLT
Posted
技术标签:
【中文标题】在封闭元素下排列节点 - XSLT【英文标题】:Arrange nodes under a closed element - XSLT 【发布时间】:2013-06-11 04:19:12 【问题描述】:所以我有这个 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,因为我的编辑器不支持它。
【问题讨论】:
【参考方案1】:为此,您需要一个复合键,它将是标识您的组的所有值的串联,在您的情况下是 Type(父元素的),以及位置
<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>
唯一需要注意的是,串联中的“竖线”字符可以是任何你喜欢的字符,只要它不在Type和Position中的任何一个中出现即可 元素,以确保此类元素的两个不同组合不会产生相同的键。
【讨论】:
以上是关于在封闭元素下排列节点 - XSLT的主要内容,如果未能解决你的问题,请参考以下文章
如何获取具有相同名称的元素并根据 XSLT 中的子节点值对它们进行排序