在 third-party 应用程序中打开时,XSLT 转换的 CSV 文本输出会出现乱码
CSV text output from XSLT transformation gets garbled when openend in a third-party application
运行有点问题。
我正在使用 VS2015 构建将在第 3 方程序中使用的 XSLT。我已将来自第 3 方程序 (Epicor Service Connect) 的示例数据生成到 XML,并基于此构建了 XSLT。现在,当我在 VS 中调试样式表时,我得到了预期的结果 - 列在顶部,由 semi-colons 分隔,然后每个数据块都在下面,正如预期的那样。
然而,当我通过 Service Connect 程序 运行 它时,我得到了这个完全的谜团:
我需要能够使用 semi-colon 作为分隔符将我的数据 return 保存在 CSV 文件中。我在 VS 中获得的一小段数据表明这是可行的:
当然,当放入 CSV 文件时,它会显示正确的信息。
XSLT 给任何好奇的人(请注意这是我使用 XSLT 的第二天,在此之前我只知道它是什么的缩写 - 所以它不是很好 - 但如果你有改进建议,我很高兴接受建设性批评):
<xsl:stylesheet version="1.0" xmlns:csv="csv:csv" xmlns:message="http://Epicor.com/Message/2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ext_UserSchema="http://Epicor.com/SC/UserSchema">
<xsl:output method="text" encoding="utf-8" />
<xsl:strip-space elements="*" />
<xsl:template match="message:Receiver"/>
<xsl:template match="message:Body">
<xsl:apply-templates select="message:Req"/>
</xsl:template>
<xsl:template match="message:Req">
<xsl:apply-templates select="message:Dta"/>
</xsl:template>
<xsl:template match="message:Dta">
<xsl:call-template name="PrimaryDataLoadForESC"/>
</xsl:template>
<xsl:template match="*">
<xsl:variable name="tessst" select="local-name()"/>
<xsl:choose>
<xsl:when test="$tessst = 'QueryResultDataSet'">
<xsl:call-template name="PrimaryDataLoadNotESC"/>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="message:Body"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="PrimaryDataLoadNotESC">
<xsl:apply-templates select="/QueryResultDataSet/Results[1]/*" mode="header"/>
<xsl:apply-templates select="/QueryResultDataSet/Results" />
</xsl:template>
<xsl:template name="PrimaryDataLoadForESC">
<xsl:apply-templates select="ext_UserSchema:QueryResultDataSet/ext_UserSchema:Results[1]/*" mode="header"/>
<xsl:apply-templates select="ext_UserSchema:QueryResultDataSet/ext_UserSchema:Results" />
</xsl:template>
<xsl:template match="*" mode="header">
<xsl:value-of select="translate(local-name(), '_', ' ')"/>
<xsl:choose>
<xsl:when test="position()=last()">
<xsl:text>
</xsl:text>
</xsl:when>
<xsl:otherwise>;</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="QueryResultDataSet/Results">
<xsl:apply-templates select="*" mode="dataNodes"/>
</xsl:template>
<xsl:template match="ext_UserSchema:QueryResultDataSet/ext_UserSchema:Results">
<xsl:apply-templates select="*" mode="dataNodes"/>
</xsl:template>
<xsl:template match="*" mode="dataNodes">
<xsl:value-of select="."/>
<xsl:choose>
<xsl:when test="position()=last()">
<xsl:text>
</xsl:text>
</xsl:when>
<xsl:otherwise>;</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
一些示例数据:
服务连接前 (post-formatted):
<QueryResultDataSet>
<Results>
<Source_-_System>SOURCE SYSTEM 1</Source_-_System>
<Customer>96247</Customer>
<Description_-_Short>COMPANY DESCRIPTION SHORT</Description_-_Short>
<Description_-_Medium>COMPANY DESCRIPTION MEDIUM</Description_-_Medium>
<Description_-_Long>COMPANY DESCRIPTION LONG</Description_-_Long>
</Results>
服务连接后:
<?xml version="1.0" encoding="utf-16"?>
<msg:Msg xsi:schemaLocation="http://Epicor.com/Message/2.0 http://scshost/schemas/epicor/ScalaMessage.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:msg="http://Epicor.com/Message/2.0">
<msg:Hdr>
<msg:Ctrl>
<msg:MsgID></msg:MsgID>
</msg:Ctrl>
<msg:Sender>
<msg:Name></msg:Name>
<msg:Subname></msg:Subname>
</msg:Sender>
<msg:Logon></msg:Logon>
</msg:Hdr>
<msg:Body>
<msg:Req msg-type="DocumentToProcess" action="MapAndProcess">
<msg:Dta>
<ext_UserSchema:QueryResultDataSet xmlns:msg="http://Epicor.com/InternalMessage/1.1" xmlns:ext_UserSchema="http://Epicor.com/SC/UserSchema">
<ext_UserSchema:Results>
<ext_UserSchema:Source_System>SOURCE_SYS1</ext_UserSchema:Source_System>
<ext_UserSchema:Vendor>96247</ext_UserSchema:Vendor>
<ext_UserSchema:Description_-_Short>COMPANY DESCRIPTION SHORT</ext_UserSchema:Description_-_Short>
<ext_UserSchema:Description_-_Medium>COMPANY DESCRIPTION MEDIUM</ext_UserSchema:Description_-_Medium>
<ext_UserSchema:Description_-_Long>COMPANY DESCRIPTION LONG</ext_UserSchema:Description_-_Long>
</ext_UserSchema:Results>
</ext_UserSchema:QueryResultDataSet>
</msg:Dta>
</msg:Req>
</msg:Body>
</msg:Msg>
有人知道是什么导致了这个问题吗?
我很惊讶我没有早点发现这一点:
由于 byte order mark! The first character is the rendering in ISO-8859-1, CP1252 (windows) or Unicode of 0xFF 'ÿ' and the second 0xFE 'þ',您的渲染出错应用UTF-8解码(字节为0xEF,0xBB 0xBF)。
所以,简而言之,要解决这个问题,请将 xsl:output
更改为包含:
<xsl:output byte-order-mark="no" />
但这只适用于 XSLT 2.0 或更高版本。如果您无法切换到 XSLT 2.0,您应该检查处理器的文档,看它是否支持不带字节顺序标记的 UTF-8 编码。
至少在某些时候,the Saxon processor output a byte order mark 在使用 UTF-8 文本输出时。此外,在 Windows 上,记事本和许多其他编辑器会在保存文件时自动发出字节顺序标记(例如,如果您 post 手动编辑 CSV,则可能会发生这种情况)。
要解决此问题:
- 使用任何处理器切换到 XSLT 2.0
- Post-处理您的输出以删除字节顺序标记
- 检查第三方软件的文档是否有删除或忽略字节顺序标记的选项
- 使用不输出字节顺序标记的不同编码
运行有点问题。
我正在使用 VS2015 构建将在第 3 方程序中使用的 XSLT。我已将来自第 3 方程序 (Epicor Service Connect) 的示例数据生成到 XML,并基于此构建了 XSLT。现在,当我在 VS 中调试样式表时,我得到了预期的结果 - 列在顶部,由 semi-colons 分隔,然后每个数据块都在下面,正如预期的那样。
然而,当我通过 Service Connect 程序 运行 它时,我得到了这个完全的谜团:
我需要能够使用 semi-colon 作为分隔符将我的数据 return 保存在 CSV 文件中。我在 VS 中获得的一小段数据表明这是可行的:
当然,当放入 CSV 文件时,它会显示正确的信息。
XSLT 给任何好奇的人(请注意这是我使用 XSLT 的第二天,在此之前我只知道它是什么的缩写 - 所以它不是很好 - 但如果你有改进建议,我很高兴接受建设性批评):
<xsl:stylesheet version="1.0" xmlns:csv="csv:csv" xmlns:message="http://Epicor.com/Message/2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ext_UserSchema="http://Epicor.com/SC/UserSchema">
<xsl:output method="text" encoding="utf-8" />
<xsl:strip-space elements="*" />
<xsl:template match="message:Receiver"/>
<xsl:template match="message:Body">
<xsl:apply-templates select="message:Req"/>
</xsl:template>
<xsl:template match="message:Req">
<xsl:apply-templates select="message:Dta"/>
</xsl:template>
<xsl:template match="message:Dta">
<xsl:call-template name="PrimaryDataLoadForESC"/>
</xsl:template>
<xsl:template match="*">
<xsl:variable name="tessst" select="local-name()"/>
<xsl:choose>
<xsl:when test="$tessst = 'QueryResultDataSet'">
<xsl:call-template name="PrimaryDataLoadNotESC"/>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="message:Body"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="PrimaryDataLoadNotESC">
<xsl:apply-templates select="/QueryResultDataSet/Results[1]/*" mode="header"/>
<xsl:apply-templates select="/QueryResultDataSet/Results" />
</xsl:template>
<xsl:template name="PrimaryDataLoadForESC">
<xsl:apply-templates select="ext_UserSchema:QueryResultDataSet/ext_UserSchema:Results[1]/*" mode="header"/>
<xsl:apply-templates select="ext_UserSchema:QueryResultDataSet/ext_UserSchema:Results" />
</xsl:template>
<xsl:template match="*" mode="header">
<xsl:value-of select="translate(local-name(), '_', ' ')"/>
<xsl:choose>
<xsl:when test="position()=last()">
<xsl:text>
</xsl:text>
</xsl:when>
<xsl:otherwise>;</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="QueryResultDataSet/Results">
<xsl:apply-templates select="*" mode="dataNodes"/>
</xsl:template>
<xsl:template match="ext_UserSchema:QueryResultDataSet/ext_UserSchema:Results">
<xsl:apply-templates select="*" mode="dataNodes"/>
</xsl:template>
<xsl:template match="*" mode="dataNodes">
<xsl:value-of select="."/>
<xsl:choose>
<xsl:when test="position()=last()">
<xsl:text>
</xsl:text>
</xsl:when>
<xsl:otherwise>;</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
一些示例数据:
服务连接前 (post-formatted):
<QueryResultDataSet>
<Results>
<Source_-_System>SOURCE SYSTEM 1</Source_-_System>
<Customer>96247</Customer>
<Description_-_Short>COMPANY DESCRIPTION SHORT</Description_-_Short>
<Description_-_Medium>COMPANY DESCRIPTION MEDIUM</Description_-_Medium>
<Description_-_Long>COMPANY DESCRIPTION LONG</Description_-_Long>
</Results>
服务连接后:
<?xml version="1.0" encoding="utf-16"?>
<msg:Msg xsi:schemaLocation="http://Epicor.com/Message/2.0 http://scshost/schemas/epicor/ScalaMessage.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:msg="http://Epicor.com/Message/2.0">
<msg:Hdr>
<msg:Ctrl>
<msg:MsgID></msg:MsgID>
</msg:Ctrl>
<msg:Sender>
<msg:Name></msg:Name>
<msg:Subname></msg:Subname>
</msg:Sender>
<msg:Logon></msg:Logon>
</msg:Hdr>
<msg:Body>
<msg:Req msg-type="DocumentToProcess" action="MapAndProcess">
<msg:Dta>
<ext_UserSchema:QueryResultDataSet xmlns:msg="http://Epicor.com/InternalMessage/1.1" xmlns:ext_UserSchema="http://Epicor.com/SC/UserSchema">
<ext_UserSchema:Results>
<ext_UserSchema:Source_System>SOURCE_SYS1</ext_UserSchema:Source_System>
<ext_UserSchema:Vendor>96247</ext_UserSchema:Vendor>
<ext_UserSchema:Description_-_Short>COMPANY DESCRIPTION SHORT</ext_UserSchema:Description_-_Short>
<ext_UserSchema:Description_-_Medium>COMPANY DESCRIPTION MEDIUM</ext_UserSchema:Description_-_Medium>
<ext_UserSchema:Description_-_Long>COMPANY DESCRIPTION LONG</ext_UserSchema:Description_-_Long>
</ext_UserSchema:Results>
</ext_UserSchema:QueryResultDataSet>
</msg:Dta>
</msg:Req>
</msg:Body>
</msg:Msg>
有人知道是什么导致了这个问题吗?
我很惊讶我没有早点发现这一点:
由于 byte order mark! The first character is the rendering in ISO-8859-1, CP1252 (windows) or Unicode of 0xFF 'ÿ' and the second 0xFE 'þ',您的渲染出错应用UTF-8解码(字节为0xEF,0xBB 0xBF)。
所以,简而言之,要解决这个问题,请将 xsl:output
更改为包含:
<xsl:output byte-order-mark="no" />
但这只适用于 XSLT 2.0 或更高版本。如果您无法切换到 XSLT 2.0,您应该检查处理器的文档,看它是否支持不带字节顺序标记的 UTF-8 编码。
至少在某些时候,the Saxon processor output a byte order mark 在使用 UTF-8 文本输出时。此外,在 Windows 上,记事本和许多其他编辑器会在保存文件时自动发出字节顺序标记(例如,如果您 post 手动编辑 CSV,则可能会发生这种情况)。
要解决此问题:
- 使用任何处理器切换到 XSLT 2.0
- Post-处理您的输出以删除字节顺序标记
- 检查第三方软件的文档是否有删除或忽略字节顺序标记的选项
- 使用不输出字节顺序标记的不同编码