2016-01-16 80 views
1

我有以下flat xml結構。XSLT 1.0根據父子關係構建層次結構

<customUI > 
    <elements> 
    <tab id="1" parent="0"/> 
    <tab id="-1" parent="0"/> 
    <group id="-2" parent="-1"/> 
    <group id="2" parent="1"/> 
    <group id="11" parent="1"/> 
    <menu id="-27" parent="-26"/> 
    <menu id="-24" parent="-4"/> 
    <menu id="-18" parent="-4"/> 
    <menu id="-11" parent="-9"/> 
    <menu id="-10" parent="-9"/> 
    <menu id="-3" parent="-2"/> 
    <menu id="3" parent="2"/> 
    <menu id="10" parent="65"/> 
    <menu id="12" parent="11"/> 
    <menu id="16" parent="11"/> 
    <menu id="18" parent="11"/> 
    <menu id="25" parent="11" /> 
    <menu id="29" parent="11"/> 
    <menu id="46" parent="11"/> 
    <menu id="74" parent="-3"/> 
    <menu id="85" parent="11"/> 
    <menu id="89" parent="2"/> 
    <menu id="95" parent="2"/> 
    <menu id="104" parent="2"/> 
    <button id="-28" parent="-2"/> 
    <button id="-25" parent="-24"/> 
    <button id="-12" parent="-11"/> 
    <button id="32" parent="29"/> 
    <button id="26" parent="25"/> 
    <button id="41" parent="18"/> 
    <button id="66" parent="46"/> 
    <button id="82" parent="74"/> 
    <button id="86" parent="46"/> 
    <button id="87" parent="89"/> 
    <button id="90" parent="89"/> 
    <button id="99" parent="89"/> 
    <button id="58" parent="16"/> 
    <button id="42" parent="18"/> 
    <button id="47" parent="46"/> 
    <button id="48" parent="46"/> 
    <button id="33" parent="29"/> 
    <!-- The list continues --> 
    </elements> 
</customUI> 

我想要做的是使用'id'值和'parent'值之間的關係構建一個層次結構。

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

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

<xsl:template match="tab"> 
    <xsl:variable name="controllerId" select="@id" as="xs:string"/> 
    <xsl:copy> 
     <xsl:apply-templates select="@*|node()"/> 
     <xsl:copy-of select="//*[@parent = $controllerId]"/> 
    </xsl:copy> 
</xsl:template> 


<xsl:template match="group" name="group"> 
    <xsl:variable name="controllerId" select="@id" as="xs:string"/> 
    <xsl:copy> 
     <xsl:apply-templates select="@*|node()"/> 
     <xsl:copy-of select="//*[@parent = $controllerId]"/> 
    </xsl:copy> 
</xsl:template> 


<xsl:template match="menu" name="menu"> 
    <xsl:variable name="controllerId" select="@id" as="xs:string"/> 
    <xsl:copy> 
     <xsl:apply-templates select="@*|node()"/> 
     <xsl:copy-of select="//*[@parent = $controllerId]"/> 
    </xsl:copy> 
</xsl:template> 

</xsl:stylesheet> 

這是我到現在爲止所嘗試的,但它不起作用。

任何幫助將不勝感激。

+0

你能告訴你在這種情況下,期待輸出?謝謝! –

回答

1

這是一個有點粗糙,但它應該工作:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <!-- Identity template --> 
    <xsl:template match="@* | node()"> 
    <xsl:copy> 
     <xsl:apply-templates select="@* | node()"/> 
    </xsl:copy> 
    </xsl:template> 

    <xsl:template match="elements"> 
    <xsl:copy> 
     <xsl:for-each select="*"> 
     <xsl:if test="not(../*[@id=current()/@parent])"> 
      <xsl:apply-templates select="."/> 
     </xsl:if> 
     </xsl:for-each> 
    </xsl:copy> 
    </xsl:template> 

    <xsl:template match="elements/*"> 
    <xsl:copy> 
     <xsl:apply-templates select="@* | node()"/> 
     <xsl:apply-templates select="../*[@parent = current()/@id]"/> 
    </xsl:copy> 
    </xsl:template> 
</xsl:stylesheet> 

elements模板拷貝它,但在它的每個元素,它只有在沒有其他兄弟姐妹誰的父母申請模板是這個;即如果您的數據表示完整的層次結構,它可能只是根。

第二個模板適用於元素模板中的任何內容,並按照原樣複製,然後還包括任何其他父元素是當前元素的元素,遞歸地。

使用按鍵的替代方案,可能會更快,但將有問題,如果有一個以上的elements元素:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:key name="elemsById" match="elements/*" use="@id"/> 
    <xsl:key name="elemsByParent" match="elements/*" use="@parent"/> 

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

    <xsl:template match="elements"> 
    <xsl:copy> 
     <xsl:apply-templates select="*[not(key('elemsById',@parent))]"/> 
    </xsl:copy> 
    </xsl:template> 

    <xsl:template match="elements/*"> 
    <xsl:copy> 
     <xsl:apply-templates select="@* | node()"/> 
     <xsl:apply-templates select="key('elemsByParent',@id)"/> 
    </xsl:copy> 
    </xsl:template> 
</xsl:stylesheet> 
+0

我說不出話來......如何能夠如此快速地提供解決方案,甚至是可能的......而且最令人驚訝的是它似乎很有效。 – Andy

+0

幸運地說實話。我最近做了一些非常相似的事情,並沒有太大的不同。 – Flynn1179

+0

順便說一句,因爲我是初學者,請你向我推薦一些來源,從那裏我可以更有條理地學習XSLT,因爲現在我處於更多的試驗和錯誤階段,這不幸的是很耗時。 – Andy