简体   繁体   English

在C#中,我无法将XML反序列化为对象

[英]In C# I can't get my XML to deserialize into an object

I've looked through the various questions on here similar to this, but can't get my solution to work. 我已经仔细阅读了与此类似的各种问题,但无法获得有效的解决方案。

I'm using Visual Studio 2015 Community, building a WPF project. 我正在使用Visual Studio 2015社区,正在构建WPF项目。

I get xml from my backend API, and I'm trying to convert it into a C# object, but I can't get it to work. 我从后端API获取xml,并且试图将其转换为C#对象,但无法正常工作。

This is the xml 这是XML

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

This is class 这个课

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; }
    }
}

And this is my attempt to deserialize it 这是我反序列化的尝试

// 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);
}

But this throws NullReference exception when it gets to Debug.WriteLine() 但这会在到达Debug.WriteLine()时引发NullReference异常。

{"Object reference not set to an instance of an object."} {“你调用的对象是空的。”}

I've checked that the url is returning the xml properly, so it must me a poorly constructed class, or I'm not doing the deserialization properly. 我检查了网址是否正确返回了xml,因此它必须是构造不良的类,否则我无法正确进行反序列化。

Visual Studio有一些不错的工具可以从XML或JSON生成可序列化的类-只需将XML的示例复制到剪贴板,打开一个空的类文件,然后在Visual Studio中使用以下菜单路径将其粘贴为类: 编辑->选择性粘贴->将XML粘贴为类 ...或者,如果是JSON,则“粘贴JSON作为类”。

Once XDocument came out ( matched with Linq ) , I stopped all the Xml Attribute voodoo. XDocument出现后(与Linq匹配),我停止了所有Xml Attribute voodoo。 This "mapping" code is simple and straight forward. 此“映射”代码简单明了。

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

In the above code you seem to treat "_Url" as XML but it's just the URL of the backend API, isn't it? 在上面的代码中,您似乎将“ _Url”视为XML,但这只是后端API的URL,不是吗?

I tried replacing it with your sample XML and made it work only by changing the class visibility to public 我尝试用示例XML替换它,并仅通过将类的可见性更改为public使其工作

So this worked for me: 所以这对我有用:

        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 the class like this: 使用这样的类:

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; }
    }
}

I looked into why it didn't work with internal declaration and found this SO answer which helped me understand a few things about the internals of XmlSerializer: https://stackoverflow.com/a/6156822/3093396 我调查了为什么它不能与内部声明一起使用,并找到了这样的答案,它帮助我了解了有关XmlSerializer内部的一些信息: https : //stackoverflow.com/a/6156822/3093396

Hope this helps. 希望这可以帮助。

Your properties are required to be public in order to be serialised. 您的媒体资源必须公开才能进行序列化。 Per the documentation : 根据文档

XML serialization is the process of converting an object's public properties and fields to a serial format (in this case, XML) for storage or transport. XML序列化是将对象的公共属性和字段转换为串行格式(在本例中为XML)以进行存储或传输的过程。

Change Settings from internal to public and it will deserialise correctly (you will also have to change the class modified on ComputerSetting to public in order to compile). Settingsinternal更改为public ,它将正确反序列化(您还必须将在ComputerSetting上修改的类更改为public ,才能进行编译)。

As an aside, you shouldn't be using XmlTextReader , its use has been discouraged since .NET 2 was released. XmlTextReader ,您不应该使用XmlTextReader ,因为.NET 2发布以来,一直不鼓励使用它。 Per the remarks in the documentation , you should use XmlReader.Create . 根据文档中的说明 ,您应该使用XmlReader.Create

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM