我需要一种优雅的方式来根据属性值将兄弟姐妹分组为孩子。这类似于基于 'colspan' 属性将 html 表转换为分层数据。
输入结构有多个兄弟节点,子节点包含数据。然而,数据节点可能包含指示等级优越性的等级属性。
输入
<root>
<Sibling>
<Data level="4">ABC</Data>
</Sibling>
<Sibling>
<Data level="3">fff</Data>
</Sibling>
<Sibling>
<Data>8000</Data>
<Data>01/04/2013</Data>
</Sibling>
<Sibling>
<Data level="3">ggg</Data>
</Sibling>
<Sibling>
<Data>2000</Data>
<Data>01/05/2013</Data>
</Sibling>
<Sibling>
<Data level="4">DEF</Data>
</Sibling>
<Sibling>
<Data level="3">iii</Data>
</Sibling>
<Sibling>
<Data>2000</Data>
<Data>01/22/2013</Data>
</Sibling>
<Sibling>
<Data level="4">GHI</Data>
</Sibling>
<Sibling>
<Data level="3">mmm</Data>
</Sibling>
<Sibling>
<Data>4000</Data>
<Data>07/05/2011</Data>
</Sibling>
<Sibling>
<Data level="3">nnn</Data>
</Sibling>
<Sibling>
<Data>6000</Data>
<Data>01/07/2011</Data>
</Sibling>
</root>
使用 level 属性我需要移动兄弟姐妹成为孩子,如下所示。
输出
<Main>
<Group>
<Data level="4">ABC</Data>
<Subgroup>
<Data level="3">fff</Data>
<Child>
<Data>8000</Data>
<Data>01/04/2013</Data>
</Child>
</Subgroup>
<Subgroup>
<Data level="3">ggg</Data>
<Child>
<Data>2000</Data>
<Data>01/05/2013</Data>
</Child>
</Subgroup>
</Group>
<Group>
<Data level="4">DEF</Data>
<Subgroup>
<Data level="3">iii</Data>
<Child>
<Data>2000</Data>
<Data>01/22/2013</Data>
</Child>
</Subgroup>
</Group>
<Group>
<Data level="4">GHI</Data>
<Subgroup>
<Data level="3">mmm</Data>
<Child>
<Data>4000</Data>
<Data>07/05/2011</Data>
</Child>
</Subgroup>
<Subgroup>
<Data level="3">nnn</Data>
<Child>
<Data>6000</Data>
<Data>01/07/2011</Data>
</Child>
</Subgroup>
</Group>
</Main>
我开发的样式表不是很优雅,并且对级别值进行了假设。它通过基于逻辑和级别值输出打开和关闭标签来创建父节点。我更喜欢传递节点并添加子节点,但找不到这样做的示例。有没有人有更优雅的方式来做到这一点?
样式表
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes" />
<xsl:variable name="group_begin"><Group></xsl:variable>
<xsl:variable name="subgroup_begin"><Subgroup></xsl:variable>
<xsl:variable name="group_end"></Group></xsl:variable>
<xsl:variable name="subgroup_end"></Subgroup></xsl:variable>
<xsl:template match="/">
<Main>
<xsl:apply-templates select="root" />
</Main>
</xsl:template>
<xsl:template match="root">
<xsl:for-each select="Sibling">
<xsl:choose>
<xsl:when test="Data[not(@level)]">
<xsl:call-template name="Sibling">
<xsl:with-param name="level" select="0"/>
<xsl:with-param name="next_level" select="following-sibling::*[1]/Data/@level"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="Sibling">
<xsl:with-param name="level" select="Data/@level"/>
<xsl:with-param name="next_level" select="0"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
<xsl:value-of disable-output-escaping="yes" select="$group_end"/>
</xsl:template>
<xsl:template name="Sibling">
<xsl:param name="level" />
<xsl:param name="next_level"/>
<xsl:choose>
<xsl:when test="$level = '4'">
<xsl:value-of disable-output-escaping="yes" select="$group_begin"/>
<xsl:copy-of select="*"/>
</xsl:when>
<xsl:when test="$level = '3'">
<xsl:value-of disable-output-escaping="yes" select="$subgroup_begin"/>
<xsl:copy-of select="*"/>
</xsl:when>
<xsl:otherwise>
<Child>
<xsl:copy-of select="*"/>
</Child>
<xsl:value-of disable-output-escaping="yes" select="$subgroup_end"/>
<xsl:if test="$next_level = 4">
<xsl:value-of disable-output-escaping="yes" select="$group_end"/>
</xsl:if>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
我已经研究过在这里使用基于属性包装兄弟节点的技术,但属性级别实际上是一个相对值而不是固定的。