我有一个XML,该XML具有一个组类型作为最深的节点。我必须对XML的一个子部分进行分组,否则将返回完全相同的XML。
我在Stackoverflow中研究了不同的问题。具体来说,我一直基于这一答案: Grouping xml nodes by value of a child in Xsl
输入XML如下:
<list>
<element>
<foo>
<bar>
</bar>
</foo>
<values>
<position>
<foo2>
</foo2>
<type>first
</type>
</position>
<position>
<foo2>
</foo2>
<type>second
</type>
</position>
<position>
<foo2>
</foo2>
<type>first
</type>
</position>
</values>
</element>
</list>
输出XML应该如下所示:
<list>
<element>
<foo>
<bar>
</bar>
</foo>
<types>
<first>
<values>
<position>
<foo2>
</foo2>
</position>
<position>
<foo2>
</foo2>
</position>
</values>
</first>
<second>
<values>
<position>
<foo2>
</foo2>
</position>
</values>
</second>
</types>
</element>
</list>
到目前为止,我有以下XLST,它会将转换复制到顶部:
<xsl:key name="types" match="type" use="."/>
<xsl:template match="/list">
<root>
<xsl:apply-templates select="element/values/position/type[generate-id() = generate-id(key('types', .)[1])]"/>
<xsl:apply-templates select="*|@*|comment()|text()"/>
</root>
</xsl:template>
<xsl:template match="type">
<xsl:variable name="currentType" select="."/>
<xsl:element name="{$currentType}">
<xsl:apply-templates select="*|@*|comment()|text()"/>
</xsl:element>
</xsl:template>
<xsl:template match="*">
<xsl:element name="{local-name(.)}">
<xsl:apply-templates select="*|@*|comment()|text()"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
一旦我将一个应用模板放在父节点上(在与类型匹配的模板中),它就不再返回任何内容:
<xsl:template match="type">
<xsl:variable name="currentType" select="."/>
<xsl:element name="{$currentType}">
<xsl:apply-templates select="../../*|@*|comment()|text()"/>
</xsl:element>
答案 0 :(得分:1)
第一件事:您想将position
节点按公用type
分组-因此,您应该使密钥匹配position
并使用type
。
一旦您这样做,就可以很简单:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="pos-by-type" match="position" use="type"/>
<!-- identity transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="values">
<types>
<xsl:for-each select="position[generate-id() = generate-id(key('pos-by-type', type)[1])]">
<xsl:element name="{normalize-space(type)}">
<values>
<xsl:apply-templates select="key('pos-by-type', type)"/>
</values>
</xsl:element>
</xsl:for-each>
</types>
</xsl:template>
<xsl:template match="type"/>
</xsl:stylesheet>
请注意,这取决于type
包含的字符串,该字符串是有效的XML元素名称。在您的示例中不是,我使用了normalize-space()
。但是您的实际输入可能包含其他字符串,还有其他问题。