使用 xsl 输出纯文本

Posted

技术标签:

【中文标题】使用 xsl 输出纯文本【英文标题】:use xsl to output plain text 【发布时间】:2011-08-20 00:03:35 【问题描述】:

我需要使用 XSL 从 XML 生成简单的纯文本输出。由于我没有在网上找到任何好的、简洁的示例,我决定在这里发布我的解决方案。任何引用更好示例的链接当然会受到赞赏:

<?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>

一些对我有帮助的重要事情:

    使用 xsl:output 省略输出文档开头的标准声明 使用 xml:space="preserve" 属性来保留我在 xsl:for-each 标记中编写的任何空白。这还要求我将所有代码都写在 for-each 标记中,包括该标记在内,都写在一行上(换行符除外)。 使用 插入换行符 - 我不得不在这里省略标准 xml 缩进。

这个 xslt 的结果和期望的输出是:

在 -f alluser 23:58 17.4.2010 在 -f ggroup67 7:58 28.4.2010 在 -f ggroup70 15:58 18.4.2010 在 -f alluser 23:58 18.4.2010 在 -f ggroup61 7:58 22.9.2010 在 -f ggroup60 23:58 21.9.2010 在 -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>

【问题讨论】:

您可以使用concat('at -f ', username, ' ', startTime/@hours, ' ', ...) 节省&lt;xsl:value&gt; 元素的数量。此外,您可以包装您的源代码 - 如果您在标签内这样做,它不会影响输出。 好问题,+1。请参阅我的答案以获得完整、非常简短且非常通用的解决方案。 @Christopher Creutzig:感谢您对 concat() 的建议。你指的是什么“包装你的源代码”? 见 Mads 的回答:没有必要把所有东西都放在一条大线上。 (虽然我不会在 逗号之前换行。它看起来很奇怪并且没有添加任何内容,甚至无法更轻松地注释掉某些内容。) 我们不对 Stack Overflow 进行代码审查。我建议您重新构建您的问题,使其成为一个实际问题(例如,如何从 this XML 文档中删除文本),然后发布您的草稿作为答案。 【参考方案1】: 您可以定义一个模板来匹配script/command 并消除xsl:for-each concat() 可用于缩短表达式,避免显式插入这么多 &lt;xsl:text&gt;&lt;xsl:value-of&gt; 元素。 使用实体引用&amp;#xA; 进行回车,而不是依靠保留&lt;xsl:text&gt; 元素之间的换行符更安全一些,因为代码格式不会弄乱换行符。此外,对我来说,它读作明确的换行符,更容易理解其意图。
<?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>

【讨论】:

感谢 Mads,提出了很好的建议。这正是我一直在寻找的。我忘记了 XPath 2 的有用特性……它是怎么回事 在 windows 上给我一个新行,而 windows 通常不仅需要换行,还需要回车? @Chris Dickinson 请注意,这是一个 XSLT/XPath 1.0 解决方案,没有使用 XPath 2.0 功能。 &amp;#xA;(换行)通常就足够了。需要CRLF的可以加&amp;#xD;(回车)。【参考方案2】:

只是为了好玩:这可以以非常通用和紧凑的方式完成

<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  

注意:如果要输出的所有数据都包含在文本节点中,而不是属性中,则此一般方法最适用。

【讨论】:

@* 值丢失(并且应该由 ':' 分隔)。此外,不确定输出中 'at -f' 之前的前导空格是否有问题。 @Mads Hansen:感谢您注意到这一点。现已修复。 几乎,但我认为源 XML 在@hours 的值中没有':'。发布的示例 XSL 明确地将“:”放入,而不是从属性值中选择。 @Mads Hansen:当然。虽然我说“为了好玩”,但我的回答指出了一种设计 XML 的通用方法,以便可以使用相同的通用和琐碎的 XSLT 转换来生成输出,而无需了解任何其他细节。正如我在回答中所说,我不会使用属性,只会将数据存储在文本节点中。 LibXML2 用户(php、Python、浏览器等)的提示:如果您不使用&lt;xsl:text&gt;,它不会删除空格 (!)。

以上是关于使用 xsl 输出纯文本的主要内容,如果未能解决你的问题,请参考以下文章

使用PHP格式化HTML代码以纯文本输出[重复]

如何格式化 Oracle SQL 纯文本选择输出

如何使 xsl 转换缩进输出?

angularjs输出纯文本而不是html

ffprobe 或 avprobe 在 JSON 输出中返回纯文本错误

XSL 转换以输出许多嵌入式 XSL 样式表