使用XSLT,如何根据节点的值分离节点?
我有一个非常简单的XML结构,我需要将其重新排序到分类的部分,而且,就我的一生而言,我不知道如何在XSLT中实现它(这并不是说我是专家) 基本上,原始XML看起来有点像:使用XSLT,如何根据节点的值分离节点?,xslt,xpath,saxon,Xslt,Xpath,Saxon,我有一个非常简单的XML结构,我需要将其重新排序到分类的部分,而且,就我的一生而言,我不知道如何在XSLT中实现它(这并不是说我是专家) 基本上,原始XML看起来有点像: <things> <thing> <value>one</value> <type>a</type> </thing> <thing> <value>two</value>
<things>
<thing>
<value>one</value>
<type>a</type>
</thing>
<thing>
<value>two</value>
<type>b</type>
</thing>
<thing>
<value>thee</value>
<type>b</type>
</thing>
<thing>
<value>four</value>
<type>a</type>
</thing>
<thing>
<value>five</value>
<type>d</type>
</thing>
</things>
一
A.
二
B
你
B
四
A.
五
D
我需要输出如下内容:
<data>
<a-things>
<a>one</a>
<a>four</a>
</a-things>
<b-things>
<b>two</b>
<b>three</b>
</b-things>
<d-things>
<d>five</d>
</d-things>
</data>
一
四
二
三
五
请注意,如果没有任何
元素,我就无法输出
,但我确实提前知道完整的类型列表是什么,而且它相当短,因此每个类型的手工编码模板绝对是可能的。感觉上我可能可以用
和
一起破解一些东西,但感觉上肯定有更多的…'templatey的方法。有人能帮忙吗
干杯。当然,问这个问题让事情变得显而易见 我的解决方案确实使用了
,但我看不出它是怎么做到的,现在我想起来了。我的解决方案基本上如下所示:
<xsl:if test="/things/thing/type = 'a'">
<a-things>
<xsl:apply-templates select="/things/thing[type='a']" mode="a" />
</a-things>
</if>
<xsl:template match="/things/thing[type='a']" mode="a">
<a><xsl:value-of select="value"/>
</xsl:template>
对其他类型重复上述步骤。我已经把它编好了,它似乎工作得很好。当然,问这个问题让它变得很明显
<a-things>
<xsl:for-each select="thing[type = 'a']">
<a><xsl:value-of select="./value" /></a>
</xsl:for-each>
</a-things>
我的解决方案确实使用了
,但我看不出它是怎么做到的,现在我想起来了。我的解决方案基本上如下所示:
<xsl:if test="/things/thing/type = 'a'">
<a-things>
<xsl:apply-templates select="/things/thing[type='a']" mode="a" />
</a-things>
</if>
<xsl:template match="/things/thing[type='a']" mode="a">
<a><xsl:value-of select="value"/>
</xsl:template>
对其他类型重复上述步骤。我已经把它编码好了,它似乎工作得很好。
<a-things>
<xsl:for-each select="thing[type = 'a']">
<a><xsl:value-of select="./value" /></a>
</xsl:for-each>
</a-things>
如果您想变得非常时髦,请使用参数替换
和谓词,并使用属性值模板:
<xsl:param name="type" />
<xsl:element name="{$type}-things">
<xsl:for-each select="thing[type = $type]">
<xsl:element name="{$type}"><xsl:value-of select="./value" /></xsl:element>
</xsl:for-each>
</xsl:element>
如果您想变得非常时髦,请使用参数替换
和谓词,并使用属性值模板:
<xsl:param name="type" />
<xsl:element name="{$type}-things">
<xsl:for-each select="thing[type = $type]">
<xsl:element name="{$type}"><xsl:value-of select="./value" /></xsl:element>
</xsl:for-each>
</xsl:element>
使用分组,您可以在不使用以下条件的情况下进行分组:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="things">
<data>
<xsl:for-each select="thing[not(type=preceding-sibling::thing/type)]">
<xsl:variable name="type"><xsl:value-of select="type" /></xsl:variable>
<xsl:element name="concat($type, '-things')">
<xsl:for-each select="../thing[type=$type]">
<xsl:element name="$type">
<xsl:value-of select="value" />
</xsl:element>
</xsl:for-each>
</xsl:element>
</xsl:for-each>
</data>
</xsl:template>
</xsl:stylesheet>
使用分组,您可以在不使用以下条件的情况下进行分组:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="things">
<data>
<xsl:for-each select="thing[not(type=preceding-sibling::thing/type)]">
<xsl:variable name="type"><xsl:value-of select="type" /></xsl:variable>
<xsl:element name="concat($type, '-things')">
<xsl:for-each select="../thing[type=$type]">
<xsl:element name="$type">
<xsl:value-of select="value" />
</xsl:element>
</xsl:for-each>
</xsl:element>
</xsl:for-each>
</data>
</xsl:template>
</xsl:stylesheet>
在使用Saxon时,请使用本机XSLT 2.0分组
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" />
<xsl:template match="things">
<data>
<xsl:for-each-group select="thing" group-by="type">
<xsl:element name="{concat(current-grouping-key(),'-things')}">
<xsl:for-each select="current-group()">
<xsl:element name="{current-grouping-key()}">
<xsl:value-of select="value" />
</xsl:element>
</xsl:for-each>
</xsl:element>
</xsl:for-each-group>
</data>
</xsl:template>
</xsl:stylesheet>
在使用Saxon时,请使用本机XSLT2.0分组
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" />
<xsl:template match="things">
<data>
<xsl:for-each-group select="thing" group-by="type">
<xsl:element name="{concat(current-grouping-key(),'-things')}">
<xsl:for-each select="current-group()">
<xsl:element name="{current-grouping-key()}">
<xsl:value-of select="value" />
</xsl:element>
</xsl:for-each>
</xsl:element>
</xsl:for-each-group>
</data>
</xsl:template>
</xsl:stylesheet>
通用解决方案是使用XSL键:
<xsl:key name="kThingByType" match="thing" use="type" />
<xsl:template match="things">
<xsl:copy>
<xsl:apply-templates select="thing" mode="group">
<xsl:sort select="type" />
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="thing" mode="group">
<xsl:variable name="wholeGroup" select="key('kThingByType', type)" />
<xsl:if test="generate-id() = generate-id($wholeGroup[1])">
<xsl:element name="{type}-thing">
<xsl:copy-of select="$wholeGroup/value" />
</xsl:element>
</xsl:if>
</xsl:template>
上述收益率:
<things>
<a-thing>
<value>one</value>
<value>four</value>
</a-thing>
<b-thing>
<value>two</value>
<value>thee</value>
</b-thing>
<d-thing>
<value>five</value>
</d-thing>
</things>
一
四
二
你
五
通用解决方案是使用XSL键:
<xsl:key name="kThingByType" match="thing" use="type" />
<xsl:template match="things">
<xsl:copy>
<xsl:apply-templates select="thing" mode="group">
<xsl:sort select="type" />
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="thing" mode="group">
<xsl:variable name="wholeGroup" select="key('kThingByType', type)" />
<xsl:if test="generate-id() = generate-id($wholeGroup[1])">
<xsl:element name="{type}-thing">
<xsl:copy-of select="$wholeGroup/value" />
</xsl:element>
</xsl:if>
</xsl:template>
上述收益率:
<things>
<a-thing>
<value>one</value>
<value>four</value>
</a-thing>
<b-thing>
<value>two</value>
<value>thee</value>
</b-thing>
<d-thing>
<value>five</value>
</d-thing>
</things>
一
四
二
你
五
在XSLT2中,您可以非常优雅地执行此操作。假设您有一个模板,用于在将每个内容包装到元素中之前对其进行格式化:
然后,您可以为每个唯一类型(示例输入中的a、b、d)调用该函数来构建整个输出,您完成了:
<xsl:template match="/">
<data>
<xsl:sequence select="
for $type in distinct-values(things/thing/type/text())
return my:things-group($type, /things/thing)
"/>
</data>
</xsl:template>
在XSLT2中,您可以非常优雅地执行此操作。假设您有一个模板,用于在将每个内容包装到元素中之前对其进行格式化: 然后,您可以为每个唯一类型(示例输入中的a、b、d)调用该函数来构建整个输出,您完成了:
<xsl:template match="/">
<data>
<xsl:sequence select="
for $type in distinct-values(things/thing/type/text())
return my:things-group($type, /things/thing)
"/>
</data>
</xsl:template>