C# 在C语言中,我无法将XML反序列化为对象
我已经看过了与此类似的各种问题,但无法找到有效的解决方案 我正在使用Visual Studio 2015社区,构建一个WPF项目 我从后端API获取xml,并试图将其转换为C对象,但无法使其工作 这是xmlC# 在C语言中,我无法将XML反序列化为对象,c#,xml,serialization,C#,Xml,Serialization,我已经看过了与此类似的各种问题,但无法找到有效的解决方案 我正在使用Visual Studio 2015社区,构建一个WPF项目 我从后端API获取xml,并试图将其转换为C对象,但无法使其工作 这是xml <response> <computer_setting id="1" hospital_name="foo" computer_type="bar" environment="staging" label_printer_name="labels" documen
<response>
<computer_setting id="1" hospital_name="foo" computer_type="bar" environment="staging" label_printer_name="labels" document_printer_name="docs"/>
</response>
这是我反序列化它的尝试
// 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.WriteLine时,会引发NullReference异常
{对象引用未设置为对象的实例。}
我已经检查过url是否正确返回了xml,因此它一定是一个构造糟糕的类,或者我没有正确地进行反序列化。一旦XDocument与Linq匹配,我就停止了所有xml属性voodoo。此映射代码简单明了
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();
在上面的代码中,您似乎将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内部的一些事情:
希望这能有所帮助。您的属性必须是公共的才能序列化。根据: XML序列化是将对象的公共属性和字段转换为串行格式(在本例中为存储或传输XML)的过程 将设置从internal更改为public,它将正确反序列化您还必须将ComputerSetting上修改的类更改为public才能编译
顺便说一句,您不应该使用XmlTextReader,自从.NET2发布以来,一直不鼓励使用它。根据,您应该使用XmlReader.Create。Visual Studio有一些很好的工具来从XML或JSON生成可序列化的类-只需将XML的示例复制到剪贴板,打开一个空类文件,并使用Visual Studio中的以下菜单路径将其粘贴为类:编辑->粘贴特殊->将XML粘贴为类…或者,在JSON的情况下,将JSON粘贴为类。您可以简化所有属性获取程序-例如stringitem1.Attributeid??string.Empty。item1永远不会为null。是的,我在url附近的评论中提到了这一点。但感谢您为OP提供了真实的示例代码。此解决方案允许您保留内部名称。需要考虑的事情。
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; }
}
}