Linq XML to Object,其中 xml 节点具有嵌套元素

Posted

技术标签:

【中文标题】Linq XML to Object,其中 xml 节点具有嵌套元素【英文标题】:Linq XML to Object, where xml nodes have nested elements 【发布时间】:2019-12-01 11:15:27 【问题描述】:

我需要从 XML 文档生成一个List<Event>,而Event 有一个List<Contact>。阅读时如何将 XML 转换为 List<Event> 对象:

这是我的事件类:

public class Event

    public string id  get; set; 
    public string title  get; set; 
    public DateTime Start  get; set; 
    public DateTime End  get; set; 
    public virtual List<Contact> contacts  get; set; 

联系班级

public class Contact


    public int Id  get; set; 
    public string Name  get; set; 

这是我在用户添加内容时保存 XML 文档的方式。

<Event>
    <id>1</id>
    <title>AA</title>
    <start>2019-12-01T14:13:58.863</start>
    <end>2019-12-01T15:13:58.787</end>
    <contacts>

      <contact>
        <id>1</id>
        <name>ABC</name>
      </contact>

      <contact>
        <id>2</id>
        <name>ABCD</name>
      </contact>

      <contact>
        <id>3</id>
        <name>ABCDE</name>
      </contact>

    </contacts>
  </Event>

获取我使用的 XML 文档

XDocument xml = new XDocument();
xmlDoc = XDocument.Load("Data.xml");

我对如何将项目读取到列表中感到震惊。我该怎么做?

【问题讨论】:

可以反序列化xml:docs.microsoft.com/en-us/dotnet/api/… 【参考方案1】:

假设你的 xml 的根被称为事件:

<?xml version="1.0" encoding="UTF-8"?>
<Events>
    <Event>
        <id>1</id>
        <title>AA</title>
        <start>2019-12-01T14:13:58.863</start>
        <end>2019-12-01T15:13:58.787</end>
        <contacts>
            <contact>
                <id>1</id>
                <name>ABC</name>
            </contact>
            <contact>
                <id>2</id>
                <name>ABCD</name>
            </contact>
            <contact>
                <id>3</id>
                <name>ABCDE</name>
            </contact>
        </contacts>
    </Event>
    <Event>
        <id>2</id>
        <title>AA</title>
        <start>2019-12-02T14:13:58.863</start>
        <end>2019-12-02T15:13:58.787</end>
        <contacts>
            <contact>
                <id>4</id>
                <name>DEF</name>
            </contact>
            <contact>
                <id>5</id>
                <name>BNH</name>
            </contact>
            <contact>
                <id>6</id>
                <name>KLK</name>
            </contact>
        </contacts>
    </Event>
</Events>

您可以定义以下两个代表 XML 文档结构的类:

[XmlType("Event")]
public class Event

    [XmlElement("id")]
    public string Id  get; set; 
    [XmlElement("title")]
    public string Title  get; set; 
    [XmlElement("start")]
    public DateTime Start  get; set; 
    [XmlElement("end")]
    public DateTime End  get; set; 
    [XmlArray("contacts")]
    public virtual List<Contact> Contacts  get; set; 


[XmlType("contact")]
public class Contact

    [XmlElement("id")]
    public int Id  get; set; 

    [XmlElement("name")]
    public string Name  get; set; 

然后你可以反序列化你的 XML 如下:

using (var reader = new StreamReader(filename))

    var deserializer = new XmlSerializer(typeof(List<Event>), new XmlRootAttribute("Events"));
    return (List<Event>) deserializer.Deserialize(reader);

您必须将filename 替换为您的xml 文件所在的路径。

如果我们假设您已选择要复制到输出目录的 xml - 右键单击​​文件并检查它的属性以检查或设置它 - 那么您可以很容易地获得它的路径,如下所示(假设它被称为 events.xml):

var outputDirectory = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
var filename = Path.Combine(outputDirectory, @"events.xml");

为了让您掌握 XmlSerializer,我建议您从 XmlSerializer 开始,然后继续使用此 Examples of XML Serialization。

