2013-07-31 28 views
1

我有一個XML文檔,像這樣:XSLT來包裝所有CHID元素的父標記

<Catalogs> 
    <Catalog> 
     <Code>x</Code> 
     <Name>Ox</Name> 
     <Categories> 
      <Category> 
       <Id>9245</Id> 
       <Name>a</Name> 
       <Category> 
        <Id>9247</Id> 
        <Name>x</Name> 
       </Category> 
      </Category> 
      <Category> 
       <Id>9250</Id> 
       <Name>x</Name> 
       <Category> 
        <Id>9252</Id> 
        <Name>x</Name> 
       </Category> 
       <Category> 
        <Id>9258</Id> 
        <Name>x</Name> 
        <Category> 
         <Id>9260</Id> 
         <Name>x</Name> 
        </Category> 
        <Category> 
         <Id>9261</Id> 
         <Name>x</Name> 
        </Category> 
        <Category> 
         <Id>9261</Id> 
         <Name>x</Name> 
        </Category> 
       </Category> 
      </Category> 
      <Category> 
       <Id>9251</Id> 
       <Name>x</Name> 
       <Category> 
        <Id>9253</Id> 
        <Name>x</Name> 
       </Category> 
      </Category> 
     </Categories> 
    </Catalog> 
</Catalogs> 

我想類別標籤的每個子集包裝成一個集合標籤(類別)。 這裏的問題是,這是一個遞歸樹,並且樹的深度未知。

我嘗試過爲此使用xslt轉換,但尚未成功。我的嘗試

<?xml version="1.0" encoding="ISO-8859-1"?> 
<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 

<xsl:template match="Category"> 
    <Categories><xsl:apply-templates select="Category"/></Categories> 
</xsl:template> 

</xsl:stylesheet> 

只是用一個空的類別標記替換所有的孩子。

樣本輸出應該是這樣的:

<Catalogs> 
    <Catalog> 
     <Code>x</Code> 
     <Name>Ox</Name> 
     <Categories> 
      <Category> 
       <Id>9245</Id> 
       <Name>a</Name> 
       <Categories> 
        <Category> 
         <Id>9247</Id> 
         <Name>x</Name> 
        </Category> 
       </Categories> 
      </Category> 
      <Category> 
       <Id>9250</Id> 
       <Name>x</Name> 
       <Categories> 
        <Category> 
         <Id>9252</Id> 
         <Name>x</Name> 
        </Category> 
        <Category> 
         <Id>9258</Id> 
         <Name>x</Name> 
         <Categories> 
          <Category> 
           <Id>9260</Id> 
           <Name>x</Name> 
          </Category> 
          <Category> 
           <Id>9261</Id> 
           <Name>x</Name> 
          </Category> 
          <Category> 
           <Id>9261</Id> 
           <Name>x</Name> 
          </Category> 
         </Categories> 
        </Category> 
       </Categories> 
      </Category> 
      <Category> 
       <Id>9251</Id> 
       <Name>x</Name> 
       <Categories> 
        <Category> 
         <Id>9253</Id> 
         <Name>x</Name> 
        </Category> 
       </Categories> 
      </Category> 
     </Categories> 
    </Catalog> 
</Catalogs> 

任何指針(或完整解決方案),將不勝感激。

回答

4

首先,你應該建立在XSLT身份模板的頂部,這將複製所有節點在XML的XSLT,而您沒有明確的匹配模板

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

沒有這一點, XSLT的內置模板將會啓動,並輸出它找到的任何元素的文本。

的另一個問題你XSLT,就是當你匹配類別元素,你正在做的<xsl:apply-templates select="Category"/>這意味着你只告訴XSLT尋找任何類別元素是當前元素的孩子。你可以採取

一種方法是讓你的模板匹配任何類別元素的父(不含分類元素的話)

<xsl:template match="*[not(self::Categories)][Category]"> 

然後,在此,您可以複製的元素,並插入分類元素中它包含所有類別元素

<xsl:copy> 
    <xsl:apply-templates select="@*|node()[not(self::Category)]"/> 
    <Categories> 
    <xsl:apply-templates select="Category"/> 
    </Categories> 
</xsl: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="*[not(self::Categories)][Category]"> 
    <xsl:copy> 
     <xsl:apply-templates select="@*|node()[not(self::Category)]"/> 
     <Categories> 
     <xsl:apply-templates select="Category"/> 
     </Categories> 
    </xsl:copy> 
    </xsl:template> 

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

這種方法的缺點是,雖然如果父母中的類別後出現的任何元素,這些都將是分類前移到元素被創建。

另一種方法是匹配其父項內的類別元素第一次出現,然後複製該元素及其以下所有的兄弟姐妹

試試這個XSLT太

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

    <xsl:template match="Category[1]"> 
    <Categories> 
     <xsl:apply-templates select="self::*|following-sibling::Category" mode="categories"/> 
    </Categories> 
    </xsl:template> 

    <xsl:template match="Category" mode="categories"> 
    <xsl:call-template name="identity" /> 
    </xsl:template> 

    <xsl:template match="Category" /> 

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

兩件事情來注意這種方法。首先,在尋找匹配節點的模板時,XSLT將始終優先考慮更具體的模板匹配。因此,「類別[1]」將被用於第一個孩子類別元素的「類別」。

其次,注意在這裏使用模式,否則你會有兩個模板匹配具有相同優先級的「類別」,這是不允許的。

+0

感謝不僅2(!)工作解決方案,但也有一些額外的解釋。似乎我需要更多地瞭解xslt –

相關問題