用中文字符向Microsoft Translator API发布XML会引发反序列化exception

我正在尝试使用Microsoft Translator API将中文(简体)翻译成英文。

一些要求

  • 我必须使用HTTP方法POST ,而不是使用查询string的GET ,因为我的查询超过了微软的URI限制的15,845个字符(请注意,即使在中文字符的情况下使用less于10,000个字符的限制,是查询string必须进行URL编码,这会显着增加长度,但是在确定字符数之前由Microsoft解码。

  • 唯一允许POST的翻译HTTP方法是TranslateArrayMethod ,例如TranslateMethod只允许GET 。 不幸的是, TranslateArrayMethod只接受一个XML文档,所以我必须使用XML。

以下是我发送的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,我不认为这应该重要。

好的,我遇到了完全一样的问题,从Node.js调用Microsoft Translator POST API之一。 API工作正常 – 只要没有非ASCII字符,只要返回翻译就可以了,但是当我在POST正文的适当的<string>部分添加一个重音符号“é”时,它会以一个错误:

  <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头部需要字节长度,但是我一直以字符forms发送长度。 为什么会发生? 那么,测量Node http请求的主体长度的典型方法是调用

 var length = body.length 

并获得string的“长度”(即字符数)。 当所有的字符都是ASCII时,这是有效的。 但是,事实certificate,在UTF-8中,非ASCII字符(包括我的重音字符“é”)可以多于一个字节。 所以当主体包含非ASCII字符时,字节长度将不再等于字符长度,字符长度不正确。 在这种情况下,它导致Microsoft服务器过早地停止读取消息,生成错误消息。

相反,我们需要用这个调用来测量字节的长度(在Node.js中)

 var length = Buffer.byteLength(body, 'utf8') 

并在Content-Length标题中发送该长度,Microsoft Translator API再次运行。

问题最可能的不是中文,而是MS翻译不喜欢新的符号。 当我偶然发现这个错误信息时,我改变了以下内容:

  1. 在<string>节点的每个内容中用空stringreplace新行字符。 这些字符具有Unicode值:0xA,0xB,0xC,0xD,0x85,0x2028,0x2029
  2. 在<string>节点的每个内容中用其替代表示replace了XML保留字:

    &→&amp;

    <→&lt;

    >→&gt;

    '→'

    “→”

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

之后,一切顺利。 关于你的具体例子,“南”这个符号被翻译为“南”。 我没有使用CDATA转义。