Получение нуля во вложенных элементах при десериализации xml - PullRequest
0 голосов
/ 16 мая 2019

Я десериализирую свой xml, который является строкой, в мои классы.Проблема в том, что часть вложенных дочерних элементов или их атрибутов возвращает ноль.

Вот моя функция десериализации:

public static T DeSerialize<T>(this string xml)
{
    XmlSerializer serializer = new XmlSerializer(typeof(T));
    using (TextReader reader = new StringReader(xml))
    {
        T result = (T)serializer.Deserialize(reader);
        return result;
    }
}

Вот мои классы:

[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.specifiedcompany.com/API")]
public partial class VideoGames
{
    private GameType[] typesField;

    private Platform platformField;

    private string memoField;

    [System.Xml.Serialization.XmlArray("Types", Order = 0)]
    [System.Xml.Serialization.XmlArrayItem("Data", IsNullable = false)]
    public GameType[] Types
    {
        get
        {
            return this.typesField;
        }
        set
        {
            this.typesField= value;
        }
    }

    [System.Xml.Serialization.XmlElementAttribute("Platform", Order = 1)]
    public Platform Platform
    {
        get
        {
            return this.platformField;
        }
        set
        {
            this.platformField= value;
        }
    }

    [System.Xml.Serialization.XmlAttributeAttribute()]
    public string Memo
    {
        get
        {
            return this.memoField;
        }
        set
        {
            this.memoField= value;
        }
    }
}

[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.specifiedcompany.com/API")]
public partial class Platform
{
    private decimal compressedField;

    [System.Xml.Serialization.XmlAttributeAttribute()]
    public decimal Compressed
    {
        get
        {
            return this.compressedField;
        }
        set
        {
            this.compressedField= value;
        }
    }
}

[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.specifiedcompany.com/API")]
public partial class GameType
{
    private Code[] codeField;

    private string nameField;

    [System.Xml.Serialization.XmlArrayAttribute("Code", Order = 0)] 
    [System.Xml.Serialization.XmlArrayItemAttribute("Category", IsNullable = false)]
    public Code[] Code
    {
        get
        {
            return this.codeField;
        }
        set
        {
            this.codeField= value;
        }
    }

    [System.Xml.Serialization.XmlAttributeAttribute()]
    public string Name
    {
        get
        {
            return this.nameField;
        }
        set
        {
            this.nameField= value;
        }
    }
}

[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.specifiedcompany.com/API")]
public partial class Code
{
    private string textField;

    [System.Xml.Serialization.XmlAttributeAttribute()]
    public string Text
    {
        get
        {
            return this.textField;
        }
        set
        {
            this.textField= value;
        }
    }
}

Здесьэто xml:

<VideoGames Memo="1">
    <Types>
        <Data Name="RPG">
            <Code>
                <Category Text="TestingData"/>
            </Code>
        </Data>
    </Types>
    <Platform Compressed="3.2876"/>
</VideoGames>

И я использую десериализацию следующим образом:

string xml = "";//xml string above.
VideoGames a = xml.DeSerialize<VideoGames>();

Я ожидаю, что каждое свойство в классе будет иметь значение, но только Memo в VideoGames имеет значение, другиеимеют значение null.

Например: a.Types равно нулю, но a.Memo равно "1".

Я пробовал все связанные вопросы, найденные по этой теме, и ни один из них не работает.

Примечание:

XmlDocument xDoc = new XmlDocument();
xDoc.LoadXml(xml);

Я проверил этот xDoc, он отлично загрузился, ничего не пропало.

1 Ответ

0 голосов
/ 17 мая 2019

Самый простой способ диагностики проблем десериализации XML - это сериализация в XML и сравнение наблюдаемого XML с требуемым XML. Обычно проблема будет сразу очевидна.

Если я создаю и сериализую экземпляр VideoGames следующим образом:

var root = new VideoGames
{
    Types = new []
    {
        new GameType
        {
            Name = "RPG",
            Code = new []
            {
                new Code { Text = "TestingData" },
            }
        },
    },
    Platform = new Platform  { Compressed = 3.2876m, },
};

var xml = root.GetXml(omitStandardNamespaces: true);
Console.WriteLine(xml);

Используя следующий метод расширения:

public static string GetXml<T>(this T obj, XmlSerializer serializer = null, bool omitStandardNamespaces = false)
{
    XmlSerializerNamespaces ns = null;
    if (omitStandardNamespaces)
    {
        ns = new XmlSerializerNamespaces();
        ns.Add("", ""); // Disable the xmlns:xsi and xmlns:xsd lines.
    }           
    using (var textWriter = new StringWriter())
    {
        var settings = new XmlWriterSettings() { Indent = true }; // For cosmetic purposes.
        using (var xmlWriter = XmlWriter.Create(textWriter, settings))
            (serializer ?? new XmlSerializer(obj.GetType())).Serialize(xmlWriter, obj, ns);
        return textWriter.ToString();
    }
}

Тогда вывод:

<VideoGames>
  <Types xmlns="http://www.specifiedcompany.com/API">
    <Data Name="RPG">
      <Code>
        <Category Text="TestingData" />
      </Code>
    </Data>
  </Types>
  <Platform Compressed="3.2876" xmlns="http://www.specifiedcompany.com/API" />
</VideoGames>

Демонстрационная скрипка здесь .

Как видите, дочерние элементы <Types> и <Platform> все сериализуются в XML-пространстве имен , в частности http://www.specifiedcompany.com/API.

Ваша десериализация завершается неудачно, потому что в примере XML эти элементы не находятся ни в каком пространстве имен.

Почему это происходит? Это потому, что все ваши классы, включая VideoGames, имеют атрибут XmlTypeAttribute, который задает Namespace:

[System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.specifiedcompany.com/API")]
public partial class VideoGames
{
}

Этот атрибут указывает, что по умолчанию все свойства типа должны быть сериализованы в указанное пространство имен . (Сравните с XmlRootAttribute, который указывает, как должен быть сериализован сам корневой элемент <VideoGames>, а не только его дочерние элементы.)

Если вы не хотите этого, удалите настройку XmlTypeAttribute.Namespace из ваших классов c # VideoGames, Platform, GameType и Code (демо-скрипта # 2 здесь ). Если вы этого хотите, измените ваш XML, включив в него необходимое пространство имен, как показано в выходном XML в этом ответе.

...