Merge XML nodes using XSLT

前端 未结 2 1454
死守一世寂寞
死守一世寂寞 2020-12-22 07:43

I need to transform my XML into another datastructure. I recieve the XML like below:


  
    
      

        
相关标签:
2条回答
  • 2020-12-22 07:59
    <?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>
    
    0 讨论(0)
  • 2020-12-22 08:05

    I know this is an older question, but I wanted to provide an answer that, unlike the accepted answer, is shorter, simpler, makes use of common push-oriented design patterns, doesn't require templates with parameters, and doesn't do multiple complete traversals of the tree.

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

    ...is run against the provided 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>
    

    ...the wanted result is produced:

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

    Again, nothing inherently wrong with @Mike's answer, but this is much more maintainable and makes fuller use of the XSLT parser's native abilities.

    0 讨论(0)
提交回复
热议问题