欧洲字符到固定宽度输出的XSLT字符填充

时间:2010-07-01 08:02:18

标签: xml xslt character-encoding

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

这是一个问题,因为我的代码会检查属性的长度是什么,然后从固定长度输出格式的最大长度中减去它(例如,如果它读取了它,则为30宽度字段我认为它需要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大于零,则递归调用count-1直到0。

任何输入都非常有用:)

4 个答案:

答案 0 :(得分:2)

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

有关这些字符的详情,请参阅http://en.wikipedia.org/wiki/Combining_character

如果您有XSLT 2,则有一个内置函数来规范化它们应该有效:fn:normalize-unicode

对于XSLT 1.0,您必须使用某些函数来计算除组合字符之外的字符。一种可能性可能是使用翻译:

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的渲染器   使这成为一个急剧的   渲染,到XML引擎它是两个   人物,e和急性。

答案 1 :(得分:2)

与所有XSLT / XPath一样,

string-length()是基于字符的,而不是基于字节的,因此string-length("Ãbcd")肯定会给出4.如果它给出5,那么:

  • 你的Ã实际上是两个独立的字符,其中一个字符组合了波形变量,它实际上是正确的,即使它意味着列没有在视觉上排列。但我猜可能不是,因为你在这里粘贴的版本是一个单一的组合字符,U + 00C3 LATIN CAPITAL LETTER A WITH TILDE。或者,

  • 您的输入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等现代脚本语言的几行重写上面的模板,使其更具可读性和效率。

答案 2 :(得分:0)

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

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

答案 3 :(得分:0)

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

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