MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

C#中的XML与JSON数据处理

2021-03-105.3k 阅读

C#中XML数据处理基础

XML简介

XML(可扩展标记语言)是一种标记语言,旨在存储和传输数据。它具有良好的可读性和可扩展性,广泛应用于数据交换、配置文件等场景。在C#中,处理XML数据有多种方式,包括使用XmlDocument、XmlReader和XmlWriter等类。

使用XmlDocument

XmlDocument类提供了一种将XML文档加载到内存并以树形结构操作的方式。以下是一个简单的示例,展示如何创建一个基本的XML文档并添加节点:

using System;
using System.Xml;

class Program
{
    static void Main()
    {
        // 创建一个XmlDocument实例
        XmlDocument doc = new XmlDocument();

        // 创建根节点
        XmlElement root = doc.CreateElement("Books");
        doc.AppendChild(root);

        // 创建第一个书节点
        XmlElement book = doc.CreateElement("Book");
        root.AppendChild(book);

        // 添加书的属性
        XmlAttribute titleAttr = doc.CreateAttribute("Title");
        titleAttr.Value = "C# Programming";
        book.Attributes.Append(titleAttr);

        // 添加作者子节点
        XmlElement author = doc.CreateElement("Author");
        author.InnerText = "John Doe";
        book.AppendChild(author);

        // 保存XML文档到文件
        doc.Save("books.xml");
    }
}

在上述代码中,首先创建了一个XmlDocument实例。接着,创建了根节点Books并将其添加到文档中。然后创建了一个Book节点,并为其添加了Title属性和Author子节点。最后,将整个XML文档保存到books.xml文件中。

加载和读取XML文档同样简单。假设我们有如下的books.xml文件:

<Books>
    <Book Title="C# Programming">
        <Author>John Doe</Author>
    </Book>
    <Book Title="Advanced C#">
        <Author>Jane Smith</Author>
    </Book>
</Books>

下面的代码展示如何加载并读取该XML文档:

using System;
using System.Xml;

class Program
{
    static void Main()
    {
        XmlDocument doc = new XmlDocument();
        doc.Load("books.xml");

        XmlNodeList bookNodes = doc.GetElementsByTagName("Book");
        foreach (XmlNode book in bookNodes)
        {
            XmlAttribute titleAttr = book.Attributes["Title"];
            if (titleAttr != null)
            {
                Console.WriteLine("Title: " + titleAttr.Value);
            }

            XmlNode authorNode = book.SelectSingleNode("Author");
            if (authorNode != null)
            {
                Console.WriteLine("Author: " + authorNode.InnerText);
            }
        }
    }
}

这里,通过Load方法加载XML文档,然后使用GetElementsByTagName获取所有的Book节点。遍历这些节点时,获取Title属性和Author子节点的文本内容并输出。

使用XmlReader

XmlReader提供了一种快速、只进的方式来读取XML数据,适合处理大型XML文件,因为它不会将整个文档加载到内存中。以下是一个示例:

using System;
using System.Xml;

class Program
{
    static void Main()
    {
        using (XmlReader reader = XmlReader.Create("books.xml"))
        {
            while (reader.Read())
            {
                if (reader.NodeType == XmlNodeType.Element && reader.Name == "Book")
                {
                    Console.WriteLine("Book:");
                    Console.WriteLine("  Title: " + reader.GetAttribute("Title"));
                    while (reader.Read())
                    {
                        if (reader.NodeType == XmlNodeType.Element && reader.Name == "Author")
                        {
                            reader.Read();
                            Console.WriteLine("  Author: " + reader.Value);
                            break;
                        }
                    }
                }
            }
        }
    }
}

在上述代码中,通过XmlReader.Create方法创建一个XmlReader实例来读取books.xml文件。在while (reader.Read())循环中,当遇到Book元素节点时,获取其Title属性。然后,在内部循环中找到Author元素节点并获取其文本值。

XML数据处理的高级操作

XPath查询

XPath(XML路径语言)是一种用于在XML文档中定位节点的语言。在C#中,XmlDocumentXmlNode类都支持XPath查询。以下是一个示例:

using System;
using System.Xml;

class Program
{
    static void Main()
    {
        XmlDocument doc = new XmlDocument();
        doc.Load("books.xml");

        // 使用XPath查询获取所有作者为John Doe的书
        XmlNodeList nodes = doc.SelectNodes("//Book[Author='John Doe']");
        foreach (XmlNode node in nodes)
        {
            XmlAttribute titleAttr = node.Attributes["Title"];
            if (titleAttr != null)
            {
                Console.WriteLine("Title: " + titleAttr.Value);
            }
        }
    }
}

