2012-03-25 67 views
1

UPDATE(擾流板):這個問題的答案(見下文大衛·卡萊爾的answere),它看起來像在XSLT實現中的錯誤包括在一些版本的JRE(就像它在JDK但不要在JRE工作1.6.0_20- b02,根本不工作在1.6.0_31-b05)。我在Oracle網站上記錄了一個錯誤。如何將所有子節點原樣複製到結果樹?

我幾乎在那裏,現在它的功能方面。但我對它的某些部分不滿意,其中一些(我相信)可能會更短。這是問題...詳細請參考

這是輸入XML的例子

<?xml version="1.0" encoding="UTF-8"?> 
<t1> 
    <t2 a1="v1"> 
     <ot1 a2="v2" /> 
     <ot2 a3="v3"> 
      <t3 a5="v4"> 
       <ot1 a2="v5" /> 
      </t3> 
     </ot2> 
    </t2> 
</t1> 

這是預期的結果XML的例子(見下面的XSLT文件,以獲取有關線索什麼,什麼)

<?xml version="1.0" encoding="UTF-8"?> 
<t1> 
    <t2 a1="v1"> 
     <gt2 a="ot2" b="gtv1"> 
      <gt1 a="ot1">v2</gt1> 
     </gt2> 
     <gt2 a="ot2" b="v3"> 
      <t3 a5="v4"> 
       <gt2 a="ot2" b="gtv1"> 
        <gt1 a="ot1">v5</gt1> 
       </gt2> 
      </t3> 
     </gt2> 
    </t2> 
</t1> 

這是XSLT我最後用(但不要太高興)結束。

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:exslt="http://exslt.org/common" version="1.0" 
    exclude-result-prefixes="exslt"> 
    <xsl:output method="xml" /> 

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

    <xsl:template match="ot1|ot2"> 
     <xsl:variable name="thisResult"> 
      <xsl:apply-templates select="." mode="impl" /> 
     </xsl:variable> 
     <xsl:apply-templates select="exslt:node-set($thisResult)" /> 
    </xsl:template> 

    <xsl:template match="ot1" mode="impl"> 
     <ot2 a3="gtv1"> 
      <gt1 a="ot1"> 
       <xsl:value-of select="@a2" /> 
      </gt1> 
     </ot2> 
    </xsl:template> 

    <xsl:template match="ot2" mode="impl"> 
     <gt2 a="ot2" b="{@a3}"> 
      <xsl:for-each select="child::*"> 
       <xsl:element name="{name()}"> 
        <xsl:copy-of select="@*|node()" /> 
       </xsl:element> 
      </xsl:for-each> 
     </gt2> 
    </xsl:template> 
</xsl:stylesheet> 

問題是:如何讓這個短?

<xsl:for-each select="child::*"> 
    <xsl:element name="{name()}"> 
     <xsl:copy-of select="@*|node()" /> 
    </xsl:element> 
</xsl:for-each> 

我嘗試下面的事情,但在生成的XML的這種情況下,部分將會丟失

<xsl:copy-of select="node()"/> 

還試圖

<xsl:copy-of select="*"/> 
(特別爲GT2元件將會丟失屬性)

沒有成功

回答

2

Dimitre已經展示了一個ternative戰略,而是要回答這個問題在你原來的帖子,在xsl:對,每個是(除了一些命名空間的效果不顯示在這裏),相當於一個

<xsl:copy-of select="*"/> 

,我也得到相同的輸出,如果用它替換xsl:for-each。

你的建議的替換

<xsl:copy-of select="node()"/> 

幾乎是相同的,但拿起用於縮進源的空白節點,因此輸出在白空間不同。

你說

(具體屬性爲GT3元件將丟失)

但編碼變化不會改變的屬性,並且在該示例的輸入或輸出不gt3元件?

+0

是的,這是一個錯字,只是修正它(它應該是GT2),並澄清了例子,所以多遍處理將有意義。此外,我嘗試了你的建議,但這對我不起作用。您使用的是哪種XSLT處理器? – 2012-03-25 19:12:28

+0

我使用saxon 6.5進行xslt1測試(否則我會用saxon 9)如果我運行你的樣式表我得到與你相同的結果吧條空格,如果我通過拷貝select =「*」替換for-each獲取與原始樣式表相同的(使用差異確認)輸出。 – 2012-03-25 19:36:14

+0

我正在使用標準JRE內置XSL轉換引擎。看起來我打了一個錯誤。 – 2012-03-25 22:15:56

3

我需要定義xslt變換,它能夠執行所謂的「多遍變換」 。

這裏不需要使用多通道處理

這種短期和簡單的變換:

<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="ot1"> 
    <gt1 a="ot1"><xsl:value-of select="@a2"/></gt1> 
    <xsl:apply-templates/> 
</xsl:template> 

<xsl:template match="ot2"> 
    <gt2 a="ot2" b="{@a3}"/> 
    <xsl:apply-templates/> 
