Saxon XSLT:序列化程序产生奇怪的缩进

Saxon XSLT: Serializer producing weird indents

我正在使用 Saxon HE 9.5.1.8 将 XML 转换为另一个 XML 文件。

我的问题是,由 Saxon 的 Serializer() class 编写的 XML 内容打印出几个我不想在其中出现的额外缩进。我假设这是 "wrong" 因为我在使用 DomDestination() class 时得到了预期的输出(但随后缺少外部 XML 文档信息)或其他 XSL 转换器,如Visual Studio / .NET Framework 附带的一个。

这是输入 XML:

<?xml version="1.0"?>
<catalog>
  <book id="bk101">
    <author>Gambardella, Matthew</author>
    <title>XML Developer's Guide</title>
    <genre>Computer</genre>
    <price>.95</price>
    <publish_date>2000-10-01</publish_date>
  </book>
  <book id="bk102">
    <author>Ralls, Kim</author>
    <title>Midnight Rain</title>
    <genre>Fantasy</genre>
    <price>.95</price>
    <publish_date>2000-12-16</publish_date>
  </book>

这是 XLST 文件:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
>
    <xsl:output method="xml" indent="yes"/>

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

  <xsl:template match="book">
    <book>
      <xsl:copy-of select="@*|book/@*" />
      <xsl:for-each select="*">
        <xsl:attribute name="{name()}">
          <xsl:value-of select="text()"/>
        </xsl:attribute>
      </xsl:for-each>
    </book>
  </xsl:template>

</xsl:stylesheet>

这是预期的输出:

<?xml version="1.0" encoding="utf-8"?>
<catalog>
  <book id="bk101" author="Gambardella, Matthew" title="XML Developer's Guide" genre="Computer" price=".95" publish_date="2000-10-01" />
  <book id="bk102" author="Ralls, Kim" title="Midnight Rain" genre="Fantasy" price=".95" publish_date="2000-12-16" />
</catalog>

这是使用 Saxon 时的输出:

<?xml version="1.0" encoding="UTF-8"?>
<catalog>
    <book id="bk101"
         author="Gambardella, Matthew"
         title="XML Developer's Guide"
         genre="Computer"
         price=".95"
         publish_date="2000-10-01"/>
    <book id="bk102"
         author="Ralls, Kim"
         title="Midnight Rain"
         genre="Fantasy"
         price=".95"
         publish_date="2000-12-16"/>
</catalog>

有人知道如何抑制或修改 Saxon 的这种行为吗?这是用于调用 Saxon API:

的 C# 代码
public Stream Transform(string xmlFilePath, string xsltFilePath)
{
    var result = new MemoryStream();

    var xslt = new FileInfo(xsltFilePath);
    var input = new FileInfo(xmlFilePath);

    var processor = new Processor();
    var compiler = processor.NewXsltCompiler();
    var executable = compiler.Compile(new Uri(xslt.FullName));

    var destination = new Serializer();
    destination.SetOutputStream(result);

    using(var inputStream = input.OpenRead())
    {
        var transformer = executable.Load();
        transformer.SetInputStream(inputStream, new Uri(input.DirectoryName));
        transformer.Run(destination);
    }
    result.Position = 0;
    return result;
}

尝试将 http://saxonica.com/documentation9.5/extensions/output-extras/line-length.html 设置为一个非常大的值以避免将属性放在新行上:<xsl:output xmlns:saxon="http://saxon.sf.net/" saxon:line-length="1000"/>.

您的目标是让多个处理器以相同的格式生成输出,这是无可救药的误导。如果您选择缩进输出,则尤其如此:规范将其完全留给实现如何进行缩进,只说目标是使其易于阅读。 (并对可以插入额外空格的位置施加限制。)

很抱歉,您不觉得 Saxon 包装长属性列表的方式令人满意,但这完全符合规范的文字和精神。没有它,如果您有一个包含八个名称空间声明的元素,您可以轻松获得 400 个字符长的行,我当然不认为这是人类可读的。

从词法上比较两个 XML 文档永远行不通的原因有很多。例如,属性可以采用不同的顺序。有两种比较 XML 的方法:使用 "Canonical XML" 处理器将文档转换为规范形式,或者在树级别比较它们,例如使用 XPath 2.0 deep-equal() 函数。理想情况下(特别是如果您想知道差异在哪里,而不仅仅是差异是否存在),请使用专业的 XML 比较工具,例如 DeltaXML.

值得一提的是,当我们进行单元测试时,我们首先尝试对结果进行词法比较。如果失败,我们解析两个文档并使用 saxon:deep-equal() 比较它们,这是 deep-equal() 函数的修改形式,可以很好地控制比较规则,例如处理空白和命名空间。