在上述代码中,doc.SelectNodes("//Book[Author='John Doe']")表示在整个XML文档中查找所有Author子节点文本为John DoeBook节点。然后遍历这些节点并输出其Title属性。

XML Schema验证

XML Schema定义了XML文档的结构和数据类型。在C#中,可以使用XmlReaderSettings类来进行XML Schema验证。假设我们有一个books.xsd文件定义了books.xml的结构:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="Books">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="Book" maxOccurs="unbounded">
                    <xs:complexType>
                        <xs:sequence>
                            <xs:element name="Author" type="xs:string"/>
                        </xs:sequence>
                        <xs:attribute name="Title" type="xs:string" use="required"/>
                    </xs:complexType>
                </xs:element>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
</xs:schema>

以下是验证books.xml是否符合books.xsd的代码:

using System;
using System.Xml;

class Program
{
    static void Main()
    {
        XmlReaderSettings settings = new XmlReaderSettings();
        settings.Schemas.Add(null, "books.xsd");
        settings.ValidationType = ValidationType.Schema;

        settings.ValidationEventHandler += (sender, args) =>
        {
            Console.WriteLine("Validation error: " + args.Message);
        };

        using (XmlReader reader = XmlReader.Create("books.xml", settings))
        {
            while (reader.Read()) { }
        }
    }
}

在上述代码中,创建了一个XmlReaderSettings实例,添加了books.xsd Schema,并设置验证类型为Schema。通过注册ValidationEventHandler事件来处理验证错误。在读取XML文档时,XmlReader会根据Schema进行验证并触发相应事件。

XML序列化与反序列化

XML序列化是将对象转换为XML格式,反序列化则是将XML转换回对象。在C#中,可以使用XmlSerializer类。假设我们有一个Book类:

using System.Xml.Serialization;

[XmlRoot("Book")]
public class Book
{
    [XmlAttribute("Title")]
    public string Title { get; set; }

    [XmlElement("Author")]
    public string Author { get; set; }
}

以下是序列化和反序列化的示例:

using System;
using System.IO;
using System.Xml.Serialization;

class Program
{
    static void Main()
    {
        // 序列化
        Book book = new Book { Title = "C# Basics", Author = "Alice Johnson" };
        XmlSerializer serializer = new XmlSerializer(typeof(Book));
        using (StreamWriter writer = new StreamWriter("book.xml"))
        {
            serializer.Serialize(writer, book);
        }

        // 反序列化
        using (StreamReader reader = new StreamReader("book.xml"))
        {
            Book deserializedBook = (Book)serializer.Deserialize(reader);
            Console.WriteLine("Title: " + deserializedBook.Title);
            Console.WriteLine("Author: " + deserializedBook.Author);
        }
    }
}

在上述代码中,首先创建一个Book对象并进行序列化,将其保存为book.xml文件。然后,从book.xml文件中反序列化出Book对象并输出其属性值。

C#中JSON数据处理基础

JSON简介

JSON(JavaScript对象表示法)是一种轻量级的数据交换格式,易于阅读和编写,也易于机器解析和生成。在C#中,处理JSON数据通常使用System.Text.Json命名空间(.NET 5.0及以上)或Newtonsoft.Json库(适用于更早版本)。

使用System.Text.Json

在.NET 5.0及以上版本,可以使用System.Text.Json命名空间中的类来处理JSON。以下是一个简单的示例,展示如何将对象序列化为JSON字符串以及将JSON字符串反序列化为对象:

using System;
using System.Text.Json;

class Program
{
    class Book
    {
        public string Title { get; set; }
        public string Author { get; set; }
    }

    static void Main()
    {
        // 序列化
        Book book = new Book { Title = "C# in Depth", Author = "Jon Skeet" };
        string jsonString = JsonSerializer.Serialize(book);
        Console.WriteLine(jsonString);

        // 反序列化
        Book deserializedBook = JsonSerializer.Deserialize<Book>(jsonString);
        Console.WriteLine("Title: " + deserializedBook.Title);
        Console.WriteLine("Author: " + deserializedBook.Author);
    }
}

在上述代码中,定义了一个Book类。通过JsonSerializer.Serialize方法将Book对象序列化为JSON字符串,然后使用JsonSerializer.Deserialize方法将JSON字符串反序列化为Book对象。

使用Newtonsoft.Json

Newtonsoft.Json库是一个广泛使用的处理JSON的第三方库,在.NET Framework以及较旧的.NET Core版本中使用较多。首先,需要通过NuGet安装Newtonsoft.Json包。以下是使用该库的示例:

using System;
using Newtonsoft.Json;

