2011-05-06 90 views
22

我需要使用XSL從XML生成簡單的純文本輸出。由於我沒有在網上找到任何好的,簡明的例子,我決定在這裏發佈我的解決方案。任何涉及到一個更好的例子鏈接當然會意識到:這有助於我在這裏使用xsl輸出純文本

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" > 
    <xsl:output method="text" omit-xml-declaration="yes" indent="no"/> 
    <xsl:template match="/"> 
     <xsl:for-each select="script/command" xml:space="preserve">at -f <xsl:value-of select="username"/> <xsl:value-of select="startTime/@hours"/>:<xsl:value-of select="startTime/@minutes"/> <xsl:value-of select="startDate"/><xsl:text> 
</xsl:text></xsl:for-each> 
    </xsl:template> 
</xsl:stylesheet> 

一些重要的事情:

  1. 使用的xsl:輸出省略標準的聲明開頭的輸出文件
  2. 使用xml:space =「preserve」屬性來保留我在xsl:for-each標記內寫入的任何空格。這也要求我在for-each標籤中寫入所有的代碼,包括標籤以及單行(除了換行符)。
  3. 使用插入換行符 - 再次我不得不在這裏省略標準xml縮進。

所得並且爲此XSLT期望的輸出是:

在-f ALLUSER 23時58 2010年4月17日
在-f ggroup67 19:58 2010年4月28日
在-f ggroup70 15: 58 2010年4月18日
在-f ALLUSER 23:58 2010年4月18日
在-f ggroup61 7:58 2010年9月22日
在-f ggroup60 23:58 2010年9月21日
在-f ALLUSER 3:58 22.9 .2010

正如我所說,任何建議如何更優雅地做到這一點,將不勝感激。


的後續2011-05-08:

這裏是XML的,我治療類型:

<script xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="script.xsd"> 
    <command> 
     <username>alluser</username> 
     <startTime minutes="58" hours="23"/> 
     <startDate>17.4.2010</startDate> 
    </command> 
</script> 
+1

您可以使用'concat('at -f',username,'',startTime/@ hours,'',...)'節省''元素的數量。此外,你可以打包你的源代碼 - 如果你在代碼中這樣做,它不會影響輸出。 – 2011-05-06 08:50:44

+0

好問題,+1。看到我的答案是一個完整的,非常簡短的,真正通用的解決方案 – 2011-05-06 13:25:12

+0

@Christopher Creutzig:感謝concat()的精彩建議。你指的是「包裝你的源代碼」? – Chris 2011-05-08 16:30:47

回答

21
  • 可以定義模板匹配script/command和消除xsl:for-each
  • concat()可以用來縮短表達式並且避免明確地插入太多的數字<xsl:text><xsl:value-of>元素。
  • 使用實體引用&#xA;來回車,而不是依靠保留您的<xsl:text>元素之間的換行符更安全一些,因爲代碼格式化不會破壞您的換行符。另外,對我而言,它是作爲明確的換行符來讀取的,並且更容易理解意圖。

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:fo="http://www.w3.org/1999/XSL/Format" > 
    <xsl:output method="text" omit-xml-declaration="yes" indent="no"/> 

    <xsl:template match="script/command"> 
     <xsl:value-of select="concat('at -f ' 
        ,username 
        ,' ' 
        ,startTime/@hours 
        ,':' 
        ,startTime/@minutes 
        ,' ' 
        ,startDate 
        ,'&#xA;')"/> 
    </xsl:template> 

</xsl:stylesheet> 
+0

感謝Mads,出色的建議。這正是我所期待的。我已經忘記了XPath 2的有用功能... 如何在windows上給我一個新行,當windows通常不僅需要換行符,而且還需要回車? – Chris 2011-05-08 17:15:02

+1

@Chris Dickinson請注意,這是一個XSLT/XPath 1.0解決方案,沒有使用XPath 2.0功能。 ' '(換行)通常就夠了。如果您需要CRLF,您可以添加' '(回車)。 – 2011-05-08 18:28:05

7

只是爲了好玩:這可以在一個非常普遍的和緊湊的方式來完成:

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

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

    <xsl:template match="username"> 
     at -f <xsl:apply-templates select="*|@*"/> 
    </xsl:template> 
</xsl:stylesheet> 

當這個XML文檔施加:

<script> 
<command> 
    <username>John</username> 
    <startTime hours="09:" minutes="33"/> 
    <startDate>05/05/2011</startDate> 

    <username>Kate</username> 
    <startTime hours="09:" minutes="33"/> 
    <startDate>05/05/2011</startDate> 

    <username>Peter</username> 
    <startTime hours="09:" minutes="33"/> 
    <startDate>05/05/2011</startDate> 
</command> 
</script> 

的希望,正確的結果產生:

at -f 09:33 05/05/2011 
    at -f 09:33 05/05/2011 
    at -f 09:33 05/05/2011 

注意:這genaral方法最適用的,如果所有的數據輸出包含在文本節點 - 不是在屬性。

+0

@ *值缺失(並且應該由':'分隔)。另外,不確定輸出中'at -f'之前的空格是否會成爲問題。 – 2011-05-06 14:22:31

+0

@Mads Hansen:謝謝你的注意。現在修復。 – 2011-05-06 14:36:26

+0

差不多,但我不認爲源XML在'@ hours'的值中有':'。發佈的示例XSL明確地將':'放入,而不是從屬性值中進行選擇。 – 2011-05-06 15:07:45