源文件中的长文本字符串,导致输出文件中出现多行

Posted

技术标签:

【中文标题】源文件中的长文本字符串,导致输出文件中出现多行【英文标题】:Long text strings in source file, result in multi-lines in output file 【发布时间】:2021-08-22 09:21:36 【问题描述】:

我需要在技术测试平台中运行由 XSLT 生成的输出文件 (Xhtml)。

每次我使用长文本字符串(来自源文件)并执行 XSLT 时,测试台都不会批准该文档。原因似乎是输出文件 (XHTML) 正在使用长文本字符串并将其分成几行。

在“xsl:output”中我设置了属性“suppress-indentation”,但看起来该属性只控制节点元素(标签)的缩进,而不是节点值的长度。

在我的环境中,我还控制了终端中的输出文件,以确保问题不仅限于我的编程文本编辑器。

有没有办法控制 XSLT 何时判断将长字符串切割成几行的长度?

我的环境:

来自 Saxonica 的 Saxon-HE 10.5J

Java 版本 11.0.11

您可以在 xsltfiddle 中看到该行为: https://xsltfiddle.liberty-development.net/jxWZS72/4

数据:

<?xml version="1.0" encoding="utf-8" ?>
<data>
    <content-cut>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</content-cut>
    <content-no-cut>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt</content-no-cut>
</data>

XSL:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    version="3.0"
>

  <xsl:output method="xhtml" indent="yes" suppress-indentation="content" html-version="5"/>

  <xsl:template match="data">
    <html>
      <head>
        <title>MyTitle</title>
      </head>
      <body>
          
        <string-one>
            <xsl:value-of select="content-cut"/>
        </string-one>
        
        <string-two>
            <xsl:value-of select="content-no-cut"/>
        </string-two>  

      </body>
    </html>
    
  </xsl:template>
  
</xsl:stylesheet>

结果:

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html><html>
   <head>
      <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/><title>MyTitle</title></head>
   <body>
      <string-one>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt
         ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation
         ullamco laboris nisi ut aliquip ex ea commodo consequat.
      </string-one>
      <string-two>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt</string-two>
   </body>
</html>

想要的结果:

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html><html>
   <head>
      <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/><title>MyTitle</title></head>
   <body>
      <string-one>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. </string-one>
      <string-two>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt</string-two>
   </body>
</html>

【问题讨论】:

众所周知,如果您使用缩进,Saxon 会在段落中插入换行符以提高可读性,我认为商业版本具有专有的输出属性,理论上可以通过将非常高的行长度设置为默认值来实现这一点。我不记得HE是否有简单的解决方案;一方面依赖缩进,另一方面又希望保留某些格式是一种困难的方法。 saxonica.com/html/documentation10/extensions/output-extras/… 具有 saxon:line-length 的默认值 80 和“使用 HTML 输出方法,文本行会尽可能按此行长度拆分。”。 规范 w3.org/TR/xslt-xquery-serialization-31/#HTML_INDENT 建议,例如,对于 pre 元素,不应在内容内添加空格,我认为 Saxon 可能会尊重这一点,因为 string-onestring-two 是无论如何都不是任何 HTML 元素,请改用 pre。我认为从技术上讲,suppress-indentation="string-one string-two" 也应该有效,但让我们看看 Michael Kay 怎么说。 【参考方案1】:

看起来您的“测试平台”依赖于 XSLT 规范不需要的行为,实际应用程序可能也不需要。在这种情况下,最好的办法一般是放宽对测试台的要求,以免对转换输出提出不合理的要求。

无论如何,测试序列化的 XML 输出总是很棘手,尤其是在设置了 indent="yes" 时,这使得输出实现的许多方面都得到了定义。

