首页 > 解决方案 > XSLT 1.0 For-Each-Group 平面 XML

问题描述

我需要一些帮助。我对 XSLT 有点陌生。

我知道在 2.0 中您可以使用 For-Each-Group 来解决我的问题,但我仅限于 1.0。

我需要使用“group-starting-with”函数对平面 XML 进行分组。

这只是一个例子,但我的实际问题非常相似。

我有这个 XML:

<?xml version="1.0" encoding="UTF-8"?>
    <catalog>

        <xpto name="1">ABC</xpto>
        <title>Empire Burlesque</title>
        <artist>Bob Dylan</artist>
        <country>USA</country>
        <company>Columbia</company>
        <price>10.90</price>
        <year>1985</year>
        <xpto name="2">ABC</xpto>

        <xpto name="1">ABC</xpto>
        <title>Hide your heart</title>
        <artist>Bob Dylan</artist>
        <country>UK</country>
        <company>CBS Records</company>
        <price>9.90</price>
        <year>1988</year>
        <xpto name="2">ABC</xpto>

    </catalog>

我希望它是:

<?xml version="1.0" encoding="UTF-8"?>
    <catalog>

        <group>
            <xpto name="1">ABC</xpto>
            <title>Empire Burlesque</title>
            <artist>Bob Dylan</artist>
            <country>USA</country>
            <company>Columbia</company>
            <price>10.90</price>
            <year>1985</year>
            <xpto name="2">ABC</xpto>
        </group>

        <group>
            <xpto name="1">ABC</xpto>
            <title>Hide your heart</title>
            <artist>Bob Dylan</artist>
            <country>UK</country>
            <company>CBS Records</company>
            <price>9.90</price>
            <year>1988</year>
            <xpto name="2">ABC</xpto>
        </group>

    </catalog>

所以我想在每次出现以下内容时对元素进行分组:

    <xpto name="1">ABC</xpto>

有没有办法用 XSLT 1.0 做到这一点?

非常感谢!

标签: xmlxsltxslt-1.0xslt-grouping

解决方案


假设您要对以元素开头的<xpto name="1">元素进行分组,您可以定义一个键,以按其前面的第一个此类元素对其他子元素进行分组:

 <xsl:key name="start" match="*[not(self::xpto[@name='1'])]" use="generate-id(preceding-sibling::xpto[@name='1'][1])" />

然后,您可以选择所有起始元素,并获取其他组项,如下所示:

<xsl:apply-templates select=".|key('start', generate-id())" /> 

试试这个 XSLT

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

  <xsl:key name="start" match="*[not(self::xpto[@name='1'])]" use="generate-id(preceding-sibling::xpto[@name='1'][1])" />

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

  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()" />
    </xsl:copy>
  </xsl:template>

  <xsl:template match="catalog">
    <xsl:copy>
      <xsl:for-each select="xpto[@name='1']">
        <group>
          <xsl:apply-templates select=".|key('start', generate-id())" /> 
        </group>
      </xsl:for-each>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

推荐阅读