【问题标题】:XSLT character padding for European characters to fixed width output将欧洲字符的 XSLT 字符填充到固定宽度输出
【发布时间】:2010-07-01 16:39:13
【问题描述】:

我需要获取一些 XML 并将其转换为固定宽度的加载文件,以便加载到 SAP 系统。我的算法工作正常,除了一些奇怪的欧洲字符,例如 Ã,在字符串中为每个字符实例返回 +1 的字符串长度。因此,例如文本 Ãbcd 的字符串长度($value)将是 5 而不是 4。

这是一个问题,因为我的代码检查属性的长度是多少,然后从固定长度输出格式的最大长度中减去它(即对于 30 宽度的字段,如果它读取 Ãbcd 它会认为它需要 25 个空格而不是 26 个)。

有谁知道更好的方法来做到这一点,或者我在算法中做错了什么?

以下是我的 xsl 模板(大多数情况下......无法将它们完全正确地放在这里......)

写出属性的模板:

<xsl:param name="value"/>
<xsl:param name="width"/>

<!-- find the current length of the field-->
<xsl:variable name="valueWidth" select="string-length($value)" />
<xsl:variable name="difference" select="$width - $valueWidth" />


  <xsl:if test="$difference &gt; 0">
  <xsl:value-of select="$value"/>
  <!-- run this for loop x times outputing space for each -->
  <xsl:call-template name="for-loop-spaces">
    <xsl:with-param name="count" select="$difference - 1" />
  </xsl:call-template>

</xsl:if>


<xsl:if test="($difference &lt; 0)">
  <xsl:value-of select="substring($value,0,$width)"/>
</xsl:if>

<xsl:if test="$difference = 0">
  <xsl:value-of select="$value"/>
</xsl:if>
</xsl:template>

For-loop-spaces 模板(它不会复制粘贴): 每次调用时输出一个空格。接受参数“计数”。如果 count 大于零,递归调用 count-1 直到 0。

任何输入都会非常有用:)

