2009-11-26 116 views
1

是否可以合併相同指定類型的每個節點序列? (在這種情況下, 'AAA')(未序列的只是第一次出現)合併相同類型的相鄰節點(XSLT 1.0)

這裏是我的XML輸入:

<block> 
    <aaa>text1</aaa> 
    <aaa>text2</aaa> 
    <aaa><xxx>text3</xxx></aaa> 
    <bbb>text4</bbb> 
    <aaa>text5</aaa> 
    <bbb><yyy>text6</yyy></bbb> 
    <bbb>text7</bbb> 
    <aaa>text8</aaa> 
    <aaa><zzz>text9</zzz></aaa> 
    <aaa>texta</aaa> 
</block> 

而且我想下面的輸出:

<block> 
    <aaa>text1text2<xxx>text3</xxx></aaa> 
    <bbb>text4</bbb> 
    <aaa>text5</aaa> 
    <bbb><yyy>text6</yyy></bbb> 
    <bbb>text7</bbb> 
    <aaa>text8<zzz>text9</zzz>texta</aaa> 
</block> 

任何幫助表示讚賞

回答

0

這是另一種方法來做到這一點。

首先,匹配塊元件

<xsl:template match="block/child::*"> 

接下來,檢查如果該元素的最直接的兄弟具有不同的名稱的所有子節點上,表示這是第一個或多個相鄰元素:

<xsl:if test="local-name(preceding-sibling::*[position()=1]) != $name"> 

如果是這樣,您可以複製該節點。然後,您需要複製具有相同名稱的以下兄弟姐妹。我通過遞歸調用每個緊隨同胞的模板名稱相同

<xsl:apply-templates select="following-sibling::*[1][local-name()=$name]" mode="next"/> 

把所有這些組合起來做這給

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

    <!-- Match children of the block element --> 
    <xsl:template match="block/child::*"> 
     <xsl:variable name="name" select="local-name()"/> 

     <!-- Is this the first element in a sequence? --> 
     <xsl:if test="local-name(preceding-sibling::*[position()=1]) != $name"> 
     <xsl:copy> 
      <xsl:apply-templates /> 

      <!-- Match the next sibling if it has the same name --> 
      <xsl:apply-templates select="following-sibling::*[1][local-name()=$name]" mode="next"/> 
     </xsl:copy> 
     </xsl:if> 
    </xsl:template> 

    <!-- Recursive template used to match the next sibling if it has the same name --> 
    <xsl:template match="block/child::*" mode="next"> 
     <xsl:variable name="name" select="local-name()"/> 
     <xsl:apply-templates /> 
     <xsl:apply-templates select="following-sibling::*[1][local-name()=$name]" mode="next"/> 
    </xsl:template> 

    <!-- Template used to copy a generic node --> 
    <xsl:template match="@* | node()"> 
     <xsl:copy> 
      <xsl:apply-templates select="@* | node()"/> 
     </xsl:copy> 
    </xsl:template> 
</xsl:stylesheet> 
+0

對於我的問題的解決方案,我只需要合併「AAA」的節點,因此,我必須通過將'match ='int:block/child :: *'''更改爲'match ='int:block/child :: aaa''來稍微調整您的解決方案,否則它可以完美地工作。 – Peter 2009-11-27 20:59:34

0

假設您只有一個block,Muenchian method是最優化的方式:

<!-- group nodes by name --> 
<xsl:key name="block-children-by-name" match="block/*" use="name()"/> 

<!-- for nodes that aren't first in their group, no output --> 
<xsl:template match="block/*" /> 

<!-- for nodes that are first in their group, combine group children and output --> 
<xsl:template match="block/*[generate-id() = 
          generate-id(key('block-children-by-name', name())[1])]"> 
    <xsl:copy> 
    <xsl:copy-of select="key('block-children-by-name', name())/*"/> 
    </xsl:copy> 
</xsl:template> 

請注意,這隻合併子節點,而不是例如。可能在aaabbb本身上發生的任何屬性。

0

這裏的另一種方法,而無需使用遞歸模板。

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

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

    <xsl:template match="aaa"> 
    <xsl:if test="not(preceding-sibling::*[1]/self::aaa)"> 
     <xsl:variable name="following" 
        select="following-sibling::aaa[ 
           not(preceding-sibling::*[ 
           not(self::aaa) and 
           not(following-sibling::aaa = current()) 
           ]) 
          ]"/> 
     <xsl:copy> 
     <xsl:apply-templates select="$following/@*"/> 
     <xsl:apply-templates select="@*"/> 
     <xsl:apply-templates select="node()"/> 
     <xsl:apply-templates select="$following/node()"/> 
     </xsl:copy> 
    </xsl:if> 
    </xsl:template> 

</xsl:stylesheet> 

的頗爲曲折XPath表達式,用於選擇以下的兄弟被歸併到當前的一個aaa節點:

following-sibling::aaa[      # following 'aaa' siblings 
    not(preceding-sibling::*[     # if they are not preceded by 
    not(self::aaa) and      #  a non-'aaa' node 
    not(following-sibling::aaa = current()) #  after the current node 
    ]) 
]