Saxon9将UTF-8 XML转win-1251 CSV报十进制160字符编码错误
UTF-8编码XML转windows-1251编码CSV报字符不支持错误
问题现象
将UTF-8编码的XML转换为win-1251(windows-1251)编码的CSV文件时,程序抛出如下错误:
net.sf.saxon.trans.DynamicError: Output character not available in this encoding (decimal 160)
已确认报错原因:XML文本中存在十进制编码为160的字符,Saxon 9.1.0.8版本判定该字符不在win-1251编码的支持范围内。
此前曾尝试在XSLT转换前预处理XML清理非法字符,但方案未生效,预处理代码如下:
Charset charset = Charset.forName("windows-1251"); CharsetDecoder decoder = charset.newDecoder(); CharsetEncoder encoder = charset.newEncoder(); encoder.onUnmappableCharacter(CodingErrorAction.REPLACE); String result = s; try { ByteBuffer bbuf = encoder.encode(CharBuffer.wrap(s)); CharBuffer cbuf = decoder.decode(bbuf); result = cbuf.toString(); } catch (CharacterCodingException cce) { log.error("Exception during character encoding/decoding: " + cce.getMessage()); }
相关配置与执行信息
- 转换执行命令:
java -cp saxon-9.1.0.8.jar net.sf.saxon.Transform -t -s:myxml.xml -xsl:myxsl.xsl -o:result.csv
- 执行后完整错误日志:
Saxon 9.1.0.8J from Saxonica Java version 1.8.0_333 Warning: at xsl:stylesheet on line 11 column 81 of myxsl.xsl: Running an XSLT 1.0 stylesheet with an XSLT 2.0 processor Stylesheet compilation time: 378 milliseconds Processing file:/D:/111/myxml2.xml Building tree for file:/D:/111/myxml2.xml using class net.sf.saxon.tinytree.TinyBuilder Tree built in 4 milliseconds Tree size: 46 nodes, 0 characters, 99 attributes Loading net.sf.saxon.event.MessageEmitter Error at xsl:value-of on line 46 of myxsl.xsl: Output character not available in this encoding (decimal 160) at xsl:apply-templates (file:/D:/111/my/myxsl.xsl#66) processing /blocks/table[1]/head[1]/row[1]/col[2] at xsl:apply-templates (file:/D:/111/myxsl.xsl#73) processing /blocks/table[1]/head[1]/row[1] at xsl:apply-templates (file:/D:/111/myxsl.xsl#32) processing /blocks/table[1]/head[1] at xsl:apply-templates (file:/D:/111/myxsl.xsl#24) processing /blocks/table[1] in built-in template rule Transformation failed: Run-time errors were reported
- 使用的XSL样式表示例:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE csv-style [ <!ENTITY semicolons ';;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;'> <!ENTITY commas ',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,'> ]> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" > <xsl:output method="text" indent="no" omit-xml-declaration="yes" encoding="windows-1251"/> <xsl:param name="delim">semicolon</xsl:param> <xsl:param name="showHead">yes</xsl:param> <xsl:variable name="delimStr"> <xsl:choose> <xsl:when test="$delim = 'comma'">&commas;</xsl:when> <xsl:otherwise>&semicolons;</xsl:otherwise> </xsl:choose> </xsl:variable> <xsl:template match="blocks"> <xsl:apply-templates select="*"/> </xsl:template> <xsl:template match="description|pair|foot|body/table/head"> <!-- don't do anything just skip it--> </xsl:template> <xsl:template match="table"> <xsl:apply-templates select="table|head|body"/> </xsl:template> <xsl:template match="col"> <xsl:if test="position()=1"> <xsl:value-of select="substring($delimStr, 1, @id - 1)"/> </xsl:if> <xsl:choose> <xsl:when test="@value"> <xsl:text>"</xsl:text><xsl:variable name="escape"> <xsl:call-template name="_replace_string"> <xsl:with-param name="string" select="@value" /> </xsl:call-template> </xsl:variable> <xsl:value-of select="$escape" /><xsl:text>"</xsl:text> </xsl:when> <xsl:otherwise> <xsl:text>""</xsl:text> <xsl:apply-templates/> </xsl:otherwise> </xsl:choose> <xsl:choose> <xsl:when test="position()=last()"> <xsl:value-of select="substring($delimStr, 1, ancestor::table[1]/@colNum - @id)"/> </xsl:when> <xsl:otherwise> <xsl:value-of select="substring($delimStr, 1, following-sibling::col[1]/@id - @id)"/> </xsl:otherwise> </xsl:choose> </xsl:template> <!-- col --> <xsl:template match="row"> <xsl:if test="col[@value][1]"> <xsl:apply-templates select="col"/> <xsl:text> </xsl:text> </xsl:if> </xsl:template> <xsl:template match="head"> <xsl:if test="$showHead = 'yes'"> <xsl:apply-templates select="*"/> </xsl:if> </xsl:template> <xsl:template match="body"> <xsl:apply-templates select="*"/> </xsl:template> <xsl:template name="_replace_string"> <xsl:param name="string" select="''"/> <xsl:variable name="find">"</xsl:variable> <xsl:variable name="replace">""</xsl:variable> <xsl:choose> <xsl:when test="contains($string,$find)"> <xsl:value-of select="concat(substring-before($string,$find),$replace)"/> <xsl:call-template name="_replace_string"> <xsl:with-param name="string" select="substring-after($string,$find)"/> <xsl:with-param name="find" select="$find"/> <xsl:with-param name="replace" select="$replace"/> </xsl:call-template> </xsl:when> <xsl:otherwise> <xsl:value-of select="$string"/> </xsl:otherwise> </xsl:choose> </xsl:template> </xsl:stylesheet>
- 待转换的XML样例:
<?xml version="1.0" encoding="UTF-8" ?><blocks type="report"><functions><func num="4" text=" nameOf_10031"></func><func num="5" text="name Of_10071"></func><func num="6" text="name Of_10006"></func></functions><description name="[441] testesttest with 160 "><rows total="44" start="1" end="44" show-data="yes"></rows><columns count="10"><column id="1" type="4" position="1" width="" format="'dd.mm.yyyy'"></column><column id="2" type="4" position="2" width="" format="'dd.mm.yyyy'"></column><column id="3" type="3" position="3" width=""></column><column id="4" type="2" position="4" width=""></column><column id="5" type="2" position="5" width=""></column><column id="6" type="2" position="6" width=""></column><column id="7" type="2" position="7" width=""></column><column id="8" type="2" position="8" width=""></column><column id="9" type="2" position="9" width=""></column><column id="10" type="2" position="10" width=""></column></columns></description><pair name="ReportName" value="test test test "></pair><table colNum="10" id="12561"><head><row><col id="1" value="test test test"></col><col id="2" value=" test test test"></col><col id="3" value="test test test"></col><col id="4" value="test test test"></col><col id="5" value="test test test"></col><col id="6" value="test test test"></col><col id="7" value="test test test"></col><col id="8" value=" test test test"></col><col id="9" value="test test test"></col><col id="10" value="test test test"></col></row></head><body><row num="1"><col id="1" value="01.07.2006"></col><col id="2"></col><col id="3" value="53363"></col><col id="4" value="65187" record-id="65187"></col><col id="5" value="53363" record-id="53368"></col><col id="6" value="test test test" record-id="1974"></col><col id="7"></col><col id="8"></col><col id="9" value="test test test"></col><col id="10"></col></row></body></table></blocks>
测试确认使用Saxon-HE-10.3等新版本Saxon时转换无异常,但受环境限制无法升级Saxon版本,寻求该问题的最优解决方式。
内容的提问来源于stack exchange,提问作者Thomazzz
相关产品推荐
相关产品推荐

