2012-07-05 99 views
2

保留空格我想這個XML轉換: -從XSL樣式表

<list> 
    <unit> 
    <data1>a</data1> 
    <data2>b</data2> 
    <data3>c</data3> 
    </unit> 
</list> 

這樣: -

<list> 
    <unit> 
    <category1> 
     <data1>a</data1> 
     <data2>b</data2> 
    </category1> 
    <category2> 
     <data3>c</data3> 
    </category2> 
    </unit> 
</list> 

使用XSL。我正在使用以下XSL: -

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:s="some_namespace"> 


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

<xsl:template match="//s:unit" xml:space="preserve"> 
    <xsl:copy> 
    <category1> 
    <xsl:apply-templates select="./s:data1"/> 
    <xsl:apply-templates select="./s:data2"/> 
    </category1> 
    <category2> 
    <xsl:apply-templates select="./s:data3"/> 
    </category2> 
    </xsl:copy> 
</xsl:template> 

</xsl:stylesheet> 

現在,這將保留內部的縮進但將其完全混淆w.r.t.名單。這是我得到: -

<list> 
<unit> 
    <category1> 
    <data1>a</data1> 
    <data2>b</data2> 
    </category1> 
    <category2> 
    <data3>c</data3> 
    </category2> 
</unit> 
    </list> 

我在這裏錯過什麼?

+0

你在找什麼?縮進? – 2012-07-05 18:42:57

+0

是的。在輸出xml中縮進。 – owagh 2012-07-05 19:02:09

+5

這是依賴於實現的。大多數處理器在使用'時一起或不使用'時產生良好的縮進。你在使用哪種XSLT處理器? – 2012-07-05 19:04:40

回答

5

我在這裏錯過了什麼?

我認爲一個人不應該搞亂XSLT處理器的默認縮進。

大多數情況下,<xsl:output indent="yes"/><xsl:strip-space elements="*"/>的組合足以獲得良好的縮進。

這種轉變

<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="unit"> 
    <unit> 
     <category1> 
     <xsl:apply-templates select="*[not(position() >2)]"/> 
     </category1> 
     <category2> 
     <xsl:apply-templates select="*[position() >2]"/> 
     </category2> 
    </unit> 
</xsl:template> 
</xsl:stylesheet> 

時所提供的XML文檔應用:

<list> 
     <unit> 
     <data1>a</data1> 
     <data2>b</data2> 
     <data3>c</data3> 
     </unit> 
</list> 

可生產通緝,以及縮進結果

<list> 
    <unit> 
    <category1> 
     <data1>a</data1> 
     <data2>b</data2> 
    </category1> 
    <category2> 
     <data3>c</data3> 
    </category2> 
    </unit> 
</list> 

當變換運行具有任何以下七個XSLT處理器的這種相同的結果將產生:

  • AltovaXML(XML-SPY)。

  • .NET XslCompiledTransform。

  • .NET XslTransform。

  • 撒克遜6.5.4。

  • 撒克遜9.1.05(XSLT 2.0處理器)。

  • XQSharp/XMLPrime(XSLT 2.0處理器)。

  • AltovaXml(用於XSLT 2.0)。

與MSXML3/4/6是更復雜的案例 - 這些XSLT處理器的壓痕由只是一個新行字符的,所以每一個元件是在一個新行,但出現在開始的線。

對於我使用以下兩個通處理這些XSLT處理器,第一遍是上述變換和所述第二應用到所述第一通過的結果one of the XML pretty-printers提出尼古萊·格里戈裏夫和可用在XSLT FAQ站點通過Dave Pawson維持:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:ext="urn:schemas-microsoft-com:xslt" 
exclude-result-prefixes="ext"> 
<xsl:output method="xml"/> 
<xsl:strip-space elements="*"/> 

<xsl:param name="indent-increment" select="' '" /> 

<xsl:variable name="vrtfPass1"> 
    <xsl:apply-templates select="/*"/> 
</xsl:variable> 

<xsl:variable name="vPass1" select="ext:node-set($vrtfPass1)"/> 

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

<xsl:template match="/"> 
    <xsl:apply-templates select="$vPass1/*" mode="pass2"/> 
</xsl:template> 


<xsl:template match="unit"> 
    <unit> 
     <category1> 
     <xsl:apply-templates select="*[not(position() >2)]"/> 
     </category1> 
     <category2> 
     <xsl:apply-templates select="*[position() >2]"/> 
     </category2> 
    </unit> 
</xsl:template> 

    <xsl:template match="*" mode="pass2"> 
    <xsl:param name="indent" select="'&#xA;'"/> 

    <xsl:value-of select="$indent"/> 
    <xsl:copy> 
     <xsl:copy-of select="@*" /> 
     <xsl:apply-templates mode="pass2"> 
     <xsl:with-param name="indent" 
       select="concat($indent, $indent-increment)"/> 
     </xsl:apply-templates> 
     <xsl:value-of select="$indent"/> 
    </xsl:copy> 
    </xsl:template> 

    <xsl:template match="comment()|processing-instruction()" mode="pass2"> 
    <xsl:copy /> 
    </xsl:template> 

    <!-- WARNING: this is dangerous. Handle with care --> 
    <xsl:template match="text()[normalize-space(.)='']" mode="pass2"/> 

</xsl:stylesheet> 

當在相同的(提供的)XML文檔(上文)中進行這種轉化,所產生的結果具有所期望的縮進

<?xml version="1.0" encoding="UTF-16"?> 
<list> 
    <unit> 
     <category1> 
     <data1>a 
     </data1> 
     <data2>b 
     </data2> 
     </category1> 
     <category2> 
     <data3>c 
     </data3> 
     </category2> 
    </unit> 
</list> 

這些都是我在我的電腦上使用的XSLT處理器。我建議嘗試最後一次轉化 - 有可能會用Xalan-C產生想要的結果。

請注意

最後轉換使用的MSXML - 特定的擴展功能XXX:節點集(),屬於一個MSXML - 特定的命名空間:

xmlns:ext="urn:schemas-microsoft-com:xslt" 

對於Xalan的這需要與被替換:

xmlns:ext="http://exslt.org/common" 

或者,如果不支持EXSLT,那麼本地的Xalan命名空間

xmlns:ext="http://xml.apache.org/xalan 

在最後這種情況下,到ext:node-set()函數調用必須以ext:nodeset()調用(注意沒有破折號)來代替:

<xsl:variable name="vPass1" select="ext:nodeset($vrtfPass1)"/> 
+2

+1爲一個很好的綜合答案。 – owagh 2012-07-13 15:17:27

+0

@owagh:不客氣。 – 2012-07-13 15:50:50