按孙项的值对节点进行分组

  • 本文关键字:节点 孙项 xml xslt-1.0
  • 更新时间 :
  • 英文 :


我有一个XML,它以组类型作为最深的节点。我必须对 XML 的一个子部分进行分组,否则返回完全相同的 XML。

我在Stackoverflow中查看了不同的问题。具体来说,我一直基于这个答案: 在 Xsl 中按子节点的值对 xml 节点进行分组

输入 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>

第一件事:你想按共同typeposition节点进行分组 - 所以你应该让你的键匹配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>

请注意,这取决于包含有效 XML 元素名称字符串type。在你的例子中不是,我用normalize-space()来做到这一点。但是您的实际输入可能包含其他带有其他问题的字符串。

最新更新