我在这里看到了这个问题的一些变化,但我不确定如何将它们应用到我的情况中,所以我希望也许有人可以帮助我。
我有一个类似于这个格式的平面XML文件:
<item id="1"/>
<item id="1.1"/>
<item id="1.1.1"/>
<item id="1.1.2"/>
<item id="1.1.2.1"/>
<item id="1.2"/>
<item id="1.3"/>
我希望根据id属性分层设置标签,如下所示:
<item id="1">
<item id="1.1">
<item id="1.1.1"/>
<item id="1.1.2">
<item id="1.1.2.1"/>
</item>
</item>
<item id="1.2"/>
<item id="1.3"/>
</item>
某些id值有两位数字(例如“1.2.3.15.1”),这使得比较它们更具挑战性。
帮助?
答案 0 :(得分:3)
选择正确的节点可能很棘手,但由于没有层次结构,这适用于您的示例输入(如果您向其添加根元素)
<!-- start somewhere -->
<xsl:template match="/root">
<root>
<!-- select all with no . in the id -->
<xsl:apply-templates select="//item[string-length(translate(@id,'1234567890',''))=0]" />
</root>
</xsl:template>
<xsl:template match="item">
<xsl:variable name="id" select="@id"/>
<!-- how many . have we ? That is how deep we are and add 1 -->
<xsl:variable name="deep" select="string-length(translate(@id,'1234567890',''))+1" />
<xsl:copy>
<!-- copy attribs over -->
<xsl:apply-templates select="@*"/>
<!-- select all nodes that start with our curent id,
select nodes that are just one level below us
and don't select our selfs-->
<xsl:apply-templates select="//item[starts-with(@id, $id) and string-length(translate(@id,'1234567890',''))=$deep and not(@id=$id)]"/>
</xsl:copy>
</xsl:template>
<!-- copy attribs -->
<xsl:template match="@*">
<xsl:copy />
</xsl:template>
答案 1 :(得分:1)
<强>予。这是一个简单的XSLT 2.0解决方案(在此之后会出现类似的XSLT 1.0解决方案):
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:my="my:my">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/*">
<xsl:sequence select="my:grouping(*, 1)"/>
</xsl:template>
<xsl:function name="my:grouping" as="element()*">
<xsl:param name="pNodes" as="element()*"/>
<xsl:param name="pLevel" as="xs:integer"/>
<xsl:if test="$pNodes">
<xsl:for-each-group select="$pNodes" group-by="tokenize(@id, '\.')[$pLevel]">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:sequence select="
my:grouping(current-group()[tokenize(@id, '\.')[$pLevel+1]], $pLevel+1)"/>
</xsl:copy>
</xsl:for-each-group>
</xsl:if>
</xsl:function>
</xsl:stylesheet>
将此转换应用于此XML文档(提供的XML片段,包含在单个顶部元素中,使其成为格式良好的XML文档):
<t>
<item id="1"/>
<item id="1.1"/>
<item id="1.1.1"/>
<item id="1.1.2"/>
<item id="1.1.2.1"/>
<item id="1.2"/>
<item id="1.3"/>
</t>
产生了想要的正确结果:
<item id="1">
<item id="1.1">
<item id="1.1.1"/>
<item id="1.1.2">
<item id="1.1.2.1"/>
</item>
</item>
<item id="1.2"/>
<item id="1.3"/>
</item>
<强> II。这是一个类似的XSLT 1.0解决方案:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="kFollowing" match="item"
use="generate-id(preceding-sibling::*
[string-length(current()/@id) > string-length(@id)
and
starts-with(current()/@id, concat(@id, '.'))]
[1])"/>
<xsl:template match="/*">
<xsl:call-template name="grouping">
<xsl:with-param name="pNodes" select="*"/>
<xsl:with-param name="pLevel" select="1"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="grouping">
<xsl:param name="pNodes"/>
<xsl:param name="pLevel" select="1"/>
<xsl:for-each select=
"$pNodes[$pLevel > string-length(@id) - string-length(translate(@id, '.', ''))]">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:call-template name="grouping">
<xsl:with-param name="pNodes" select="key('kFollowing', generate-id())"/>
<xsl:with-param name="pLevel" select="$pLevel+1"/>
</xsl:call-template>
</xsl:copy>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
当对同一文档(上图)应用此XSLT 1.0转换时,会生成相同的想要的正确结果:
<item id="1">
<item id="1.1">
<item id="1.1.1"/>
<item id="1.1.2">
<item id="1.1.2.1"/>
</item>
</item>
<item id="1.2"/>
<item id="1.3"/>
</item>