2011-03-23 62 views
2

我是XSL中的新手,但我需要XSL文件,將具有相同名稱屬性的節點合併到一個元素中,並且爲子節點完成同樣的工作,並且如果節點'具有不同的它的名字,XML的一個例子如下。合併多個節點與嵌套節點

<?xml version="1.0" encoding="UTF-8"?> 
<test> 
    <component name="root"> 
     <component name="c2"> 
      <component name="c3"> 
       <component name="c4" /> 
      </component> 
     </component> 
    </component> 
    <component name="root"> 
     <component name="c2"> 
      <component name="A4" /> 
     </component> 
     <component name="root"> 
      <component name="A3" /> 
     </component> 
     <component name="root"> 
      <component name="X1"> 
       <component name="X2" /> 
      </component> 
     </component> 
    </component> 
    <component name="difRoot"> 
    </component> 
</test> 

所需的輸出是如下

<output> 
<component name="root"> 
    <component name="c2"> 
     <component name="c3"> 
      <component name="c4"/> 
     </component> 
     <component name="A4"/> 
    </component> 
    <component name="A3"/> 
      <component name="X1"> 
       <component name="X2"/> 
      </component> 
</component> 
<component name="difRoot"/> 
</output> 

由於

回答

2

該樣式表:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:key name="kComponentByName" match="component" use="@name"/> 
    <xsl:template match="test"> 
     <output> 
      <xsl:call-template name="merge"> 
       <xsl:with-param name="pSequence" select="*"/> 
      </xsl:call-template> 
     </output> 
    </xsl:template> 
    <xsl:template name="merge"> 
     <xsl:param name="pSequence" select="/.."/> 
     <xsl:if test="$pSequence"> 
      <xsl:variable name="vName" select="$pSequence[1]/@name"/> 
      <xsl:for-each select="$pSequence[1]"> 
       <xsl:copy> 
        <xsl:copy-of select="@*"/> 
        <xsl:call-template name="merge"> 
         <xsl:with-param name="pSequence" 
          select="key('kComponentByName',$vName) 
             /component[@name != $vName]"/> 
        </xsl:call-template> 
       </xsl:copy> 
      </xsl:for-each> 
      <xsl:call-template name="merge"> 
       <xsl:with-param name="pSequence" 
        select="$pSequence[@name != $vName]"/> 
      </xsl:call-template> 
     </xsl:if> 
    </xsl:template> 
</xsl:stylesheet> 

輸出:

<output> 
    <component name="root"> 
     <component name="c2"> 
      <component name="c3"> 
       <component name="c4" /> 
      </component> 
      <component name="A4" /> 
     </component> 
     <component name="A3" /> 
     <component name="X1"> 
      <component name="X2" /> 
     </component> 
    </component> 
    <component name="difRoot" /> 
</output> 

注意:遞歸層次結構沒有完全解決,只能防止我自己成爲孩子。

更新:命名模板解釋:如果pSequence是不是空的,採取的第一個節點,然後自我複製和應用模板都具有相同的@name(過濾那些與此@name也)的component元素的孩子;最後稱自己過濾component元素pSequence與處理過的@name相同。因此,它逐級進行並逐個節點地篩選兄弟姐妹和孩子。完整的循環預防應該是通過傳遞具有祖先名稱的序列來進行過濾。這是作爲練習...

+0

非常感謝你的幫助亞歷杭德羅,你讓我的一天:D – Fattalo 2011-03-23 16:45:29

+0

@Fattalo:不客氣。 – 2011-03-23 17:00:58

+0

@Alejandro:你能否添加幾句話來解釋你的樣式表是如何工作的?我對這個問題感興趣,但我能找到答案。我讀過你的代碼,但我認爲我不太明白它的工作原理。 – MarcoS 2011-03-24 07:12:12