我有一个扁平的结构化XML文件,如下所示:
<rs>
<r id="r1" lev="0"/>
<r id="r2" lev="1"/>
<r id="r3" lev="0"/>
<r id="r4" lev="1"/>
<r id="r5" lev="2"/>
<r id="r6" lev="3"/>
<r id="r7" lev="0"/>
<r id="r8" lev="1"/>
<r id="r9" lev="2"/>
</rs>
我需要转换为嵌套的。规则是这样的,所有r[number(@lev) gt 0]
都应该嵌套在r[number(@lev) eq 0]
中。输出将是这样的:
<rs>
<r id="r1">
<r id="r2"/>
</r>
<r id="r3">
<r id="r4">
<r id="r5">
<r id="r6"/>
</r>
</r>
</r>
<r id="r7">
<r id="r8">
<r id="r9"/>
</r>
</r>
</rs>
我尝试的是以下转型:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="2.0">
<xsl:output indent="yes"/>
<xsl:template match="/">
<rs>
<xsl:apply-templates select="node()|@*"/>
</rs>
</xsl:template>
<xsl:template match="r">
<xsl:variable name="lev" select="number(@lev)" as="xs:double"/>
<r>
<xsl:copy-of select="@id"/>
<xsl:apply-templates select="following-sibling::r[not(number(@lev) eq $lev)
and
count(preceding-sibling::r[number(@lev) eq $lev]) eq 1]"/>
</r>
</xsl:template>
</xsl:stylesheet>
但是,这并没有给我预期的结果。指出我的编码错误或任何其他方法来完成工作,非常感谢。
答案 0 :(得分:3)
此转化:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:key name="kRByLevelAndParent" match="r"
use="concat(generate-id(preceding-sibling::r
[not(@lev >= current()/@lev)][1]),
@lev
)"/>
<xsl:template match="/*">
<rs>
<xsl:apply-templates select="key('kRByLevelAndParent', '0')"/>
</rs>
</xsl:template>
<xsl:template match="r">
<r id="{@id}">
<xsl:apply-templates select=
"key('kRByLevelAndParent',
concat(generate-id(), @lev+1)
)"/>
</r>
</xsl:template>
</xsl:stylesheet>
应用于提供的XML文档时:
<rs>
<r id="r1" lev="0"/>
<r id="r2" lev="1"/>
<r id="r3" lev="0"/>
<r id="r4" lev="1"/>
<r id="r5" lev="2"/>
<r id="r6" lev="3"/>
<r id="r7" lev="0"/>
<r id="r8" lev="1"/>
<r id="r9" lev="2"/>
</rs>
会产生想要的正确结果:
<rs>
<r id="r1">
<r id="r2"/>
</r>
<r id="r3">
<r id="r4">
<r id="r5">
<r id="r6"/>
</r>
</r>
</r>
<r id="r7">
<r id="r8">
<r id="r9"/>
</r>
</r>
</rs>
<强>解释强>:
使用复合键进行位置分组 - 对于其所有“子”,元素是第一个前一个兄弟,因此其lev
属性小于其各自的lev
属性。
答案 1 :(得分:1)
http://www.saxonica.com/papers/ideadb-1.1/mhk-paper.xml
搜索递归模板名称=“进程级别”。
答案 2 :(得分:0)
由于我需要在临时变量中应用转换,因此使用xsl:key
无济于事。如果我必须使用 Dimitre的解决方案 ,我必须更改现有代码。
显然,在我的问题中,我没有在这方面描述太多,这是我的错误。
来自 博士提供的//programlisting[contains(.,'xsl:template name="process-level"')]
链接。凯 我已经结束了解决方案,可能是其他人可能会在以后使用它:
样式表
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs">
<xsl:output indent="yes"/>
<xsl:template match="/*">
<rs>
<xsl:call-template name="process-level">
<xsl:with-param name="context"
select="r"/>
<xsl:with-param name="level"
select="0"/>
</xsl:call-template>
</rs>
</xsl:template>
<xsl:template name="process-level">
<xsl:param name="context" required="yes" as="element()*"/>
<xsl:param name="level" as="xs:double"/>
<xsl:for-each-group select="$context"
group-starting-with="*[number(@lev) eq $level]">
<xsl:element name="{name()}">
<!--<xsl:variable name="position" as="xs:double">
<xsl:number level="any" count="*[starts-with(local-name(), 'r')]"/>
</xsl:variable>-->
<xsl:copy-of select="@id"/>
<xsl:call-template name="process-level">
<xsl:with-param name="context" select="current-group()[position() != 1]"/>
<xsl:with-param name="level" select="$level + 1"/>
</xsl:call-template>
</xsl:element>
</xsl:for-each-group>
</xsl:template>
</xsl:stylesheet>
输入XML
<rs>
<r id="r1" lev="0"/>
<r id="r2" lev="1"/>
<r id="r3" lev="0"/>
<r id="r4" lev="1"/>
<r id="r5" lev="2"/>
<r id="r6" lev="3"/>
<r id="r7" lev="0"/>
<r id="r8" lev="1"/>
<r id="r9" lev="2"/>
</rs>
结果
<rs>
<r id="r1">
<r id="r2"/>
</r>
<r id="r3">
<r id="r4">
<r id="r5">
<r id="r6"/>
</r>
</r>
</r>
<r id="r7">
<r id="r8">
<r id="r9"/>
</r>
</r>
</rs>