XSLT在ID相同时合并数据

时间:2012-06-28 14:54:04

标签: xml xslt

我在使用XML并在其上应用多个条件时遇到了一些问题。我有一个输入XML,如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<results xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ResultsType">
    <result>
        <resultSets>
            <resultSet>
                <row>
                    <column1>11111</column1>
                    <column2>0</column2>
                    <column3>imageId/111111</column3>
                    <column4>2012-04-03T10:11:22.187</column4>
                </row>
                <row>
                    <column1>11111</column1>
                    <column2>2</column2>
                    <column3>imageId/111112</column3>
                    <column4>2012-04-03T10:11:22.187</column4>
                </row>
                <row>
                    <column1>11111</column1>
                    <column2>2</column2>
                    <column3>imageId/111113</column3>
                    <column4>2012-04-03T10:11:22.187</column4>
                </row>
                <row>
                    <column1>22222</column1>
                    <column2>0</column2>
                    <column3>imageId/222222</column3>
                    <column4>2012-04-03T10:11:22.187</column4>
                </row>
                <row>
                    <column1>22222</column1>
                    <column2>2</column2>
                    <column3>imageId/222223</column3>
                    <column4>2012-04-03T10:11:22.187</column4>
                </row>
            </resultSet>
        </resultSets>
    </result>
</results>

但我希望它看起来像这样:

<?xml version="1.0" encoding="UTF-8"?>
<results xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ResultsType">
    <result>
        <row>
            <id>11111</id>
            <lagrgeImage>imageId/111111</lagrgeImage>
            <smallImage>imageId/111112</smallImage>
            <smallImage>imageId/111113</smallImage>
        </row>
        <row>
            <id>22222</id>
            <lagrgeImage>imageId/222222</lagrgeImage>
            <smallImage>imageId/222223</smallImage>
        </row>
    </result>
</results>

如您所见,有两种过滤条件:

如果column2 = 0,则输出中需要largeImage标记,但是column2 = 2则输出中需要smallImage标记。

更新

以下两个示例都运行良好,但它们都包括root中的名称空间,这是意外的。我得到的输出是:

<?xml version="1.0" encoding="utf-8"?>
<results xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ResultsType">
    <result>
        <row>
            <id>11111</id>
            <largeImage>imageId/111111</largeImage>
            <smallImage>imageId/111112</smallImage>
            <smallImage>imageId/111113</smallImage>
        </row>
        <row>
            <id>22222</id>
            <largeImage>imageId/222222</largeImage>
            <smallImage>imageId/222223</smallImage>
        </row>
    </result>
</results>

如何从上述输出中删除xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ResultsType"

3 个答案:

答案 0 :(得分:1)

如果您使用的是XSLT2.0,则可以使用 for-each-group 功能。

<xsl:for-each-group select="row" group-by="column1">

假设您的上下文为 resultSets ,则会按 column1 中的“id”对行进行分组。然后可以按如下方式获得当前分组密钥:

<xsl:value-of select="current-grouping-key()"/>

要获取组中的各个行,将它们转换为largeImage或smallImage,您可以这样做

<xsl:apply-templates select="current-group()" />

这是完整的XSLT

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

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

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

   <xsl:template match="resultSet">
      <xsl:apply-templates select="@*"/>
      <xsl:for-each-group select="row" group-by="column1">
         <row>
            <id><xsl:value-of select="current-grouping-key()"/></id>
            <xsl:apply-templates select="current-group()" />
          </row>
      </xsl:for-each-group>
   </xsl:template>

   <xsl:template match="row[column2='0']">
      <largeImage><xsl:value-of select="column3" /></largeImage>
   </xsl:template>

   <xsl:template match="row">
      <smallImage><xsl:value-of select="column3" /></smallImage>
   </xsl:template>

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

   <xsl:template match="*">
      <xsl:element name="{local-name()}"> 
         <xsl:apply-templates select="@*|node()"/>
      </xsl:element>
   </xsl:template>
</xsl:stylesheet>

当应用于您的示例XML时,输出以下内容

<results xmlns="http://www.castiron.com//response">
   <result>
      <row>
         <id>11111</id>
         <largeImage>imageId/111111</largeImage>
         <smallImage>imageId/111112</smallImage>
         <smallImage>imageId/111113</smallImage>
      </row>
      <row>
         <id>22222</id>
         <largeImage>imageId/222222</largeImage>
         <smallImage>imageId/222223</smallImage>
      </row>
   </result>
</results>

答案 1 :(得分:0)

为了吐出'largeimage'和'smallimage'元素(在xsl for循环中),尝试:

<xsl:if test="/results/result/resultSets/resultSet/row/column2='0'">
<largeImage>
<xsl:value-of select="/results/result/resultSets/resultSet/row/column3"/>
</largeImage>    
</xsl:if>

答案 2 :(得分:0)

在XSLT 1.0中,(IMO)最直接的解决方案是首先找到所有唯一ID。这可以通过查找未出现在任何先前兄弟节点中的ID来实现(换句话说,对于每个ID,您找到包含该ID的第一个元素)。

拥有唯一ID后,您可以<xsl:for-each>覆盖具有相同ID的所有<row>兄弟姐妹(包括当前元素)。在下面的代码中,我使用<xsl:choose>元素检查<column2>并根据<largeImage>值插入<smallImage><column2>元素。

这就是你要找的东西:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes"/>

    <xsl:template match="/results">
        <results>
            <xsl:copy-of select="@*"/>
            <result>
                <xsl:apply-templates select="result"/>
            </result>
        </results>
    </xsl:template>

    <xsl:template match="/results/result/resultSets/resultSet/row">
        <xsl:if test="not(column1 = preceding-sibling::row/column1)">
            <row>
                <id><xsl:value-of select="column1"/></id>
                <xsl:for-each select="../row[column1 = current()/column1]">
                    <xsl:choose>
                        <xsl:when test="column2 = '0'">
                            <largeImage><xsl:value-of select="column3"/></largeImage>
                        </xsl:when>
                        <xsl:when test="column2 = '2'">
                            <smallImage><xsl:value-of select="column3"/></smallImage>
                        </xsl:when>
                    </xsl:choose>
                </xsl:for-each>
            </row>
        </xsl:if>
    </xsl:template>

</xsl:stylesheet>