在 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>&#xD;</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>&#xD;</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-处理您的输出以删除字节顺序标记
  • 检查第三方软件的文档是否有删除或忽略字节顺序标记的选项
  • 使用不输出字节顺序标记的不同编码