【问题标题】:Getting null in nested elements when deserializing xml反序列化 xml 时在嵌套元素中获取 null
【发布时间】:2019-10-03 06:44:55
【问题描述】:

我正在将我的字符串反序列化到我的类中。 问题是嵌套子元素的一部分或其属性返回 null。

这是我的反序列化函数:

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>();

我希望类中的每个属性都有值,但只有 VideoGames 中的 Memo 有值,其他的都是 null。

例如:a.Types 为空,但a.Memo 为“1”。

我已经尝试了该主题搜索的所有相关问题,但没有一个有效。

注意:

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

我检查了这个 xDoc,它加载完美,没有任何丢失。

【问题讨论】:

  • 会不会是TypesPlatform没有初始化?
  • @bolkay我试过了,this.typesField = new GameType[] { };,然后我得到了一个空数组,不是空的。
  • 我怀疑这是初始化数组的有效方法。例如,您可以设置typesField[5]=something? 吗?在这种情况下,根据您的初始化方法{},您的数组中没有任何内容。
  • 哦,我知道这里出了什么问题。我刚刚尝试了this.typesField = new GameType[] { new GameType() };,我得到了一个包含 1 个元素的 GameType 数组,一个没有任何值的新 GameType 类。为什么反序列化不能正确执行?我的其他班级没有这样的问题。
  • a.Platform 也为空。看来现在只能反序列化top节点的属性了。

标签: c# xml deserialization xml-deserialization


【解决方案1】:

诊断 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>

演示小提琴here.

如您所见,子元素&lt;Types&gt;&lt;Platform&gt; 都在XML namespace 中序列化,特别是http://www.specifiedcompany.com/API

您的反序列化失败,因为在示例 XML 中,这些元素不在任何命名空间中。

为什么会这样?这是因为包括VideoGames 在内的所有类都应用了XmlTypeAttribute 属性,该属性指定了Namespace

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

此属性的作用是指定默认情况下,该类型的所有属性都应序列化到指定的命名空间中。 (与 XmlRootAttribute 比较,它指定如何序列化根元素 &lt;VideoGames&gt; 本身,而不仅仅是其子元素。)

如果您不希望这样,请从您的 c# 类 VideoGamesPlatformGameTypeCode(演示小提琴 #2 here)中删除 XmlTypeAttribute.Namespace 设置。如果您确实需要,请修改您的 XML 以包含所需的命名空间,如本答案中的输出 XML 所示。

【讨论】:

  • 非常感谢您的帮助。我刚刚找到了导致问题的原因,这是我的类属性的顺序。我没想到这些ORDER 设置会导致这个问题......无论如何,我认为你的命名空间删除对我来说是一个新知识,但我应该点击接受这个答案吗?因为这可能与问题无关。
  • @ApexEC - 您问题中的示例 XML 具有正确的顺序,即 &lt;Types&gt;,然后是 &lt;Platform&gt;。如果您有不同顺序的不同 XML 并且还需要反序列化它,删除 Order 设置会有所帮助。
  • 对命名空间的解释非常有帮助,谢谢!我从 .dtd 中的 .xsd 生成了一个 .cs 类,并且该过程将 tempuri.org 的默认命名空间提供给所有内容,这使得反序列化无法正常工作。救命稻草!
  • 就我而言,我需要将子元素的命名空间留空,例如:[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "")] public partial class GameType
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-09
  • 1970-01-01
  • 2011-06-24
  • 1970-01-01
相关资源
最近更新 更多