2012-08-24 21 views
1

我在這裏看到過這個問題的一些變化,但我不確定如何將它們應用於我的情況,所以我希望也許有人能幫助我。使用屬性作爲關鍵字深化XSLT結構

我有一個格式與此類似一個扁平的XML文件:

<item id="1"/> 
<item id="1.1"/> 
<item id="1.1.1"/> 
<item id="1.1.2"/> 
<item id="1.1.2.1"/> 
<item id="1.2"/> 
<item id="1.3"/> 

我期待分層設置標籤基於id屬性,就像這樣:

<item id="1"> 
    <item id="1.1"> 
    <item id="1.1.1"/> 
    <item id="1.1.2"> 
     <item id="1.1.2.1"/> 
    </item> 
    </item> 
    <item id="1.2"/> 
    <item id="1.3"/> 
</item> 

某些id值有兩位數字(例如「1.2.3.15.1」),這使得比較它們更具挑戰性。

幫助?

+0

你叫什麼終止條件。你需要做的是,有一個函數,遞歸地調用它自己的值,如1,1.1,1.2,1.3 .. 1.nnn然後,爲他們每個人再次調用1.1.1,1.1.2等。每個系列必須在您的預定義條件下結束。 –

+0

優化可以首先收集所有屬性,按照您需要的順序排列它們,然後只調用那些屬性,因此您的終止不會被硬編碼。 –

回答

3

選擇正確的節點可能會非常棘手,但你有沒有等級這個工程爲您的樣品輸入(如果你添加一個根元素的話)

<!-- start somewhere --> 
    <xsl:template match="/root"> 
    <root> 
     <!-- select all with no . in the id --> 
     <xsl:apply-templates select="//item[string-length(translate(@id,'1234567890',''))=0]" /> 
    </root> 
    </xsl:template> 

    <xsl:template match="item"> 
    <xsl:variable name="id" select="@id"/> 
    <!-- how many . have we ? That is how deep we are and add 1 --> 
    <xsl:variable name="deep" select="string-length(translate(@id,'1234567890',''))+1" /> 
    <xsl:copy> 
     <!-- copy attribs over --> 
     <xsl:apply-templates select="@*"/> 
     <!-- select all nodes that start with our curent id, 
      select nodes that are just one level below us 
      and don't select our selfs--> 
     <xsl:apply-templates select="//item[starts-with(@id, $id) and string-length(translate(@id,'1234567890',''))=$deep and not(@id=$id)]"/> 
    </xsl:copy> 
    </xsl:template> 

    <!-- copy attribs --> 
    <xsl:template match="@*"> 
    <xsl:copy /> 
    </xsl:template> 
+0

謝謝。儘管有一個方面我必須糾正,但這一個做了訣竅。輸入文件有一些帶兩位數字的ID(例如1.2.3.11),導致節點選擇失敗。我通過將ID格式化爲兩位數字(例如01.02.03.11)作爲第一遍轉換來解決此問題。 – NestorDRod

1

一,這是一個簡單的XSLT 2.0解決方案(這一個後和類似的XSLT 1.0溶液如下):

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:my="my:my"> 
    <xsl:output omit-xml-declaration="yes" indent="yes"/> 

<xsl:template match="/*"> 
    <xsl:sequence select="my:grouping(*, 1)"/> 
</xsl:template> 

<xsl:function name="my:grouping" as="element()*"> 
    <xsl:param name="pNodes" as="element()*"/> 
    <xsl:param name="pLevel" as="xs:integer"/> 

    <xsl:if test="$pNodes"> 
     <xsl:for-each-group select="$pNodes" group-by="tokenize(@id, '\.')[$pLevel]"> 
     <xsl:copy> 
     <xsl:copy-of select="@*"/> 
     <xsl:sequence select=" 
      my:grouping(current-group()[tokenize(@id, '\.')[$pLevel+1]], $pLevel+1)"/> 
     </xsl:copy> 
    </xsl:for-each-group> 
    </xsl:if> 
</xsl:function> 
</xsl:stylesheet> 

當該變換被此XML文檔(提供的XML片段,裹機智上施加欣單個頂部元件,使之成爲良好的XML文檔):

<t> 
    <item id="1"/> 
    <item id="1.1"/> 
    <item id="1.1.1"/> 
    <item id="1.1.2"/> 
    <item id="1.1.2.1"/> 
    <item id="1.2"/> 
    <item id="1.3"/> 
</t> 

有用,正確的結果產生

<item id="1"> 
    <item id="1.1"> 
     <item id="1.1.1"/> 
     <item id="1.1.2"> 
     <item id="1.1.2.1"/> 
     </item> 
    </item> 
    <item id="1.2"/> 
    <item id="1.3"/> 
</item> 

II。下面是一個類似的XSLT 1.0解決方案

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 
<xsl:strip-space elements="*"/> 

<xsl:key name="kFollowing" match="item" 
    use="generate-id(preceding-sibling::* 
        [string-length(current()/@id) > string-length(@id) 
        and 
         starts-with(current()/@id, concat(@id, '.'))] 
         [1])"/> 

<xsl:template match="/*"> 
    <xsl:call-template name="grouping"> 
     <xsl:with-param name="pNodes" select="*"/> 
     <xsl:with-param name="pLevel" select="1"/> 
    </xsl:call-template> 
</xsl:template> 

<xsl:template name="grouping"> 
    <xsl:param name="pNodes"/> 
    <xsl:param name="pLevel" select="1"/> 

    <xsl:for-each select= 
    "$pNodes[$pLevel > string-length(@id) - string-length(translate(@id, '.', ''))]"> 
    <xsl:copy> 
    <xsl:copy-of select="@*"/> 

    <xsl:call-template name="grouping"> 
     <xsl:with-param name="pNodes" select="key('kFollowing', generate-id())"/> 
     <xsl:with-param name="pLevel" select="$pLevel+1"/> 
    </xsl:call-template> 
    </xsl:copy> 
    </xsl:for-each> 
</xsl:template> 
</xsl:stylesheet> 

當這個XSLT 1.0變換對同一文檔(上圖),同樣的希望,正確的結果產生應用:

<item id="1"> 
    <item id="1.1"> 
     <item id="1.1.1"/> 
     <item id="1.1.2"> 
     <item id="1.1.2.1"/> 
     </item> 
    </item> 
    <item id="1.2"/> 
    <item id="1.3"/> 
</item> 
相關問題