2013-03-27 80 views
1

我對XSLT很陌生,我試圖複製一個現有的XML文件,我已經擁有但重新排序的元素,但是當我嘗試重新排列孫子時,我被卡住了。XSLT - 副本孫子們重新排序

比方說,我有這樣的輸入:

<grandParent> 
    <parent> 
     <c>789</c> 
     <b> 
      <b2>123</b2> 
      <b1>456</b1> 
     </b> 
     <a>123</a> 
    </parent> 
    .... 
</grandParent> 

我想要做的就是B = B1,B2中得到相同的XML文件,但改變標籤的順序爲A,B,C該訂單。 於是我開始用XSLT文件:

<xsl:template match="node()|@*"> <- This should copy everything as it is 
    <xsl:copy> 
      <xsl:apply-templates select="node()|@*"/> 
    </xsl:copy> 
</xsl:template> 
<xsl:template match="grandParent/parent"> <- parent elements will copy in this order 
    <xsl:copy> 
     <xsl:copy-of select="@*"/> 
     <xsl:copy-of select="a"/> 
     <xsl:copy-of select="b"/> 
     <xsl:copy-of select="c"/> 
    </xsl:copy> 
</xsl:template> 

但 「XSL:複製的選擇=」 b 「的」 副本,因爲他們指定的元素(B2,B1)。 我試着使用另一個xsl:template作爲「grandParent/parent/b」,但沒有任何幫助。

也許我沒有做正確的方式......任何提示?

謝謝!

的解決方案 - 感謝尼爾斯

您的解決方案工作得很好尼爾斯,我只是定製的多一點,以適應在我目前的情況,其中「B」是可選的,並且標籤的名字可能不相關。 最後的代碼是這樣的:

<xsl:template match="node()|@*"> <- This should copy everything as it is 
    <xsl:copy> 
      <xsl:apply-templates select="node()|@*"/> 
    </xsl:copy> 
</xsl:template> 
<xsl:template match="grandParent/parent"> <- parent elements will copy in this order 
    <xsl:copy> 
     <xsl:copy-of select="@*"/> 
     <xsl:copy-of select="a"/> 
        <xslt:if test="b"> 
         <b> 
         <xsl:copy-of select="b1"/> 
         <xsl:copy-of select="b2"/> 
         </b> 
        </xslt:if> 
     <xsl:copy-of select="b"/> 
     <xsl:copy-of select="c"/> 
    </xsl:copy> 
</xsl:template> 

回答

1

我試圖用另一種XSL:模板 「祖父母/父母/ B」,但不會幫助。

既然你有一個身份模板,你應該使用<xsl:apply-templates>代替<xsl:copy-of>

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

現在你可以添加一個類似模板的b元素

<xsl:template match="parent/b"> 
    <xsl:copy> 
     <xsl:apply-templates select="@*"/> 
     <xsl:apply-templates select="b1"/> 
     <xsl:apply-templates select="b2"/> 
    </xsl:copy> 
</xsl:template> 

這將很好地處理這種情況b不存在 - 如果select="b"沒有找到任何元素,則不會激發模板。

事實上,如果排序順序是在兩種情況下(按字母順序元素名)一樣,那麼您可以將兩個模板合併成一個,它使用<xsl:sort>,給人的

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

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

    <xsl:template match="grandParent/parent | parent/b"> 
    <xsl:copy> 
     <xsl:apply-templates select="@*"/> 
     <xsl:apply-templates select="*"> 
     <xsl:sort select="name()" /> 
     </xsl:apply-templates> 
    </xsl:copy> 
    </xsl:template> 
</xsl:stylesheet> 

一個完整的轉型(爲您提供給您的示例XML實際上並不需要@*位,因爲XML不包含任何屬性,但如果在真實XML中有任何屬性,或者您添加了該屬性,它將不會造成任何傷害任何未來)。

+0

這兩個解決方案的作品。但是我認爲這個更加整潔。謝謝Ian – drewich

+0

Ian,存在一種更通用的解決方案,適用於每個XML文檔 - 不依賴於任何名稱。 –

1

使用xsl:sort

以下代碼不在我的頭頂,可能無法正常工作;但它背後的想法應該清楚。

<xsl:template match="node()|@*"> <- This should copy everything as it is 
    <xsl:copy> 
     <xsl:apply-templates select="node()|@*"/> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="grandParent/parent"> <- parent elements will copy in this order 
    <xsl:copy> 
    <xsl:copy-of select="@*"/> 
    <xsl:copy-of select="a"/> 
    <b> 
     <xsl:for-each select="b/*"> 
      <xsl:sort select="text()" /> 
      <xsl:copy-of select="." /> 
     </xsl:for-each> 
    </b> 
    <xsl:copy-of select="c"/> 
    </xsl:copy> 
</xsl:template> 
+0

正如editi中所述對我原來的問題,你的答案也適用。但在我看來,伊恩的解決方案更加整潔。無論如何,謝謝! – drewich

1

這裏是一個最通用的解決方案 - 使用xsl:sort和模板 - 沒有xsl:copy-of並沒有具體的名字的硬編碼:

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

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

當這種變換所提供的XML文檔應用:

<grandParent> 
    <parent> 
     <c>789</c> 
     <b> 
      <b2>123</b2> 
      <b1>456</b1> 
     </b> 
     <a>123</a> 
    </parent> 
    .... 
</grandParent> 

想要的,正確的結果產生

<grandParent> 
    <parent> 
     <a>123</a> 
     <b> 
     <b1>456</b1> 
     <b2>123</b2> 
     </b> 
     <c>789</c> 
    </parent> 
    .... 
</grandParent> 

現在,讓我們改變XML文檔中的所有名稱 - 請注意,沒有任何其他的答案可與此

<someGrandParent> 
    <someParent> 
     <z>789</z> 
     <y> 
      <y2>123</y2> 
      <y1>456</y1> 
     </y> 
     <x>123</x> 
    </someParent> 
    .... 
</someGrandParent> 

我們應用相同改造和它再次產生正確的結果:

<someGrandParent> 
    <someParent> 
     <x>123</x> 
     <y> 
     <y1>456</y1> 
     <y2>123</y2> 
     </y> 
     <z>789</z> 
    </someParent> 
    .... 
</someGrandParent> 
+0

嗨迪米特雷,首先謝謝你的回答。當然你的解決方案適用於這種情況。但是,如果我沒有弄錯,只有名稱相關時纔有效。我把這些名字的例子放在了縮寫中。但在我的現實生活中,解決方案無法正常工作。 – drewich

+0

@drewich,你沒有理解這個解決方案。它沒有做任何假設! 「相關」名稱是什麼意思??????? –

+0

對不起,遲到的迴應。那麼,我可能不瞭解解決方案。根據我的理解,「」會按照名稱的字母順序對標籤進行排序,對嗎? 我是XSLT的新手,所以有可能我不理解它。 – drewich