使用 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, ' ', ...)
节省<xsl:value>
元素的数量。此外,您可以包装您的源代码 - 如果您在标签内这样做,它不会影响输出。
好问题,+1。请参阅我的答案以获得完整、非常简短且非常通用的解决方案。
@Christopher Creutzig:感谢您对 concat() 的建议。你指的是什么“包装你的源代码”?
见 Mads 的回答:没有必要把所有东西都放在一条大线上。 (虽然我不会在 逗号之前换行。它看起来很奇怪并且没有添加任何内容,甚至无法更轻松地注释掉某些内容。)
我们不对 Stack Overflow 进行代码审查。我建议您重新构建您的问题,使其成为一个实际问题(例如,如何从 this XML 文档中删除文本),然后发布您的草稿作为答案。
【参考方案1】:
您可以定义一个模板来匹配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
,'
')"/>
</xsl:template>
</xsl:stylesheet>
【讨论】:
感谢 Mads,提出了很好的建议。这正是我一直在寻找的。我忘记了 XPath 2 的有用特性……它是怎么回事 在 windows 上给我一个新行,而 windows 通常不仅需要换行,还需要回车? @Chris Dickinson 请注意,这是一个 XSLT/XPath 1.0 解决方案,没有使用 XPath 2.0 功能。&#xA;
(换行)通常就足够了。需要CRLF的可以加&#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、浏览器等)的提示:如果您不使用<xsl:text>
,它不会删除空格 (!)。以上是关于使用 xsl 输出纯文本的主要内容,如果未能解决你的问题,请参考以下文章