首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >使用XSLT,如何根据节点的值分隔节点?

使用XSLT,如何根据节点的值分隔节点?
EN

Stack Overflow用户
提问于 2010-03-25 23:30:05
回答 6查看 331关注 0票数 0

我有一个非常扁平的XML结构,我需要将其重新排序到分类的部分中,而且,在我的一生中,我不知道如何在XSLT中做到这一点(并不是说我是专家)。

基本上,原始的XML看起来有点像:

代码语言:javascript
运行
复制
<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>

我需要输出如下内容:

代码语言:javascript
运行
复制
<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>

注意,如果没有任何<c>元素,我就不能输出<c-things>,但是我提前知道完整的类型列表是什么,而且它相当短,所以为每种类型手工编写模板绝对是可能的。我觉得我可以用<xsl:if><xsl:for-each>一起破解一些东西,但我也觉得必须有更多的……“‘templatey”的方式。有人能帮上忙吗?

干杯。

EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2010-03-26 01:31:36

在XSLT 2中,您可以很好地做到这一点。假设您有一个模板,用于在元素中包装每个对象之前对其进行格式化:

代码语言:javascript
运行
复制
<xsl:template match="thing" mode="format-thing">
    <xsl:value-of select="value/text()"/>
</xsl:template>

然后,您可以将其应用于某些$type的每个元素,以通过一个函数构建元素:

代码语言:javascript
运行
复制
<xsl:function name="my:things-group" as="element()">
    <xsl:param name="type" as="xs:string"/>
    <xsl:param name="things" as="element(thing)*"/>

    <xsl:element name="{ concat($type, '-things') }">
        <xsl:for-each select="$things[type/text() eq $type]">
            <xsl:element name="{ $type }">
                <xsl:apply-templates select="." mode="format-thing"/>
            </xsl:element>
        </xsl:for-each>
    </xsl:element>
</xsl:function>

然后,您可以为每个唯一的类型(示例输入中的a、b、d)调用该函数来构建整个输出,您就完成了:

代码语言:javascript
运行
复制
<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>
票数 0
EN

Stack Overflow用户

发布于 2010-03-26 01:01:57

在使用Saxon时,请使用原生XSLT2.0分组。

代码语言:javascript
运行
复制
<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>

在XSLT 1.0中,可以使用键进行分组。这种方法被称为慕尼黑分组。

键定义了一个包含thing元素的索引,这些元素按照type元素的字符串值进行分组。函数key()返回键中具有指定值的所有节点。

外部的xsl: for -each选择key()最先返回的thing元素的值。

代码语言:javascript
运行
复制
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:output method="xml" indent="yes" />

    <xsl:key name="thing" match="thing" use="type" />

    <xsl:template match="things">
        <data>
            <xsl:for-each select="thing[generate-id(.)=generate-id(key('thing',type)[1])]">
                <xsl:element name="{concat(type,'-things')}">
                    <xsl:for-each select="key('thing',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>
票数 4
EN

Stack Overflow用户

发布于 2010-03-26 01:07:22

一般的解决方案是使用XSL密钥:

代码语言:javascript
运行
复制
<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>

以上结果如下:

代码语言:javascript
运行
复制
<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>
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2516869

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档