我需要采用一些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 > 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 < 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。
任何输入都非常有用:)
答案 0 :(得分:2)
问题是可以使用组合变音符号而不是单个字符。这就是给你“错误长度”的原因。
有关这些字符的详情,请参阅http://en.wikipedia.org/wiki/Combining_character。
如果您有XSLT 2,则有一个内置函数来规范化它们应该有效:fn:normalize-unicode
对于XSLT 1.0,您必须使用某些函数来计算除组合字符之外的字符。一种可能性可能是使用翻译:
translate($input, '̴̵̶̷̸̡̢̧̨̛̖̗̘̙̜̝̞̟̠̣̤̥̦̩̪̫̬̭̮̯̰̱̲̳̹̺̻̼͇͈͉͍͎̀́̂̃̄̅̆̇̈̉̊̋̌̍̎̏̐̑̒̓̔̽̾̿̀́͂̓̈́͆͊͋͌̕̚ͅ͏͓͔͕͖͙͚͐͑͒͗͛ͣͤͥͦͧͨͩͪͫͬͭͮͯ͘͜͟͢͝͞͠͡', '')
请注意,如果你有合并的亚洲字符,你会遇到更多问题。
来自http://www.dpawson.co.uk/xsl/characters.html
但是如果是Unicode组合 使用字符和输入文件 有e'(其中'真的是' 结合急性特征)然后 应该是任何支持Unicode的渲染器 使这成为一个急剧的 渲染,到XML引擎它是两个 人物,e和急性。
答案 1 :(得分:2)
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计算字节数,则结果是正确的。