在c#中,我不能将我的XML反序列化成对象

本文关键字:XML 我的 反序列化 对象 不能 | 更新日期: 2023-09-27 18:07:30

我已经浏览了这里类似的各种问题,但无法得到我的解决方案。

我正在使用Visual Studio 2015 Community,构建一个WPF项目。

我从我的后端API得到xml,我正试图将其转换为c#对象,但我不能让它工作。

这是xml

<response>
    <computer_setting id="1" hospital_name="foo" computer_type="bar" environment="staging" label_printer_name="labels" document_printer_name="docs"/>
</response>

这是类

using System.Xml.Serialization;
namespace Casechek.Kiosk
{
    [XmlRoot("response")]
    public class ComputerSettingResponse
    {
        [XmlElement("computer_setting")]
        internal ComputerSetting Settings { get; set; }
    }
    internal class ComputerSetting
    {
        [XmlAttribute("id")]
        internal string Id { get; set; }
        [XmlAttribute("hospital_name")]
        internal string HospitalName { get; set; }
        [XmlAttribute("computer_type")]
        internal string ComputerType { get; set; }
        [XmlAttribute("environment")]
        internal string Environment { get; set; }
        [XmlAttribute("label_printer_name")]
        internal string LabelPrinterName { get; set; }
        [XmlAttribute("document_printer_name")]
        internal string DocumentPrinterName { get; set; }
    }
}

这是我对它进行反序列化的尝试

// Get ComputerSettings
String _Url = this.ApiUrl
   + "/api1/hospitals/foo/settings.xml"
   + "?access_token=" + Authentication.AccessToken;
XmlSerializer _Serializer = new XmlSerializer(typeof(ComputerSettingResponse));
ComputerSettingResponse _ComputerSettingResponse = new ComputerSettingResponse();
using (XmlTextReader _XmlReader = new XmlTextReader(_Url))
{
    _ComputerSettingResponse = (ComputerSettingResponse)_Serializer.Deserialize(_XmlReader);
    Debug.WriteLine(_ComputerSettingResponse.Settings.Environment);
}

但是当它到达debug时抛出NullReference异常。writeline ()

{"对象引用未设置为对象的实例。"}

我已经检查了url是否正确返回xml,所以它必须是一个构造不良的类,或者我没有正确地进行反序列化。

在c#中,我不能将我的XML反序列化成对象

Visual Studio有一些很好的工具可以从XML或JSON生成可序列化的类-只需将XML样本复制到剪贴板中,打开一个空的类文件并将其粘贴为类,使用Visual Studio中的以下菜单路径:Edit -> paste Special -> paste XML as classes …或者,在JSON的情况下,"Paste JSON as Classes"

你的属性必须是公共的才能被序列化。根据文档:

XML序列化是将对象的公共属性和字段转换为用于存储或传输的串行格式(在本例中为XML)的过程。

Settingsinternal更改为public,它将正确反序列化(您还必须将在ComputerSetting上修改的类更改为public以便编译)。

顺便说一句,你不应该使用XmlTextReader,自从。net 2发布以来,它的使用就不被鼓励了。根据文档中的注释,您应该使用XmlReader.Create

在上面的代码中,你似乎把"_Url"作为XML,但它只是后端API的URL,不是吗?

我尝试用您的示例XML替换它,并仅通过将类可见性更改为public

使其工作

所以这对我有用:

        String xml = File.ReadAllText("XMLFile1.xml");
        XmlSerializer _Serializer = new XmlSerializer(typeof(ComputerSettingResponse));
        ComputerSettingResponse _ComputerSettingResponse = new ComputerSettingResponse();
        using (StringReader reader = new StringReader(xml))
        {
            _ComputerSettingResponse = (ComputerSettingResponse)_Serializer.Deserialize(reader);
            Debug.WriteLine(_ComputerSettingResponse.Settings.Environment);
        }
using System.Xml.Serialization;
namespace Casechek.Kiosk
{
    [XmlRoot("response")]
    public class ComputerSettingResponse
    {
        [XmlElement("computer_setting")]
        public ComputerSetting Settings { get; set; }
    }
    public class ComputerSetting
    {
        [XmlAttribute("id")]
        public string Id { get; set; }
        [XmlAttribute("hospital_name")]
        public string HospitalName { get; set; }
        [XmlAttribute("computer_type")]
        public string ComputerType { get; set; }
        [XmlAttribute("environment")]
        public string Environment { get; set; }
        [XmlAttribute("label_printer_name")]
        public string LabelPrinterName { get; set; }
        [XmlAttribute("document_printer_name")]
        public string DocumentPrinterName { get; set; }
    }
}

我研究了为什么它不能与内部声明一起工作,并找到了这个答案,它帮助我理解了一些关于XmlSerializer内部的事情:https://stackoverflow.com/a/6156822/3093396

一旦出现XDocument(与Linq匹配),我就停止了所有Xml属性的巫术。这段"映射"代码简单而直接。

public class ComputerSettingResponse
{
    internal ComputerSetting Settings { get; set; }
}
internal class ComputerSetting
{
    internal string Id { get; set; }
    internal string HospitalName { get; set; }
    internal string ComputerType { get; set; }
    internal string Environment { get; set; }
    internal string LabelPrinterName { get; set; }
    internal string DocumentPrinterName { get; set; }
}
            string xmlString = @"<response>
    <computer_setting id=""1"" hospital_name=""foo"" computer_type=""bar"" environment=""staging"" label_printer_name=""labels"" document_printer_name=""docs""/>
</response>          ";
        XDocument xDoc = XDocument.Parse(xmlString);
        //XNamespace ns = XNamespace.Get("http://schemas.microsoft.com/developer/msbuild/2003");
        string ns = string.Empty;

        List<ComputerSettingResponse> collection = new List<ComputerSettingResponse>
        (
            from list in xDoc.Descendants(ns + "response")
            from item1 in list.Elements(ns + "computer_setting")
            where item1 != null
            select new ComputerSettingResponse
            {
                //note that the cast is simpler to write than the null check in your code
                //http://msdn.microsoft.com/en-us/library/bb387049.aspx
                Settings = new ComputerSetting
                (
                ) 
                {
                    Id = (string)item1.Attribute("id") ?? string.Empty,
                    HospitalName = (string)item1.Attribute("hospital_name") ?? string.Empty,
                    ComputerType = (string)item1.Attribute("computer_type") ?? string.Empty,
                    Environment = (string)item1.Attribute("environment") ?? string.Empty,
                    LabelPrinterName = (string)item1.Attribute("label_printer_name") ?? string.Empty,
                    DocumentPrinterName = (string)item1.Attribute("document_printer_name") ?? string.Empty
                }
            }
        );
        /* if you know there is only one */
        ComputerSettingResponse returnItem = collection.FirstOrDefault();