class Program
{
    class Book
    {
        public string Title { get; set; }
        public string Author { get; set; }
    }

    static void Main()
    {
        // 序列化
        Book book = new Book { Title = "Effective C#", Author = "Bill Wagner" };
        string jsonString = JsonConvert.SerializeObject(book);
        Console.WriteLine(jsonString);

        // 反序列化
        Book deserializedBook = JsonConvert.DeserializeObject<Book>(jsonString);
        Console.WriteLine("Title: " + deserializedBook.Title);
        Console.WriteLine("Author: " + deserializedBook.Author);
    }
}

这里,使用JsonConvert.SerializeObject方法进行序列化,JsonConvert.DeserializeObject方法进行反序列化,与System.Text.Json的使用方式类似,但使用的是Newtonsoft.Json库中的类。

JSON数据处理的高级操作

自定义序列化和反序列化

在某些情况下,可能需要自定义对象的序列化和反序列化过程。使用System.Text.Json时,可以通过继承JsonConverter类来实现自定义转换。以下是一个示例,假设我们有一个包含日期的Book类,并且希望以特定格式序列化日期:

using System;
using System.Text.Json;
using System.Text.Json.Serialization;

class Program
{
    class Book
    {
        public string Title { get; set; }
        public string Author { get; set; }
        public DateTime PublishedDate { get; set; }
    }

    class CustomDateConverter : JsonConverter<DateTime>
    {
        public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            return DateTime.Parse(reader.GetString());
        }

        public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
        {
            writer.WriteStringValue(value.ToString("yyyy - MM - dd"));
        }
    }

    static void Main()
    {
        Book book = new Book
        {
            Title = "C# 8.0 in a Nutshell",
            Author = "Joseph Albahari",
            PublishedDate = new DateTime(2020, 1, 1)
        };

        JsonSerializerOptions options = new JsonSerializerOptions();
        options.Converters.Add(new CustomDateConverter());

        string jsonString = JsonSerializer.Serialize(book, options);
        Console.WriteLine(jsonString);

        Book deserializedBook = JsonSerializer.Deserialize<Book>(jsonString, options);
        Console.WriteLine("Title: " + deserializedBook.Title);
        Console.WriteLine("Author: " + deserializedBook.Author);
        Console.WriteLine("PublishedDate: " + deserializedBook.PublishedDate.ToString("yyyy - MM - dd"));
    }
}

在上述代码中,定义了一个CustomDateConverter类继承自JsonConverter<DateTime>。重写了ReadWrite方法来实现自定义的日期序列化和反序列化。在Main方法中,将该转换器添加到JsonSerializerOptions中,然后进行序列化和反序列化操作。

使用Newtonsoft.Json时,可以通过JsonConverter特性来实现类似功能。以下是使用Newtonsoft.Json的示例:

using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;

class Program
{
    class Book
    {
        public string Title { get; set; }
        public string Author { get; set; }
        [JsonConverter(typeof(CustomDateConverter))]
        public DateTime PublishedDate { get; set; }
    }

    class CustomDateConverter : IsoDateTimeConverter
    {
        public CustomDateConverter()
        {
            DateTimeFormat = "yyyy - MM - dd";
        }
    }

    static void Main()
    {
        Book book = new Book
        {
            Title = "C# 9.0 and .NET 5 - Modern Cross - Platform Development",
            Author = "Mark J. Price",
            PublishedDate = new DateTime(2021, 1, 1)
        };

        string jsonString = JsonConvert.SerializeObject(book);
        Console.WriteLine(jsonString);

        Book deserializedBook = JsonConvert.DeserializeObject<Book>(jsonString);
        Console.WriteLine("Title: " + deserializedBook.Title);
        Console.WriteLine("Author: " + deserializedBook.Author);
        Console.WriteLine("PublishedDate: " + deserializedBook.PublishedDate.ToString("yyyy - MM - dd"));
    }
}

这里,通过继承IsoDateTimeConverter并设置DateTimeFormat来实现自定义日期格式。然后使用JsonConverter特性将该转换器应用到PublishedDate属性上。

处理复杂JSON结构

当处理复杂的JSON结构时,例如包含嵌套对象或数组的JSON,需要正确定义对应的C#类结构。假设我们有如下复杂的JSON数据:

{
    "store": {
        "books": [
            {
                "title": "JavaScript: The Definitive Guide",
                "author": "David Flanagan",
                "price": 35.99
            },
            {
                "title": "Learning JavaScript Design Patterns",
                "author": "Addy Osmani",
                "price": 24.99
            }
        ],
        "bicycles": {
            "brand": "Giant",
            "models": [
                {
                    "name": "Escape",
                    "price": 599.99
                },
                {
                    "name": "Defy",
                    "price": 1299.99
                }
            ]
        }
    }
}

