XSLT 1.0 For-Each-Group 平面 XML

XSLT 1.0 For-Each-Group flat 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 做到这一点吗?

非常感谢!

假设您想要对以 <xpto name="1"> 元素开头的元素进行分组,您可以定义一个键以将其他子元素分组到它们之前的第一个这样的元素:

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

然后,您可以 select 所有起始元素,并像这样获取其他组项目:

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