使用XSLT groupby转换XML

时间:2019-02-26 14:09:09

标签: xslt

我一直在关注XML,并尝试使用XSLT将其转换为下面提到的另一种格式。 XSLT代码有问题

<resultSet>
<Record>
<OrderID>50321523</OrderID>
<AttributeName>Color</AttributeName>
<AttributeValue>Matt-Light-Brown</AttributeValue>
</Record>
<Record>
<OrderID>50321523</OrderID>
<AttributeName>Size</AttributeName>
<AttributeValue>43.0-18</AttributeValue>
</Record>
<Record>
<OrderID>50321513</OrderID>
<AttributeName>Color</AttributeName>
<AttributeValue>Matt-Light-Brown</AttributeValue>
</Record>
<Record>
<OrderID>50321513</OrderID>
<AttributeName>Size</AttributeName>
<AttributeValue>43.0-18</AttributeValue>
</Record>
</resultSet>

目标XML:

<Record>
<Orders>
<OrderID>50321523</OrderID>
<Color>Matt-Light-Brown</Color>
<Size>43.0-18</Size>
</Orders>
<Orders>
<OrderID>50321513</OrderID>
<Color>Matt-Light-Brown</Color>
<Size>43.0-18</Size>
</Orders>
</Record>

以下是我正在使用的XSLT代码:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs"
    version="2.0">
<xsl:output indent="yes"/>    
  <xsl:key name="groups" match="/resultSet/Record" use="OrderID" />

  <xsl:template match="/Record">
    <xsl:apply-templates select="Record[generate-id() = generate-id(key('groups', OrderID)[1])]"/>
  </xsl:template>
  <xsl:template match="Record">
      <xsl:for-each select="key('groups', OrderID)">
<xsl:element name="{AttributeName}">
            <xsl:value-of select="AttributeValue"/>
      </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>

但是此XSLT无法正常工作。有人能帮忙吗?

1 个答案:

答案 0 :(得分:0)

如评论中所述,您的第一个模板应匹配resultSet。仅当/Record是根元素时,Record才能匹配任何内容,

此外,您的第二个模板缺少结尾</xsl:element>,尽管这可能是一个错字。但是,无论如何,您仍然需要添加Orders元素的创建,并复制现有的OrderID

尝试此XSLT 1.0

<xsl:stylesheet
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs"
    version="1.0">
  <xsl:output indent="yes"/>    

  <xsl:key name="groups" match="Record" use="OrderID" />

  <xsl:template match="/resultSet">
    <xsl:apply-templates select="Record[generate-id() = generate-id(key('groups', OrderID)[1])]"/>
  </xsl:template>

  <xsl:template match="Record">
    <Orders>
      <xsl:copy-of select="OrderID" />
      <xsl:for-each select="key('groups', OrderID)">
        <xsl:element name="{AttributeName}">
          <xsl:value-of select="AttributeValue"/>
        </xsl:element>
      </xsl:for-each>
    </Orders>
  </xsl:template>
</xsl:stylesheet>

请注意,如果您想在所有地方匹配所有元素,则无需使用xsl:key匹配中元素的完整路径。

请注意,如果您可以使用XSLT 2.0(这意味着使用支持XSLT 2.0的处理器。您不能仅将版本号更改为2.0并期望它在您的XSLT处理器仅支持XSLT 1.0的情况下可以工作),这样写:

<xsl:stylesheet
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs"
    version="2.0">
  <xsl:output indent="yes"/>    

  <xsl:template match="/resultSet">
    <xsl:for-each-group select="Record" group-by="OrderID">
      <Orders>
        <xsl:copy-of select="OrderID" />
        <xsl:for-each select="current-group()">
          <xsl:element name="{AttributeName}">
            <xsl:value-of select="AttributeValue"/>
          </xsl:element>
        </xsl:for-each>
      </Orders>
    </xsl:for-each-group>
  </xsl:template>
</xsl:stylesheet>