您正在使用suppress-indentation="content",但序列化输出中没有名为content 的元素。您是否尝试过`suppress-indentation="string-one string-two"?我认为这应该按照规范工作;如果没有,我们可能应该修复它。

但我认为您可能应该重新审视您的测试方式。比较序列化的缩进输出太脆弱了。

【讨论】:

我通过在“suppress-indentation”中使用适当的值更新 xsltfiddle 来更新问题。这种特定的变化并没有改善结果。我同意将 indent="yes" 与避免在元素值中剪切长字符串的需要相结合会导致错误和不稳定。 - 但是,在这种特殊情况下,测试台不在我的范围内,因此我不能“放松”它。不过,这对于能够控制和调整元素值的最大可接受文本宽度的测试变体很有用。 感觉有点尴尬,我能够自动生产大约。 10.000 行 XHTML 和当前唯一阻止 100% 自动执行此转换的突出问题是行拆分。请注意,我非常感谢您花时间提供答案和 cmets。 我应该添加一个指向在此提出的撒克逊问题的链接:saxonica.plan.io/issues/5018【参考方案2】:

我写了测试用例

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="3.0"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  exclude-result-prefixes="#all"
  expand-text="yes">
  
  <xsl:param name="suppress-indentation-in" as="xs:string*" static="yes" select="'p', 'string-data'"/>
  
  <xsl:param name="test-elements" as="xs:string*" static="yes" select="'div', $suppress-indentation-in, 'pre', 'span',"/>

  <xsl:output method="html" indent="yes" html-version="5.0" _suppress-indentation="$suppress-indentation-in"/>
  
  <xsl:mode on-multiple-match="use-last"/>

  <xsl:template match="/">
    <html>
      <head>
        <title>suppress-indenation test in $suppress-indentation-in</title>
      </head>
      <body>
        <h1 data-suppress-indentation-in="$suppress-indentation-in">suppress-indentation test in $suppress-indentation-in</h1>
        <xsl:iterate select="$test-elements">
          <xsl:param name="root" select="*"/>
          <section>
            <h2>.</h2>
            <xsl:element name=".">$root</xsl:element>
          </section>
        </xsl:iterate>
      </body>
    </html>
  </xsl:template>
  
  <xsl:template match="/" name="xsl:initial-template">
    <xsl:next-match/>
    <xsl:comment xmlns:saxon="http://saxon.sf.net/">Run with system-property('xsl:product-name') system-property('xsl:product-version') system-property('Qhttp://saxon.sf.net/platform')</xsl:comment>
  </xsl:template>

</xsl:stylesheet>

针对从样本中获取的输入运行它

<text>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</text>

即使使用 Saxon 10.5,结果显示 suppress-indentation 没有被考虑在内,因为输出是

<!DOCTYPE HTML><html>
   <head>
      <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
      <title>suppress-indenation test in p string-data</title>
   </head>
   <body>
      <h1 data-suppress-indentation-in="p string-data">suppress-indentation test in p string-data</h1>
      <section>
         <h2>div</h2>
         <div>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt
            ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation
            ullamco laboris nisi ut aliquip ex ea commodo consequat.</div>
      </section>
      <section>
         <h2>p</h2>
         <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt
            ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation
            ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
      </section>
      <section>
         <h2>string-data</h2>
         <string-data>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt
            ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation
            ullamco laboris nisi ut aliquip ex ea commodo consequat.</string-data>
      </section>
      <section>
         <h2>pre</h2>
         <pre>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</pre>
      </section>
      <section>
         <h2>span</h2><span>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt
            ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation
            ullamco laboris nisi ut aliquip ex ea commodo consequat.</span></section>
   </body>
</html><!--Run with SAXON HE 10.5.1 -->

正如https://www.w3.org/TR/xslt-xquery-serialization-31/#HTML_INDENT 所说:

空白字符不得添加到元素的内容中 其扩展 QName 与扩展 QName 列表的成员匹配 在suppress-indentation参数的值中

我认为撒克逊 10.5 之前有一个错误:https://saxonica.plan.io/issues/5018。

唯一的解决方法似乎是使用pre 元素。

不过,错误 https://saxonica.plan.io/issues/5018 已得到修复,最新版本 10.6 现在支持 suppress-indentation 就好了。

【讨论】:

我测试了预标签包装。它适用于 xsltfiddle 并在我的环境中生成输出文件 (XHTML)。尽管测试字符串的宽度是文档的两倍,但在 Web 浏览器中控制输出文件会导致结果。由于使用了前置标签,这可能是正常的,但文本字符串的宽度与文档的其余部分不对齐。如果没有预先标记,互联网浏览器可以接收 XHTML 中很长的文本字符串,并找出如何以适当的宽度线切割呈现文档。所以 pre-tag 不能作为解决方法。作为临时解决方案,我将 supress-indent 设置为“no”。 @Toolbox,好吧,我建议 pre 元素只是因为您似乎查看了 Saxon 输出,并且仅适用于 pre Saxon 似乎没有强制使用 HE 换行。如果在浏览器中渲染也是一个目标,我建议进行第二个转换步骤。否则,您需要使用 CSS 使 pre 内容看起来“正常”:&lt;pre style="white-space: pre-wrap; font-style: normal; font-family: serif;"&gt; 是的,我错过了解释最终结果目标是用户可以在 Internet 浏览器中看到的文档。

以上是关于源文件中的长文本字符串,导致输出文件中出现多行的主要内容,如果未能解决你的问题,请参考以下文章

是否有可能知道从文件中读取的长文本将在 C 中使用多少个字符?

如何在C++中 统计多行文本中的行数、单词数及字符数

替换文件中的文本

如何在 C# 中读取文本文件中的多行? [复制]

如何在 C# 中读取文本文件中的多行? [复制]

Java将多行字符串保存到文本文件