将带有中文字符的 XML 发布到 Microsoft Translator API 会引发反序列化异常

POSTing XML with Chinese characters to the Microsoft Translator API raises deserializing exception

我正在尝试使用 Microsoft Translator API.

将中文(简体)翻译成英文

几个要求

以下是我发送的 XML 文档的示例:

<TranslateArrayRequest>
    <AppId/>
    <From>es</From>
    <Options>
        <ContentType xmlns="http://schemas.datacontract.org/2004/07/Microsoft.MT.Web.Service.V2">text/plain</ContentType>
    </Options>
    <Texts>
        <string xmlns="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
        <![CDATA[Hola]]>
        </string>
    </Texts>
    <To>en</To>
</TranslateArrayRequest>

这很好用,结果是:

<ArrayOfTranslateArrayResponse xmlns="http://schemas.datacontract.org/2004/07/Microsoft.MT.Web.Service.V2" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<TranslateArrayResponse>
    <From>es</From>
    <OriginalTextSentenceLengths xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
    <a:int>4</a:int>
</OriginalTextSentenceLengths>
<TranslatedText>Hello</TranslatedText>
<TranslatedTextSentenceLengths xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
<a:int>5</a:int>
</TranslatedTextSentenceLengths>
</TranslateArrayResponse>
</ArrayOfTranslateArrayResponse>

但是,如果我再添加任何汉字,就像这样:

<TranslateArrayRequest>
    <AppId/>
    <From>zh-CHS</From>
    <Options>
        <ContentType xmlns="http://schemas.datacontract.org/2004/07/Microsoft.MT.Web.Service.V2">text/plain</ContentType>
    </Options>
    <Texts>
        <string xmlns="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
        <![CDATA[南]]>
        </string>
    </Texts>
    <To>en</To>
</TranslateArrayRequest>

我收到一个奇怪的回复:

<html>
    <body/>
    <h1>System.Runtime.Serialization.SerializationException</h1>
    <p>Message: There was an error deserializing the object of type Microsoft.MT.MDistributor.V2.TranslateArrayRequest. Unexpected end of file. Following elements are not closed: TranslateArrayRequest. Line 1, position 298.</p>
</html>

请注意,我也尝试过不使用 CDATA 转义,但没有帮助。更改 From 语言也没有效果。

我正在使用 Node.js (Javascript),尽管因为这是一个通用的 HTTP API 我认为这不重要。

很可能,问题不是中文,而是MS Translator 不喜欢换行符号。当我偶然发现此错误消息时,我更改了以下内容:

  1. 节点的每个内容中,用空字符串替换新行字符。这些字符具有 Unicode 值:0xA、0xB、0xC、0xD、0x85、0x2028、0x2029
  2. 节点的每个内容中,将 XML 保留字替换为其替代表示:

    & → &

    < → <

    > → >

    ' → '

    " → "

  3. 将整个 XML 重新排列成一行

之后一切顺利。关于您的特定示例,符号“南”被翻译为 "South"。我没有使用 CDATA 转义。

好的,我在调用来自 Node.js 的 Microsoft Translator POST API 之一时遇到了完全相同的问题。 API 工作正常 - returns 翻译符合预期 - 只要没有 non-ASCII 个字符,但是当我在适当的 [= POST body 的 13=] 部分,它响应错误:

    <html><body/><h1>System.Runtime.Serialization.SerializationException</h1>
<p>Message: There was an error deserializing the object of type Microsoft.MT.MDistributor.V2.TranslateArrayRequest. Unexpected end of file. Following elements are not closed: TranslateArrayRequest. Line 1, position 782.</p>
</html>

我发现问题是 Content-Length header 想要以字节为单位的长度,但我一直在发送以字符为单位的长度。为什么会这样?那么,测量节点 http 请求的 body 长度的典型方法是调用

var length = body.length

并获取字符串的 "length" - 即字符数。这在所有字符都是 ASCII 时有效。然而,事实证明,在 UTF-8 non-ASCII 中,每个字符(包括我的重音符号 'é')可以超过一个字节。所以当 body 包含 non-ASCII 个字符时,字节长度将不再等于字符长度,字符长度不正确。在这种情况下,它导致 Microsoft 服务器过早地停止读取消息,从而生成错误消息。

相反,我们需要通过调用(在 Node.js 中)

来测量字节长度
var length = Buffer.byteLength(body, 'utf8')

并在 Content-Length header 中发送该长度,Microsoft Translator API 再次工作。