如何在封闭元素下组织(分组)节点 - XSLT
Posted
技术标签:
【中文标题】如何在封闭元素下组织(分组)节点 - XSLT【英文标题】:How to organize(group) nodes under a closed element - XSLT 【发布时间】:2013-05-14 21:11:02 【问题描述】:我尝试过使用 XSLT 1.0 对 XML 进行简单的分组,并且成功了,但在这里我遇到了一些更复杂且实际上不同的情况。 所以XML结构基本上是这样的:
<Main>
<TB>
--> some elements and stuff - not relevant
<City>
<Area>
<Position>5</Position>
<House>
--> some elements and stuff
</House>
</Area>
<Area>
<Position>5</Position>
<Block>
--> some elements and stuff
</Block>
</Area>
<Area>
<Position>6</Position>
<House>
--> some elements and stuff
</House>
</Area>
<Area>
<Position>6</Position>
<Block>
--> some elements and stuff
</Block>
</Area>
</City>
<City>
--> same structure but with several repetitions of Position 7 and 8.
</City>
</TB>
</Main>
我需要将位于同一位置的Block
s 和House
s 分组,并删除重复的位置编号。例如它会变成这样:
<City>
<Area>
<Position>5</Position>
<House>
--> some elements and stuff
</House>
<Block>
--> some elements and stuff
</Block>
</Area>
<Area>
<Position>6</Position>
<House>
--> some elements and stuff
</House>
<Block>
--> some elements and stuff
</Block>
</Area>
</City>
<City>
--> same structure for Position 7 and 8.
</City>
比较难,因为Position不是Area的一个属性,所以我基本上要确定Area的Position的值,然后抓取同一个Position下的House和Block,放在一起被包围相同的<Area> </Area>
。
【问题讨论】:
【参考方案1】:在我看来,这似乎是一个相当标准的 Muenchian 分组问题,将 Area
元素(不是直接 House
或 Block
元素)按 Position
分组。
<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="areaByPosition" match="Area" use="Position" />
<xsl:template match="@*|node()">
<xsl:copy><xsl:apply-templates select="@*|node()" /></xsl:copy>
</xsl:template>
<!-- for the first Area in each Position -->
<xsl:template match="Area[generate-id() =
generate-id(key('areaByPosition', Position)[1])]">
<Area>
<!-- copy in the Position element once only -->
<xsl:apply-templates select="Position" />
<!-- copy in all sub-elements except Position from all matching Areas -->
<xsl:apply-templates select="
key('areaByPosition', Position)/*[not(self::Position)]" />
</Area>
</xsl:template>
<!-- ignore all other Area elements -->
<xsl:template match="Area" />
</xsl:stylesheet>
这假设文档中的其他地方没有其他名为Area
的元素,如果任何“一些元素和东西”可能被命名为Area
,那么你需要更具体一点,例如限制分组到作为City
的直接子级的Area
元素:
<xsl:key name="areaByPosition" match="City/Area" use="Position" />
<xsl:template match="City/Area[generate-id() =
generate-id(key('areaByPosition', Position)[1])]"
priority="2">
...
</xsl:template>
<xsl:template match="City/Area" priority="1" />
(有明确的优先级,因为没有它,两个模板将具有相同的default priority 0.5)
【讨论】:
这工作得很好,直到我真正找到了不允许的东西。例如我有<City A><Area><Position>5</Position>... bla bla<///>
然后我在<City B>
有相同的位置5 它从B 市获取位置5 下的元素并将它们排列在A 市的位置5 的元素下。我希望它订购房屋和街区,但留在同一个城市。
@Syspect 如果您想通过 Position
和包含 City
的名称对 Area
元素进行分组,您需要在分组键定义中包含相关内容,例如 @987654337 @ 和分组谓词,如 key('areaByPosition', concat(../@name, '|', Position)[1]
以上是关于如何在封闭元素下组织(分组)节点 - XSLT的主要内容,如果未能解决你的问题,请参考以下文章