1

I have some data referenced here http://docs.microsofttranslator.com/text-translate.html#!/default/post_TranslateArray

<ArrayOfTranslateArrayResponse 
    xmlns="http://schemas.datacontract.org/2004/07/Microsoft.MT.Web.Service.V2" 
    xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
    <TranslateArrayResponse>
        <From>en</From>
        <OriginalTextSentenceLengths 
            xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
            <a:int>14</a:int>
        </OriginalTextSentenceLengths>
        <TranslatedText>Esto es una prueba</TranslatedText>
        <TranslatedTextSentenceLengths 
            xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
            <a:int>18</a:int>
        </TranslatedTextSentenceLengths>
    </TranslateArrayResponse>
    <TranslateArrayResponse>
        <From>en</From>
        <OriginalTextSentenceLengths 
            xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
            <a:int>22</a:int>
        </OriginalTextSentenceLengths>
        <TranslatedText>Hola, yo tengo una manzana</TranslatedText>
        <TranslatedTextSentenceLengths 
            xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
            <a:int>26</a:int>
        </TranslatedTextSentenceLengths>
    </TranslateArrayResponse>
</ArrayOfTranslateArrayResponse>

I'm trying to deserialize this data using a DataContractSerializer. All the values in the collection are null. I can serialize using this same structure and it comes out the same as this text, but it won't deserialize. Here is the code.

void Main()
{
    var xmlString = "<ArrayOfTranslateArrayResponse xmlns=\"http://schemas.datacontract.org/2004/07/Microsoft.MT.Web.Service.V2\" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\"><TranslateArrayResponse><From>language-code</From><OriginalTextSentenceLengths xmlns:a=\"http://schemas.microsoft.com/2003/10/Serialization/Arrays\"><a:int>int-value</a:int></OriginalTextSentenceLengths><State/><TranslatedText>string-value</TranslatedText><TranslatedTextSentenceLengths xmlns:a=\"http://schemas.microsoft.com/2003/10/Serialization/Arrays\"><a:int>int-value</a:int></TranslatedTextSentenceLengths></TranslateArrayResponse></ArrayOfTranslateArrayResponse>";
    var dcs = new DataContractSerializer(typeof(TranslateArrayResponseCollection));

    using (var stream = new MemoryStream())
    using (var writer = new StreamWriter(stream))
    {
        writer.Write(xmlString);
        writer.Flush();
        stream.Position = 0;

        dcs.ReadObject(stream).Dump();
    }
}

[CollectionDataContract(Name = "ArrayOfTranslateArrayResponse", Namespace = "http://schemas.datacontract.org/2004/07/Microsoft.MT.Web.Service.V2")]
public class TranslateArrayResponseCollection : List<TranslateArrayResponse> { }

[DataContract(Name = "TranslateArrayResponse", Namespace = "")]
public class TranslateArrayResponse
{
    [DataMember]
    public string Error { get; set; }

    [DataMember]
    public string From { get; set; }

    [DataMember]
    public int[] OriginalSentenceLengths { get; set; }

    [DataMember]
    public string TranslatedText { get; set; }

    [DataMember]
    public int[] TranslatedSentenceLengths { get; set; }

    [DataMember]
    public string State { get; set; }
}
Josh Close
  • 22,935
  • 13
  • 92
  • 140
  • 1
    Try to generate data classes automatically using https://learn.microsoft.com/en-us/dotnet/framework/wcf/generating-data-type-classes-from-xml and check where the difference in names/namespaces is. – Alex Seleznyov Jan 25 '18 at 19:41
  • That's a really cool feature! but it didn't do anything for me. I'm using a .NET Core 2.0 project, so maybe that's why it doesn't work. – Josh Close Jan 25 '18 at 19:47
  • 1
    there is a comment somewhere on that page that it works for .net 4.5 project only. So you need to open new 4.5 project, make classes from xml and copy the file over to your original project. Messy a little, though. I don't understand why MS set that limitation. – Alex Seleznyov Jan 25 '18 at 19:50

1 Answers1

2

In your XML data arrays are named OriginalTextSentenceLengths and TranslatedTextSentenceLengths. But in your data contract they are OriginalSentenceLengths and TranslatedSentenceLengths. You should rename them in data contract:

[DataMember]
public string TranslatedText { get; set; }

[DataMember]
public int[] TranslatedTextSentenceLengths { get; set; }

Another problem is missing namespace for the elements. After I have added empty namespace xmlns="" to all elements the data is deserialized correctly. Here is modified XML:

<ArrayOfTranslateArrayResponse 
    xmlns="http://schemas.datacontract.org/2004/07/Microsoft.MT.Web.Service.V2" 
    xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
    <TranslateArrayResponse>
        <From xmlns="">en</From>
        <OriginalTextSentenceLengths xmlns=""
            xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
            <a:int>14</a:int>
        </OriginalTextSentenceLengths>
        <TranslatedText xmlns="">Esto es una prueba</TranslatedText>
        <TranslatedTextSentenceLengths xmlns=""
            xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
            <a:int>18</a:int>
        </TranslatedTextSentenceLengths>
    </TranslateArrayResponse>
    <TranslateArrayResponse>
        <From xmlns="">en</From>
        <OriginalTextSentenceLengths xmlns=""
            xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
            <a:int>22</a:int>
        </OriginalTextSentenceLengths>
        <TranslatedText xmlns="">Hola, yo tengo una manzana</TranslatedText>
        <TranslatedTextSentenceLengths xmlns=""
            xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
            <a:int>26</a:int>
        </TranslatedTextSentenceLengths>
    </TranslateArrayResponse>
</ArrayOfTranslateArrayResponse>

I believe it's the limitation of DataContractSerializer. Check this question with exactly the same problem. You should either modify source XML by adding the namespace or use XmlSerializer which should handle this case.

CodeFuller
  • 30,317
  • 3
  • 63
  • 79
  • Sorry, that was the example in that link. I put in the actual text that's returned to me from the service now. – Josh Close Jan 25 '18 at 19:22
  • Your text works for me too, but not the actual text the service returns. – Josh Close Jan 25 '18 at 19:24
  • Thanks. This is really bad. I do see that the DCS will generate all empty namespaces too. I was really hoping to just have some objects, but looks like I'll have to use the `XmlSerializer` or `XElement` instead. – Josh Close Jan 25 '18 at 20:02