【讨论】:

嗨,这很有效,感谢您提供的链接,我会检查一下,我是 c# 新手,一切看起来都很奇怪。 我可以用同样的方法从 xml 文件中获取特定节点并更新并保存它 @mikeoconner 非常欢迎您。我很高兴能帮上忙。 @mikeoconner 如果我必须得到一个特定的节点,更新它并保存它,我会选择 LINQ to XML。您可以从docs.microsoft.com/en-us/dotnet/csharp/programming-guide/… 开始阅读。然后查看类似***.com/questions/1487653/… 的答案或查看教程,它们很多。如果您需要任何具体的帮助。请提出另一个问题,具体说明问题所在。谢谢【参考方案2】:

使用System.Xml.SerializationEvent 对象保存到XML 或从XML 加载。将创建的 XML 格式与您的非常相似。

可以用相同的方式保存/加载List&lt;Event&gt;(在下面的示例中,Event 需要替换为List&lt;Event&gt;)。

注意:以下示例中的加载(使用XmlSerializer.Deserialize)将无法与您创建的 XML 文件一起正常工作,它仅适用于保存示例创建的 XML 文件(使用 @ 987654332@)。要将XmlSerializer.Deserialize 与您自己的XML 文件一起使用,需要将XmlElement 属性添加到类属性并为XmlSerializer 提供XmlRootAttribute(如Christos answer)。如果您可以使用XmlSerializer.Serialize 创建 XML 文件而不使用您已经创建的文件,您将节省额外的工作。

Event 对象保存为 XML(序列化)的示例:

public static void Save(string fileName, Event e)

    XmlSerializer xmlSerializer = new XmlSerializer(typeof(Event));

    using (Stream stream = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.None))
    

        xmlSerializer.Serialize(stream, e);
    

从 XML 加载 Event 对象的示例(脱盐):

public static Event Load(string fileName)

    Event e = null;
    XmlSerializer xmlSerializer = new XmlSerializer(typeof(Event));

    using (Stream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read,  FileShare.None))
    

        e = (Event)xmlSerializer.Deserialize(stream);
    

    return e;

将为 Event 对象创建的 XML 与您在文件中的内容相似(或相同):

<?xml version="1.0"?>
<Event xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <id>1</id>
  <title>AA</title>
  <Start>2019-12-01T14:13:58.863</Start>
  <End>2019-12-01T15:13:58.787</End>
  <contacts>
    <Contact>
      <Id>1</Id>
      <Name>ABC</Name>
    </Contact>
    <Contact>
      <Id>2</Id>
      <Name>ABCD</Name>
    </Contact>
    <Contact>
      <Id>3</Id>
      <Name>ABCDE</Name>
    </Contact>
  </contacts>
</Event>

【讨论】:

我尝试了这种方法,第一次它给了我一个错误,说不需要 RootTag。然后我在***上找到了一个答案,说要初始化像 XmlSerializer xmlSerializer = new XmlSerializer(typeof(List),xRoot); 这样的序列化程序 一旦我执行了代码,但 List 为空 xmlSerializer.Deserialize 的默认操作无法正确处理您的文件。我在答案中的意思是建议您首先使用XmlSerializer.Serialize 创建XML 文件,这样您的对象将以默认方式序列化为XML,xmlSerializer.Deserialize 将正常工作。如果要使用已创建的文件,则必须使用 XmlElement 属性,例如 Christos answer 您需要像Christos 一样提供XmlRootAttribute 答案。如果您首先使用XmlSerializer.Serialize 创建文件,那么您的工作量会更少,不需要XmlElement 属性和XmlRootAttribute

以上是关于Linq XML to Object,其中 xml 节点具有嵌套元素的主要内容,如果未能解决你的问题,请参考以下文章

Linq to XML 后代和元素有啥区别

LINQ to SQL 可以查询 XML 字段 DB-serverside 吗?

Linq to XML

LINQ to XML简介

LINQ to XML概述

C# linq to Xml(复习用)