如何使 xsl 转换缩进输出?
Posted
技术标签:
【中文标题】如何使 xsl 转换缩进输出?【英文标题】:How do I make xsl transformation indent the output? 【发布时间】:2011-01-25 00:34:49 【问题描述】:我正在使用带有以下 xsl 标头的 xalan:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0"
xmlns:redirect="http://xml.apache.org/xalan/redirect"
extension-element-prefixes="redirect"
xmlns:xalan="http://xml.apache.org/xalan">
<xsl:output method="text" indent="yes" xalan:indent-amount="4"/>
而且输出没有缩进。
有人有想法吗?
【问题讨论】:
我在notepad++中使用了xsl工具。当我的 xsl 中有错字时,它无法缩进输出。验证您的 xsl 文件具有正确的语法。 【参考方案1】:我猜你必须将method
设置为xml
。如果这不起作用,请尝试以下操作:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xalan="http://xml.apache.org/xalan">
<xsl:output method="xml" encoding="UTF-8" indent="yes" xalan:indent-amount="4"/>
【讨论】:
是否有可能您正在使用无法正确呈现内容的应用程序查看 xml?【参考方案2】:对于缩进,您需要使用不同的命名空间:http://xml.apache.org/xslt
(参见this issue)
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0"
xmlns:redirect="http://xml.apache.org/xalan/redirect"
extension-element-prefixes="redirect"
xmlns:xalan="http://xml.apache.org/xslt">
<xsl:output method="xml" indent="yes" xalan:indent-amount="4"/>
【讨论】:
xalan 命名空间在xalan.apache.org/xalan-j/apidocs/org/apache/xml/serializer/… 中有记录http://xml.apache.org/xslt
即使在旧版本中也已被弃用(请参阅Declare the xalan namespace),请改用http://xml.apache.org/xalan
。【参考方案3】:
Jirka-x1,感谢您提供问题链接。我使用了以下内容(由 Ed Knoll 13/Aug/04 提出):
<xsl:stylesheet ... xmlns:xslt="http://xml.apache.org/xslt">
<xsl:output ... indent="yes" xslt:indent-amount="4" />
这对我来说适用于 xalan (java) 2.7.1。
【讨论】:
【参考方案4】:为此苦苦挣扎了一段时间,但意外地让它工作了:
关键是添加<xsl:strip-space elements="*"/>
所以它看起来像这样:
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:java="http://xml.apache.org/xalan/java"
xmlns:xalan="http://xml.apache.org/xslt">
<xsl:output method="xml" encoding="ASCII" indent="yes" xalan:indent-amount="4"/>
<xsl:strip-space elements="*"/>
不知道为什么,但可能删除所有空格有助于 xalan 找出缩进
【讨论】:
如果没有xsl:strip-space[@elements="*"]
,xsl 会尝试在输出中保留输入中的空白节点。
即使没有 xalan 也能像魅力一样工作 :)【参考方案5】:
虽然这是一个相当老的问题,但答案可能还有另一个角度尚未触及。
TL;DR 重要的是 Result
和 Transformer
的味道。(如果您通过 Java 代码使用 xalan,则您没有编写/无法更改,这可能不是你想听到的。)
对于此答案中的演示,我将使用 PostgreSQL PL/Java,因为它带有一组示例函数,包括 preparexmltransform
和 transformxml
,它们使用 Java 的基于 xalan 的 XSLT 1.0 东西,并且还有一些额外的用于测试目的的参数。这里有一个重要的行为效应,如果没有这些额外的参数,我不会看到。
我将首先准备一个名为 indent
的转换:
SELECT
preparexmltransform(
'indent',
'<xsl:transform version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<xsl:copy-of select="."/>
</xsl:template>
</xsl:transform>',
how => 5);
应该很清楚,第一个参数是转换的名称,第二个是定义它的 XSLT。稍后我会谈到“如何”的论点。
无论如何,让我们在一些 XML 上使用该转换,看看会发生什么:
SELECT
transformxml(
'indent',
'<a b="c" d="e"><f><g/><h/></f></a>',
howin => 5, howout => 4);
transformxml
----------------
<a b="c" d="e">
<f>
<g/>
<h/>
</f>
</a>
很酷,这立即完成了所需的操作,并表明上面的短变换就足够了;值得注意的是,它不需要xalan:indent-amount
属性(除非你喜欢不同的缩进宽度),所以它不需要定义xalan
命名空间,也不需要为它定义strip-space
元素工作(如果您尝试在输入文档中使用空格,则缩进空格只是添加到其中,这看起来很愚蠢,因此您可以选择使用strip-space
,但缩进会以任何一种方式发生)。
我还没有说那些额外的参数是做什么的(现在有两个,“howin”和“howout”!),但那即将到来,因为看看会发生什么,除了“howout”从 4 到 5 没有任何变化:
SELECT
transformxml(
'indent',
'<a b="c" d="e"><f><g/><h/></f></a>',
howin => 5, howout => 5);
transformxml
------------------------------------
<a b="c" d="e"><f><g/><h/></f></a>
所以“howout”对于缩进是否发生很重要。这些是怎么回事?
嗯,Java 不只有一种用于处理 XML 的 API。它有几个,包括 DOM、StAX 和 SAX,更不用说您可能只想将 XML 处理为 String
,或通过 Reader
/Writer
处理字符流,或通过 @987654340 处理编码字节流@/OutputStream
.
JDBC 规范规定,如果您正在编写 Java 代码以在数据库中使用 XML,SQLXML API 必须让您选择任何一种处理数据的方式,以方便您的任务。 JAXP 转换 API 规定,您必须能够处理几乎任何风格的 Source
和任何风格的 Result
Transformer
,并让它做正确的事情。
这就是为什么那些 PL/Java 示例函数具有“如何”参数的原因:需要有一种方法来测试相同 XML 内容可以传递到 Transformer
的所有必需方式以及 @987654346 的所有方式@的结果可以回来。 “如何”排列(任意)如下:
code | form | howin | howout
------+---------------------+--------------+--------------
1 | binary stream | InputStream | OutputStream
2 | character stream | Reader | Writer
3 | String | String | String
4 | binary or character | StreamSource | StreamResult
5 | SAX | SAXSource | SAXResult
6 | StAX | StAXSource | StAXResult
7 | DOM | DOMSource | DOMResult
那么相同的 xalan 缩进变换在以不同的方式调用以产生其结果时会做什么?
SELECT
i, transformxml(
'indent',
'<a b="c" d="e"><f><g/><h/></f></a>',
howin => 5, howout => i)
FROM
generate_series(1,7) AS i;
i | transformxml
---+------------------------------------------
1 | <a b="c" d="e">
| <f>
| <g/>
| <h/>
| </f>
| </a>
|
2 | <a b="c" d="e">
| <f>
| <g/>
| <h/>
| </f>
| </a>
|
3 | <a b="c" d="e">
| <f>
| <g/>
| <h/>
| </f>
| </a>
|
4 | <a b="c" d="e">
| <f>
| <g/>
| <h/>
| </f>
| </a>
|
5 | <a b="c" d="e"><f><g/><h/></f></a>
6 | <a b="c" d="e"><f><g></g><h></h></f></a>
7 | <a b="c" d="e"><f><g/><h/></f></a>
嗯,这就是模式。对于Transformer
实际上必须直接生成字符或字节的序列化流的所有 API,它会根据要求添加缩进。
当它被赋予SAXResult
、StAXResult
或DOMResult
写入时,它不会添加缩进,因为它们都是结构化的XML API;就好像 xalan 将缩进严格视为一个序列化问题,并且在生成 SAX、StAX 或 DOM 时,它技术上并没有序列化。
(上表还显示,当其他 API 执行时,StAX API 并不总是将空元素呈现为自关闭。附带问题,但很有趣。)
因此,如果您发现自己试图让 xalan 转换进行缩进,但事实并非如此,请仔细检查您要求 Transformer
生成哪种形式的 Result
。
编辑: 最后一点:如果您是直接用 Java 编写代码,那么真的根本不需要编写那些七行代码的 XSLT 来获得仅此而已带有indent
输出属性集的身份转换。
如果您调用无参数 TransformerFactory.newTransformer()
,它会直接为您提供普通的身份转换。然后你需要做的就是设置它的输出属性,然后你就开始做生意了:
var tf = javax.xml.transform.TransformerFactory.newInstance();
var t = tf.newTransformer();
t.setOutputProperty("indent", "yes");
t.setOutputProperty("http://xml.apache.org/xalanindent-amount", "1"); // if you don't like the default 4
t.transform(source, result);
没有比这更简单的了。再次强调,result
必须是 StreamResult
,以便转换器进行序列化。
【讨论】:
以上是关于如何使 xsl 转换缩进输出?的主要内容,如果未能解决你的问题,请参考以下文章
粘贴到循环/if语句时如何使NetBeans自动格式化缩进?