使用XSLT合并XML节点

时间:2011-08-06 11:07:42

标签: xml xslt

我需要将XML转换为另一个数据结构。 我收到如下的XML:

<results>
  <resultset>
    <result>
      <name>BMW Cars</name>
      <code>BMW Pkw</code>
      <model.model>730d Saloon</model.model>
      <model.name>KM21</model.name>
    </result>
    <result>
      <name>BMW Cars</name>
      <code>BMW Pkw</code>
      <model.model>120i 3 doors</model.model>
      <model.name>UA51</model.name>
    </result>
    <result>
      <name>BMW Cars</name>
      <code>BMW Pkw</code>
      <model.model>Z4 sDrive23i</model.model>
      <model.name>LM31</model.name>
    </result>
    <result>
      <name>Audi</name>
      <code>AUDI</code>
      <model.model>A4 SAL.3.0 Q SPT TIP 5SPD</model.model>
      <model.name>8E2SFZ04</model.name>
    </result>
    <result>
      <name>Audi</name>
      <code>AUDI</code>
      <model.model>A6 SAL. 2.5TDI SPORT MAN.6SP.</model.model>
      <model.name>4B2BBC04</model.name>
    </result>
    <result>
      <name>AUdi</name>
      <code>AUDI</code>
      <model.model>A8 4.2 QUATTRO 6-SPD TIP</model.model>
      <model.name>4E201L04</model.name>
    </result>
  </resultset>
</results>

我需要它像这样:

<results>
  <resultset>
    <result>
      <name>BMW Cars</name>
      <code>BMW Pkw</code>
      <model.model>730d Saloon</model.model>
      <model.name>KM21</model.name>
      <model.model>120i 3 doors</model.model>
      <model.name>UA51</model.name>
      <model.model>Z4 sDrive23i</model.model>
      <model.name>LM31</model.name>
    </result>
    <result>
      <name>Audi</name>
      <code>AUDI</code>
      <model.model>A4 SAL.3.0 Q SPT TIP 5SPD</model.model>
      <model.name>8E2SFZ04</model.name>
      <model.model>A6 SAL. 2.5TDI SPORT MAN.6SP.</model.model>
      <model.name>4B2BBC04</model.name>
      <model.model>A8 4.2 QUATTRO 6-SPD TIP</model.model>
      <model.name>4E201L04</model.name>
    </result>
  </resultset>
</results>

我花了很多时间来解决这个问题,但到目前为止还没有运气。 有谁知道如何解决这个问题?

2 个答案:

答案 0 :(得分:1)

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

<xsl:key name="groupName" match="//results/resultset/result" use="concat(name, code)" />

<xsl:template match="/">

  <results>
  <resultset>
  <xsl:for-each select="//results/resultset/result[generate-id() = generate-id( key('groupName', concat(name, code))   [1] ) ]" >


      <xsl:call-template name="group">
        <xsl:with-param name="k1" select="name" />
        <xsl:with-param name="k2" select="code" />
      </xsl:call-template>

  </xsl:for-each>

  </resultset>
  </results>
</xsl:template> 

<xsl:template name="group">
<xsl:param name="k1" /> 
<xsl:param name="k2" /> 

    <result>
      <xsl:copy-of select="name" />       
      <xsl:copy-of select="code" />       

      <xsl:for-each select="//results/resultset/result[name = $k1][code = $k2]">

        <xsl:copy-of select="model.model" />       
        <xsl:copy-of select="model.name" />       

      </xsl:for-each>
    </result>

</xsl:template> 
</xsl:stylesheet>

答案 1 :(得分:0)

我知道这是一个较老的问题,但我想提供一个答案,与接受的答案不同,它更短,更简单,使用常见的面向推送的设计模式,不需要带参数的模板,并且不会不要对树进行多次完整的遍历。

当这个XSLT:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output omit-xml-declaration="no" indent="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:key name="kResultByNameCode" match="result" use="concat(name, '+', code)"/>

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

  <xsl:template match="result[generate-id() = generate-id(key('kResultByNameCode', concat(name, '+', code))[1])]">
    <xsl:copy>
      <xsl:apply-templates select="name | code"/>
      <xsl:apply-templates select="key('kResultByNameCode', concat(name, '+', code))/*[starts-with(name(), 'model')]"/> 
    </xsl:copy> 
  </xsl:template>

  <xsl:template match="result"/>

</xsl:stylesheet>

...针对提供的XML运行:

<?xml version="1.0" encoding="UTF-8"?>
<results>
  <resultset>
    <result>
      <name>BMW Cars</name>
      <code>BMW Pkw</code>
      <model.model>730d Saloon</model.model>
      <model.name>KM21</model.name>
    </result>
    <result>
      <name>BMW Cars</name>
      <code>BMW Pkw</code>
      <model.model>120i 3 doors</model.model>
      <model.name>UA51</model.name>
    </result>
    <result>
      <name>BMW Cars</name>
      <code>BMW Pkw</code>
      <model.model>Z4 sDrive23i</model.model>
      <model.name>LM31</model.name>
    </result>
    <result>
      <name>Audi</name>
      <code>AUDI</code>
      <model.model>A4 SAL.3.0 Q SPT TIP 5SPD</model.model>
      <model.name>8E2SFZ04</model.name>
    </result>
    <result>
      <name>Audi</name>
      <code>AUDI</code>
      <model.model>A6 SAL. 2.5TDI SPORT MAN.6SP.</model.model>
      <model.name>4B2BBC04</model.name>
    </result>
    <result>
      <name>Audi</name>
      <code>AUDI</code>
      <model.model>A8 4.2 QUATTRO 6-SPD TIP</model.model>
      <model.name>4E201L04</model.name>
    </result>
  </resultset>
</results>

...生成了想要的结果:

<results>
  <resultset>
    <result>
      <name>BMW Cars</name>
      <code>BMW Pkw</code>
      <model.model>730d Saloon</model.model>
      <model.name>KM21</model.name>
      <model.model>120i 3 doors</model.model>
      <model.name>UA51</model.name>
      <model.model>Z4 sDrive23i</model.model>
      <model.name>LM31</model.name>
    </result>
    <result>
      <name>Audi</name>
      <code>AUDI</code>
      <model.model>A4 SAL.3.0 Q SPT TIP 5SPD</model.model>
      <model.name>8E2SFZ04</model.name>
      <model.model>A6 SAL. 2.5TDI SPORT MAN.6SP.</model.model>
      <model.name>4B2BBC04</model.name>
      <model.model>A8 4.2 QUATTRO 6-SPD TIP</model.model>
      <model.name>4E201L04</model.name>
    </result>
  </resultset>
</results>

同样,@ Mike的答案没有任何内在错误,但这更易于维护,并且可以更充分地利用XSLT解析器的本机能力。