使用具有多个子元素的Linq解析XML

时间:2015-06-12 21:47:30

标签: c# xml linq xml-parsing

这是我关于SO的第一个问题,如果我做错了,请告诉我!

我正在尝试解析类似于此的XML:

<LiveUpdate>
  <CityID>F0A21EA2</CityID>
  <CityName>CityTown</CityName>
  <UserName>john</UserName>
  <ApplicationDetails>
    <ApplicationDetail
      Application="AC"
      Licensed="true"
      Version="2015.2"
      Patch="0001"
    />
    <ApplicationDetail
      Application="AP"
      Licensed="true"
      Version="2015.2"
      Patch="0002"
    />
  </ApplicationDetails>
</LiveUpdate>

我的课程看起来像这样:

public class Client
{
    public string cityID { get; set; }
    public string cityName { get; set; }
    public string userName { get; set; }
    public List<Apps> appList { get; set; }
    }
public class Apps
{
    public string app { get; set; }
    public string licensed { get; set; }
    public string version { get; set; }
    public string patch { get; set; }
}

我需要能够拥有一个客户端类,其中包含要迭代的所有应用程序详细信息的列表。

到目前为止,我提出的最好的是:

XDocument xml = XDocument.Load(@"C:\blah\Desktop\1.xml");
var liveUpdate = xml.Root;
var clients = (from e in liveUpdate.Elements()
               select new Client()
               {
                   cityID = e.Element("CityID").Value,
                   cityName = e.Element("CityName").Value,
                   userName = e.Element("UserName").Value,
                   appList = e.Elements("ApplicationDetails")
                              .Select(a => new Apps()
                              {
                                  app = a.Element("Application").Value,
                                  licensed = a.Element("Licensed").Value,
                                  version = a.Element("Version").Value,
                                  patch = a.Element("Patch").Value
                              }).ToList()
               });

但是,我目前遇到一个错误,指出对象引用未设置为对象的实例。 我在这里看到了一些类似的例子,但没有在多个孩子面前处理数据。

我对XML和Linq相当陌生,所以非常感谢任何帮助!

2 个答案:

答案 0 :(得分:1)

由于您已经定义了要反序列化的类,因此可以使用XmlSerializer为您反序列化它。

首先,让我们重命名一些属性名称,使其与XML和c# naming conventions更加匹配:

[XmlRoot("LiveUpdate")]
public class Client
{
    public string CityID { get; set; }
    public string CityName { get; set; }
    public string UserName { get; set; }

    [XmlArray("ApplicationDetails")]
    [XmlArrayItem("ApplicationDetail")]
    public List<Apps> AppList { get; set; }
}

public class Apps
{
    [XmlAttribute]
    public string Application { get; set; }
    [XmlAttribute]
    public bool Licensed { get; set; }
    [XmlAttribute]
    public string Version { get; set; }
    [XmlAttribute]
    public string Patch { get; set; }
}

然后添加以下扩展方法:

public static class XmlSerializationHelper
{
    public static T LoadFromXML<T>(this string xmlString)
    {
        using (StringReader reader = new StringReader(xmlString))
        {
            object result = new XmlSerializer(typeof(T)).Deserialize(reader);
            if (result is T)
            {
                return (T)result;
            }
        }
        return default(T);
    }

    public static T LoadFromFile<T>(string filename)
    {
        using (var fs = new FileStream(filename, FileMode.Open))
        {
            object result =  new XmlSerializer(typeof(T)).Deserialize(fs);
            if (result is T)
            {
                return (T)result;
            }
        }
        return default(T);
    }
}

现在您可以按如下方式从XML文件反序列化:

        string fileName = @"C:\blah\Desktop\1.xml";
        var client = XmlSerializationHelper.LoadFromFile<Client>(fileName);

我手动更新了您的Client类,以便正确映射到提供的XML,但如果您想自动执行此操作,请参阅此处:Generate C# class from XML

答案 1 :(得分:1)

  1. 您的XML只包含一个LiveUpdate标记,因此您只想查看Root元素,而不是遍历其中的所有元素。
  2. 在ApplicationDetails中,ApplicationLicensed属性,而不是元素。使用.Attribute()访问它们。
  3. ApplicationDetails是一个标记,其中包含ApplicationDetail个标记。
  4. LiveUpdate标记中没有DateTime元素。
  5. 这有效:

        var liveUpdate = xml.Root;
        var e = liveUpdate;
        var clients = new Client()
                    {
                        cityID = e.Element("CityID").Value,
                        cityName = e.Element("CityName").Value,
                        userName = e.Element("UserName").Value,
                        //dateTime = e.Element("DateTime").Value,
                        appList = e.Element("ApplicationDetails").Elements("ApplicationDetail")
                                    .Select(a => new Apps()
                                    {
                                        app = a.Attribute("Application").Value,
                                        licensed = a.Attribute("Licensed").Value,
                                        version = a.Attribute("Version").Value,
                                        patch = a.Attribute("Patch").Value
                                    }).ToList()
                    };