使用XSLT以非线性方式转换XML

时间:2013-07-05 11:12:25

标签: xml xslt

如何使用XSLT将以下两个XML中的第一个转换为第二个?

这样做的困难在于它并不是一个线性过程,因为第一个XML按日期对博客的评论进行分组,而第二个XML按用户对评论进行分组。

输入XML:

<blog>
    <block>
        <day>2011-11-20</day> 
        <data>
            <comment>bla bla bla</comment>
            <ops>
                <user>357098</user> 
            <ops>
        </data>
    </block>
    <block>
        <day>2011-11-21</day> 
        <data>
            <comment>blu blu blu</comment>
            <ops>
                <user>357098</user> 
            <ops>
        </data>
        <data>
            <comment>bum</comment>
            <ops>
                <user>11111</user> 
            <ops>
        </data>
    </block>
</blog>

我必须在输出中得到这个:

<blog>
    <user id="357098">
        <list>
            <comment>
                <text>bla bla bla</text>
                <date>2011-11-20</date>
            </comment>
            <comment>
                <text>blu blu blu</text>
                <date>2011-11-21</date>
            </comment>          
        </list>
    </user>
    <user id="11111">
        <list>
            <comment>
                <text>bum</text>
                <date>2011-11-21</date>
            </comment>
        </list>
    </user>
</blog>

1 个答案:

答案 0 :(得分:1)

这是一个典型的分组问题,这是一个XSLT 1.0解决方案:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
  <xsl:key name="kUser" match="data" use="ops/user" />

  <xsl:template match="/*">
    <xsl:copy>
      <xsl:apply-templates select="block/data[generate-id() = 
                                            generate-id(key('kUser', ops/user)[1])]" />
    </xsl:copy>
  </xsl:template>

  <xsl:template match="data">
    <user id="{ops/user}">
      <list>
        <xsl:apply-templates select="key('kUser', ops/user)/comment" />
      </list>
    </user>
  </xsl:template>

  <xsl:template match="comment">
    <comment>
      <text>
        <xsl:value-of select="." />
      </text>
      <date>
        <xsl:value-of select="../../day" />
      </date>
    </comment>
  </xsl:template>
</xsl:stylesheet>

在样本输入上运行时,结果为:

<blog>
  <user id="357098">
    <list>
      <comment>
        <text>bla bla bla</text>
        <date>2011-11-20</date>
      </comment>
      <comment>
        <text>blu blu blu</text>
        <date>2011-11-21</date>
      </comment>
    </list>
  </user>
  <user id="11111">
    <list>
      <comment>
        <text>bum</text>
        <date>2011-11-21</date>
      </comment>
    </list>
  </user>
</blog>