【问题讨论】:

    标签: xml xslt character-encoding


    【解决方案1】:

    问题在于可以使用组合变音符号代替单个字符。这就是给你“错误长度”的原因。

    有关这些字符的更多信息,请参阅http://en.wikipedia.org/wiki/Combining_character

    如果您有 XSLT 2,则有一个内置函数可以对它们进行规范化,这应该可以工作:fn:normalize-unicode

    对于 XSLT 1.0,您必须使用一些函数来计算不包括组合字符的字符。一种可能是使用 translate:

    translate($input, '&#768;&#769;&#770;&#771;&#772;&#773;&#774;&#775;&#776;&#777;&#778;&#779;&#780;&#781;&#782;&#783;&#784;&#785;&#786;&#787;&#788;&#789;&#790;&#791;&#792;&#793;&#794;&#795;&#796;&#797;&#798;&#799;&#800;&#801;&#802;&#803;&#804;&#805;&#806;&#807;&#808;&#809;&#810;&#811;&#812;&#813;&#814;&#815;&#816;&#817;&#818;&#819;&#820;&#821;&#822;&#823;&#824;&#825;&#826;&#827;&#828;&#829;&#830;&#831;&#832;&#833;&#834;&#835;&#836;&#837;&#838;&#839;&#840;&#841;&#842;&#843;&#844;&#845;&#846;&#847;&#848;&#849;&#850;&#851;&#852;&#853;&#854;&#855;&#856;&#857;&#858;&#859;&#860;&#861;&#862;&#863;&#864;&#865;&#866;&#867;&#868;&#869;&#870;&#871;&#872;&#873;&#874;&#875;&#876;&#877;&#878;&#879;', '')
    

    请注意,如果您将亚洲字符组合在一起,您将遇到更多问题。

    引用http://www.dpawson.co.uk/xsl/characters.html

    但是,如果 Unicode 结合 使用字符和输入文件 有 e' (其中 ' 真的是 结合急性字符)然后同时 任何 Unicode 感知渲染器都应该 把它变成一个 e 锐度 呈现,对于 XML 引擎,它是两个 字符,e 和锐角。

    【讨论】:

    • 我认为应该强调的是,这不是 XSLT 问题而是渲染问题:两个不同的字符串(一个带有一个字符,一个带有一个字符和一个变音符号)可以在同一个方法。因此,问题是如何在 XSLT 中重现渲染算法(没有理由事先知道)。
    • @Alejandro,你是完全正确的。但我的建议基本上确实解决了这个问题:它试图让 string-length() 返回呈现的宽度而不是字符宽度。
    • 您的回答非常好,并且有据可查。但是来自 Dave Pawson 网站的引用可以解释为对 XSLT 功能的批评(形式上 XSLT 应该了解 Unicode 渲染算法)。这只是一个“社论”评论。
    • @Alejandro,我明白了。我认为问题在于大多数人不太了解 Unicode 以及相关的东西,例如 UTF 编码、组合字符等等。 Unicode 很棒,但它的复杂性和功能集经常被低估。话虽这么说,XSLT(和任何其他基于字符的处理)通常不能意识到呈现的观点。不间断空格、换行符、制表符等也很大程度上依赖于渲染,但人们知道其中的大部分,因此本能地知道它们将如何表现或如何处理它们。
    【解决方案2】:

    string-length() 和所有 XSLT/XPath 一样,是基于字符的,而不是基于字节的,所以 string-length("Ãbcd") 肯定应该给出 4。如果给出 5,那么:

    • 您的 Ã 实际上是两个单独的字符,其中一个是组合波浪号变音符号,即使这意味着列在视觉上没有对齐,它实际上也是正确的。但我猜可能不是,因为您在此处粘贴的版本是单个组合字符,U+00C3 带有 TILDE 的拉丁大写字母 A。或者,

    • 您的输入 XML 已使用错误的编码读取,实际上是 UTF-8(XML 的默认值),但已被读取为其他内容,通常是 ISO-8859-1,从而导致 U+00C3 字符,由字节序列0xC3,0x83表示,输出为两个字符U+00C3,U+0083 (Ã)。

    您需要担心的不仅仅是“奇怪的欧洲字符”;如果你弄错了 Unicode,那么 所有 基本 7 位 ASCII 集之外的字符都会被破坏,包括许多即使是孤立的美国人也喜欢使用的字符。

    在任何情况下,SAP 想要为其 FWV 输入格式采用什么编码都是一个问题。将Ã 视为单个字符并为一个字符添加正确数量的填充字符,这一切都很好,但是如果您随后输出到 UTF-8 并且 SAP 实际上并没有读取 UTF-8,它仍然会破坏导入。

    您需要找出目标 SAP 安装所需的编码(如果不是 UTF-8,cp1252 是另一个不错的猜测),以及该格式的固定列是否基于 Unicode 字符或字节。从此(相关?)spec 我相信它们实际上是基于字节的,在这种情况下,如果您的数据库应该包含 UTF-8,那么 5 实际上是正确的字节长度。

    不幸的是,XSLT 完全是关于字符的,并没有让您有机会使用字节,所以如果输入文件是基于字节的,您将不得不:

    • 删除所有非 ASCII 字符,使这一点没有实际意义,或者

    • 使用 XSLT 之外的另一个工具来执行此处理,一个知道字节的工具。老实说,这对我来说是最有意义的:XSLT 非常适合 XML 到 XML 的转换,但对于其他字符串处理任务来说非常糟糕。您可以用几行现代脚本语言(如 Python)重新编写上面的模板,使其更具可读性和效率。

    【讨论】:

      【解决方案3】:

      您是在计算字节数还是字符数?您提到的 Ã 是 1 个字符,但 2 个字节(使用 UTF-8 时,似乎是这种情况)。 UTF-8 中的字符可以占用 1-4 个字节。

      如果string-length计算字节,则结果正确。

      【讨论】:

      【解决方案4】:

      这不是 XSLT 问题,而可能是输出的编码问题。您的 XSLT 是如何执行的?您可能必须更改输出编写器的设置。

      正如 Oded 所说,这可能是输入阅读器编码而不是输出编码的问题,因为根据XPath specification,字符串长度计算字符,因此您可能正在计算转换为的字符串的字符Ä 有多个字符。 也许输入是 UTF-8,但您的配置将其读取为单字节编码?

      【讨论】:

      • 也可能是输入的编码问题。
      • 是的,很可能就是这样!
      猜你喜欢
      • 1970-01-01
      • 2016-01-31
      • 2018-05-31
      • 1970-01-01
      • 1970-01-01
      • 2021-11-30
      • 1970-01-01
      • 2011-01-15
      • 1970-01-01
      相关资源
      最近更新 更多