对应的C#类结构可以定义如下:

using System;
using System.Collections.Generic;
using System.Text.Json.Serialization;

class Program
{
    class Store
    {
        public List<Book> books { get; set; }
        public Bicycle bicycles { get; set; }
    }

    class Book
    {
        public string title { get; set; }
        public string author { get; set; }
        public double price { get; set; }
    }

    class Bicycle
    {
        public string brand { get; set; }
        public List<BicycleModel> models { get; set; }
    }

    class BicycleModel
    {
        public string name { get; set; }
        public double price { get; set; }
    }

    static void Main()
    {
        string json = @"{
            ""store"": {
                ""books"": [
                    {
                        ""title"": ""JavaScript: The Definitive Guide"",
                        ""author"": ""David Flanagan"",
                        ""price"": 35.99
                    },
                    {
                        ""title"": ""Learning JavaScript Design Patterns"",
                        ""author"": ""Addy Osmani"",
                        ""price"": 24.99
                    }
                ],
                ""bicycles"": {
                    ""brand"": ""Giant"",
                    ""models"": [
                        {
                            ""name"": ""Escape"",
                            ""price"": 599.99
                        },
                        {
                            ""name"": ""Defy"",
                            ""price"": 1299.99
                        }
                    ]
                }
            }
        }";

        Store store = JsonSerializer.Deserialize<Store>(json);

        Console.WriteLine("Books:");
        foreach (var book in store.books)
        {
            Console.WriteLine($"Title: {book.title}, Author: {book.author}, Price: {book.price}");
        }

        Console.WriteLine("\nBicycles:");
        Console.WriteLine($"Brand: {store.bicycles.brand}");
        foreach (var model in store.bicycles.models)
        {
            Console.WriteLine($"Model: {model.name}, Price: {model.price}");
        }
    }
}

在上述代码中,定义了多个类来匹配JSON的结构。通过JsonSerializer.Deserialize方法将JSON字符串反序列化为Store对象,然后可以方便地访问和处理其中的数据。

XML与JSON的比较与选择

数据结构和可读性

XML使用树形结构,标签和嵌套层次清晰,对于复杂的数据关系和结构化数据表示较为直观,可读性较好,尤其适合需要严格定义结构和数据类型的场景,如配置文件和数据交换。例如,一个描述图书目录的XML文件:

<Catalog>
    <Book>
        <Title>C# Programming</Title>
        <Author>John Doe</Author>
        <PublicationYear>2023</PublicationYear>
    </Book>
    <Book>
        <Title>Advanced C#</Title>
        <Author>Jane Smith</Author>
        <PublicationYear>2024</PublicationYear>
    </Book>
</Catalog>

JSON使用键值对和数组,结构相对扁平,对于简单的数据表示非常简洁,易于阅读和编写。例如,同样的图书目录用JSON表示:

{
    "Catalog": [
        {
            "Title": "C# Programming",
            "Author": "John Doe",
            "PublicationYear": 2023
        },
        {
            "Title": "Advanced C#",
            "Author": "Jane Smith",
            "PublicationYear": 2024
        }
    ]
}

JSON在简单数据场景下更简洁,而XML在复杂层次结构数据上更具优势。

数据量和性能

在数据量较小的情况下,XML和JSON的性能差异不明显。但随着数据量的增加,JSON通常在序列化和反序列化速度上更快,因为它的结构更简单,解析和生成相对容易。XML由于需要处理标签、属性等信息,在处理大数据量时性能可能会稍逊一筹。例如,在处理包含大量商品信息的文件时,JSON格式的数据加载和处理速度会更快。

应用场景

XML常用于企业级应用、数据交换和配置文件,因为它具有严格的Schema定义和良好的结构化特性,能够确保数据的一致性和完整性。例如,企业间的数据交互、数据库的配置文件等场景经常使用XML。

JSON则广泛应用于Web应用开发,尤其是在前后端数据交互中。由于JavaScript对JSON的原生支持,JSON在Web环境中传输和解析非常方便,能够快速地在客户端和服务器之间传递数据。例如,RESTful API接口返回的数据格式大多为JSON。

在选择使用XML还是JSON时,需要综合考虑数据的复杂度、数据量、应用场景以及与其他系统的兼容性等因素。如果需要严格的数据结构定义和处理复杂层次关系,XML可能是更好的选择;如果追求简洁、快速的数据传输和处理,尤其是在Web应用中,JSON则更为合适。