如何使 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】:

为此苦苦挣扎了一段时间,但意外地让它工作了:

关键是添加&lt;xsl:strip-space elements="*"/&gt;

所以它看起来像这样:

<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 重要的是 ResultTransformer 的味道。(如果您通过 Java 代码使用 xalan,则您没有编写/无法更改,这可能不是你想听到的。)

对于此答案中的演示,我将使用 PostgreSQL PL/Java,因为它带有一组示例函数,包括 preparexmltransformtransformxml,它们使用 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,它会根据要求添加缩进。

当它被赋予SAXResultStAXResultDOMResult写入时,它不会添加缩进,因为它们都是结构化的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 转换缩进输出?的主要内容,如果未能解决你的问题,请参考以下文章

如何修复/转换 Sublime Text 中的空格缩进?

粘贴到循环/if语句时如何使NetBeans自动格式化缩进?

LaTex缩进问题

如何才能使此代码正常运行?我遇到了if和else语句的问题,显然它没有正确缩进

ScintillaNET 中的缩进和智能缩进

如何将由空格缩进的用户输入存储到 String 数组中并将数字转换为 int 数组?