2013-05-03 17 views
1

我正在使用XSLT將XML文檔從一種文檔類型轉換爲另一種文檔類型。在簡化形式,我有一些看起來像這樣:在XSLT中放置一組元素的包裝

<section> 
    <title>Title</title> 
    <a>content1</a> 
    <a>content2</a> 
    <a>content3</a> 
    <a>content4</a> 
    <b>other content</b> 
    <a>content5</a> 
    <a>content6</a> 
    <a>content7</a> 
    <c>other content</c> 
    <a>content8</a> 
    <a>content9</a> 
    <a>content10</a> 
</section> 

我想是把周圍<a>單元的組的包裝,所以翻譯的結果是這樣的:

<section> 
    <title>Title</title> 
    <a-wrapper> 
     <a>content1</a> 
     <a>content2</a> 
     <a>content3</a> 
     <a>content4</a> 
    </a-wrapper> 
    <b>other content</b> 
    <a-wrapper> 
     <a>content5</a> 
     <a>content6</a> 
     <a>content7</a> 
    </a-wrapper> 
    <c>other content</c> 
    <a-wrapper> 
     <a>content8</a> 
     <a>content9</a> 
     <a>content10</a> 
    </a-wrapper> 
</section> 

我目前的模板看起來像這樣:

<xsl:template match="a"> 
    <xsl:choose> 
     <xsl:when test="not(preceding-sibling::a)"> 
      <xsl:element name="a-wrapper"> 
       <xsl:element name="a"> 
        <xsl:apply-templates/> 
       </xsl:element> 
       <xsl:apply-templates select="following-sibling::a[generate-id(preceding-sibling::a[last()]) = generate-id(current())]"/> 
      </xsl:element> 
     </xsl:when> 
     <xsl:otherwise> 
      <xsl:element name="a"> 
       <xsl:apply-templates/> 
      </xsl:element> 
     </xsl:otherwise> 
    </xsl:choose> 
</xsl:template> 

這讓我在那裏。問題是,apply-templates標籤中的select子句獲取所有的<a>標籤,當我希望它在第一個非<a>標籤處停止時,即第一個標籤的處理將所有10個<a>標籤在第一個<a-wrapper>內,當我只想要前四個時。這也有插入嵌套的<a-wrapper>標籤的效果,如第五個標籤生成的標籤,這是DTD所不允許的。

所以問題是,如何選擇以第一個非<a>標籤結尾的以下兄弟的子集?

回答

2

假設,從你比如你要「包」以外的所有部分元素中的第一元素,你可以寫一個模板的部分元素匹配,然後通過選擇子元素的名字開始從最前面的兄弟姐妹不同

<xsl:apply-templates 
    select="*[position() > 1] 
       [local-name() != local-name(preceding-sibling::*[1])]" mode="wrapper" /> 

那麼,這種「包裝」模板中,你可以創建你的包裝元素,然後開始選擇的第一個元素來包裝

<xsl:element name="{local-name()}-wrapper"> 
    <xsl:apply-templates select="self::*" mode="copy"/> 
    </xsl:element> 

而這個「複製」模板中,你會複製元素,然後遞歸地選擇下一個元素,它應該具有相同的名稱

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

以下是完整的XSLT

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

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

    <xsl:template match="/*"> 
     <xsl:copy> 
     <xsl:apply-templates select="*[1]"/> 
     <xsl:apply-templates select="*[position() &gt; 1][local-name() != local-name(preceding-sibling::*[1])]" mode="wrapper"/> 
    </xsl:copy> 
    </xsl:template> 

    <xsl:template match="*" mode="wrapper"> 
     <xsl:element name="{local-name()}-wrapper"> 
     <xsl:apply-templates select="self::*" mode="copy"/> 
     </xsl:element> 
    </xsl:template> 

    <xsl:template match="*" mode="copy"> 
     <xsl:call-template name="identity"/> 
     <xsl:apply-templates select="following-sibling::*[1][local-name() = local-name(current())]" mode="copy"/> 
    </xsl:template> 
</xsl:stylesheet> 

當應用你的XML,下面是輸出

<section> 
    <title>Title</title> 
    <a-wrapper> 
     <a>content1</a> 
     <a>content2</a> 
     <a>content3</a> 
     <a>content4</a> 
    </a-wrapper> 
    <b-wrapper> 
     <b>other content</b> 
    </b-wrapper> 
    <a-wrapper> 
     <a>content5</a> 
     <a>content6</a> 
     <a>content7</a> 
    </a-wrapper> 
    <c-wrapper> 
     <c>other content</c> 
    </c-wrapper> 
    <a-wrapper> 
     <a>content8</a> 
     <a>content9</a> 
     <a>content10</a> 
    </a-wrapper> 
</section> 

注意怎麼沒有在此解決方案的任何特定元素的名稱,其中應該有希望使你更靈活的硬編碼。

編輯:因爲你實際上只想包裝'a'元素,這使得它實際上更簡單。你可以有一個模板來匹配,像這樣

<xsl:template match="a[preceding-sibling::*[1][not(self::a)]]"> 

一組「A」元素的第一次出現,那麼你會複製元素,下面以類似的方式「一」元素之前。

試試這個XSLT而不是

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

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

    <xsl:template match="a[preceding-sibling::*[1][not(self::a)]]"> 
     <a-wrapper> 
      <xsl:apply-templates select="self::a" mode="copy"/> 
     </a-wrapper> 
    </xsl:template> 

    <xsl:template match="a" /> 

    <xsl:template match="a" mode="copy"> 
     <xsl:call-template name="identity"/> 
     <xsl:apply-templates select="following-sibling::*[1][self::a]" mode="copy"/> 
    </xsl:template> 
</xsl:stylesheet> 
0

我很欣賞你代表我的努力。現在輪到我道歉了,因爲問題陳述並不完整。我忽略了注意到我正在將[a]轉換爲其他標籤 - 我們稱之爲[a2]。其他轉換也正在發生,包括[部分]到[部分1]。

與此同時,另一個來源提出了一個適用於我的解決方案。它看起來像這樣,以片段形式:

<xsl:template match="section"> 
    <xsl:element name="sect1"> 
     <xsl:for-each-group select="*" group-adjacent="boolean(self::a)"> 
      <xsl:choose> 
       <xsl:when test="current-grouping-key()"> 
        <xsl:element name="a-wrapper"> 
         <xsl:apply-templates select="current-group()"/> 
        </xsl:element> 
       </xsl:when> 
       <xsl:otherwise> 
        <xsl:apply-templates select="current-group()"/> 
       </xsl:otherwise> 
      </xsl:choose> 
     </xsl:for-each-group> 
    </xsl:element> 
</xsl:template> 
相關問題