我正在尝试基于表示路径的level
元素从平面XML创建嵌套层次结构。每个level
元素及其所属的兄弟(名称和数字不同)应包含在“记录”元素中,从而创建树结构。
从来源(简化):
<?xml version="1.0" encoding="UTF-8"?>
<record>
<level>first</level>
<unitid>0001</unitid>
<a-few-more-siblings/>
<level>first/second</level>
<unitid>0002</unitid>
<many-more-siblings/>
<level>first/second/third</level>
<unitid>0003a</unitid>
<some-more-siblings/>
<level>first/second/third</level>
<unitid>0003b</unitid>
<many-more-siblings/>
<level>first/second/third</level>
<unitid>0003c</unitid>
<some-more-siblings/>
<level>first</level>
<unitid>0004</unitid>
<again-more-siblings/>
</record>
我想生成以下所需的输出:
<Record level="first">
<level>first</level>
<unitid>001</unitid>
<a-few-more-siblings/>
<Record level="second">
<level>second</level>
<unitid>002</unitid>
<many-more-siblings/>
<Record level="third">
<level>third</level>
<unitid>003a</unitid>
<some-more-siblings/>
</Record>
<Record level="third">
<level>third</level>
<unitid>003b</unitid>
<many-more-siblings/>
</Record>
<Record level="third">
<level>third</level>
<unitid>003c</unitid>
<some-more-siblings/>
</Record>
</Record>
</Record>
<Record level="first">
<level>first</level>
<unitid>0004</unitid>
<again-more-siblings/>
</Record>
我到目前为止最接近的是:
<record level="first">
<level>first</level>
<unitid>0001</unitid>
<some-other-siblings/>
<record level="second">
<level>first/second</level>
<unitid>0002</unitid>
<some-other-siblings/>
<record level="third">
<level>first/second</level>
<unitid>0002</unitid>
<some-other-siblings/>
<level>first/second/third</level>
<unitid>0003a</unitid>
<some-other-siblings/>
</record>
<record level="third">
<level>first/second</level>
<unitid>0002</unitid>
<some-other-siblings/>
<level>first/second/third</level>
<unitid>0003a</unitid>
<some-other-siblings/>
<level>first/second/third</level>
<unitid>0003b</unitid>
<some-other-siblings/>
</record>
<record level="third">
<level>first/second/third</level>
<unitid>0003c</unitid>
<some-other-siblings/>
</Record>
</record>
</record>
(第三级的不受欢迎的兄弟姐妹另外缩进;第一级0004
无法出现)
我尝试了针对类似问题提出的不同方法变体(“平面到层次结构”,“跟随兄弟姐妹直到”等),但最终要么停留在某个位置打印的太多兄弟节点,要么只输出第三级的第一个记录。
非常感谢任何帮助。
答案 0 :(得分:2)
这样做的一种方法是使用密钥。为了开始获取level
元素的兄弟,你可以定义一个键,用于按照前面第一个level
元素对元素进行分组(即该组将是所有兄弟姐妹)。
<xsl:key name="siblings"
match="*[not(self::level)]"
use="generate-id(preceding-sibling::level[1])" />
您还可以定义一个键来获取level
元素的直接“后代”(即每个级别,使用短名称将它们分组到第一个最前面的级别)。
<xsl:key name="nextlevel"
match="level"
use="generate-id(preceding-sibling::level[starts-with(current(), concat(., '/'))][1])" />
在XSLT中,您只需选择“第一个”级别元素
即可<xsl:apply-templates select="level[. = 'first']" />
然后,您将拥有一个匹配level
元素的通用模板,您可以利用这些元素输出兄弟姐妹和下一级元素
<xsl:template match="level">
<Record level="{.}">
<xsl:copy-of select="." />
<xsl:apply-templates select="key('siblings', generate-id())" />
<xsl:apply-templates select="key('nextlevel', generate-id())" />
</Record>
</xsl:template>
尝试以下XSLT
<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:key name="siblings" match="*[not(self::level)]" use="generate-id(preceding-sibling::level[1])" />
<xsl:key name="nextlevel" match="level" use="generate-id(preceding-sibling::level[starts-with(current(), concat(., '/'))][1])" />
<xsl:template match="record">
<xsl:apply-templates select="level[. = 'first']" />
</xsl:template>
<xsl:template match="level">
<Record level="{.}">
<xsl:copy-of select="." />
<xsl:apply-templates select="key('siblings', generate-id())" />
<xsl:apply-templates select="key('nextlevel', generate-id())" />
</Record>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
应用于XML时,输出以下内容
<Record level="first">
<level>first</level>
<unitid>0001</unitid>
<a-few-more-siblings/>
<Record level="first/second">
<level>first/second</level>
<unitid>0002</unitid>
<many-more-siblings/>
<Record level="first/second/third">
<level>first/second/third</level>
<unitid>0003a</unitid>
<some-more-siblings/>
</Record>
<Record level="first/second/third">
<level>first/second/third</level>
<unitid>0003b</unitid>
<many-more-siblings/>
</Record>
<Record level="first/second/third">
<level>first/second/third</level>
<unitid>0003c</unitid>
<some-more-siblings/>
</Record>
</Record>
</Record>
<Record level="first">
<level>first</level>
<unitid>0004</unitid>
<again-more-siblings/>
</Record>
这不是您当前显示的预期输出,因为您的预期输出有两个“第一个”level
元素包含在单个Record
元素中(与单独的{{1相比) “第三个”Record
元素的元素。如果您的预期输出确实符合预期,请尝试使用这两个模板替换匹配level
的模板:
record