</xsl:template> 
</xsl:stylesheet> 

時所提供的XML文檔應用:

<t1> 
    <t2 a1="v1"> 
     <ot1 a2="v2" /> 
     <ot2 a3="v3"> 
      <t3 a5="v4"> 
       <ot1 a2="v5" /> 
      </t3> 
     </ot2> 
    </t2> 
</t1> 

產生想要的,正確的結果

<t1> 
    <t2 a1="v1"> 
     <gt1 a="ot1">v2</gt1> 
     <gt2 a="ot2" b="v3"/> 
     <t3 a5="v4"> 
     <gt1 a="ot1">v5</gt1> 
     </t3> 
    </t2> 
</t1> 

UPDATE:OP已經更新了他認爲需要多次處理的問題 - 這仍然不是真實的。

下面是一個簡短和簡單的解決方案的新的問題,再一次在單程

<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="ot1"> 
    <gt2 a="ot2" b="gtv{substring-after(name(), 'ot')}"> 
    <gt1 a="ot1"><xsl:value-of select="@a2"/></gt1> 
    </gt2> 
    <xsl:apply-templates/> 
</xsl:template> 

<xsl:template match="ot2"> 
    <gt2 a="ot2" b="{@a3}"/> 
    <xsl:apply-templates/> 
</xsl:template> 
</xsl:stylesheet> 

當該變換被應用到新提供的XML源文檔:

<t1> 
    <t2 a1="v1"> 
     <ot1 a2="v2" /> 
     <ot2 a3="v3"> 
      <t3 a5="v4"> 
       <ot1 a2="v5" /> 
      </t3> 
     </ot2> 
    </t2> 
</t1> 

再次通緝,正確的結果產生

<t1> 
    <t2 a1="v1"> 
     <gt2 a="ot2" b="gtv1"> 
     <gt1 a="ot1">v2</gt1> 
     </gt2> 
     <gt2 a="ot2" b="v3"/> 
     <t3 a5="v4"> 
     <gt2 a="ot2" b="gtv1"> 
      <gt1 a="ot1">v5</gt1> 
     </gt2> 
     </t3> 
    </t2> 
</t1> 

UPDATE2:由於OP是詢問他目前的代碼重構,特別需要更好地表達此摘錄:

<xsl:for-each select="child::*"> 
    <xsl:element name="{name()}"> 
     <xsl:copy-of select="@*|node()" /> 
    </xsl:element> 
</xsl:for-each> 

這裏就是一個明顯的refactorung - 用代替上述:

<xsl:apply-templates/> 

此修改後的完整代碼變爲

<t1> 
    <t2 a1="v1"> 
     <ot1 a2="v2" /> 
     <ot2 a3="v3"> 
      <t3 a5="v4"> 
       <ot1 a2="v5" /> 
      </t3> 
     </ot2> 
    </t2> 
</t1> 

有用結果產生

<t1> 
    <t2 a1="v1"> 
     <gt2 a="ot2" b="gtv1"> 
     <gt1 a="ot1">v2</gt1> 
     </gt2> 
     <gt2 a="ot2" b="v3"> 
     <t3 a5="v4"> 
      <gt2 a="ot2" b="gtv1"> 
       <gt1 a="ot1">v5</gt1> 
      </gt2> 
     </t3> 
     </gt2> 
    </t2> 
</t1> 

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
     xmlns:exslt="http://exslt.org/common" version="1.0" 
     exclude-result-prefixes="exslt"> 
     <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="ot1|ot2"> 
      <xsl:variable name="thisResult"> 
       <xsl:apply-templates select="." mode="impl" /> 
      </xsl:variable> 
      <xsl:apply-templates select= 
      "exslt:node-set($thisResult)" /> 
     </xsl:template> 

     <xsl:template match="ot1" mode="impl"> 
      <ot2 a3="gtv1"> 
       <gt1 a="ot1"> 
        <xsl:value-of select="@a2" /> 
       </gt1> 
      </ot2> 
     </xsl:template> 

     <xsl:template match="ot2" mode="impl"> 
      <gt2 a="ot2" b="{@a3}"> 
       <xsl:apply-templates/> 
      </gt2> 
     </xsl:template> 
</xsl:stylesheet> 

和當最新提供源XML文檔施加

+0

Dimitre,謝謝你的嘗試!但不要誤解我的意思,「我需要多次處理」不是問題,我真的需要它。我編輯了這個問題以使這個更清潔。 – 2012-03-25 19:08:34

+0

@Tornn:你認爲爲了解決更新後的問題,多通道處理**是必須的?其實,這是沒有必要的。請在我的答案結尾處看到更新 - 再次,一個相當簡單的單遍轉換解決了這個問題。 – 2012-03-25 20:31:14

+0

看起來像你在回答問題「我需要多次處理?」。但這不是我的問題。我想我會編輯它以避免混淆。 – 2012-03-25 21:10:39

相關問題