VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > 编程开发 > c#编程 >
  • 正则表达式——C#编写邮箱/手机号验证工具

第一部分:C#基础入门
6.LINQ to XML——订单数据XML转换
实例介绍
LINQ to XML 是.NET 3.5+引入的XML处理技术,它将LINQ查询能力与XML文档操作深度融合,相比传统的XmlDocument或XDocument(非LINQ方式),代码更简洁、类型更安全,且能直接用LINQ语法查询XML数据。
在电商、物流等系统中,订单数据的XML转换是高频场景:比如将订单对象序列vb.net教程C#教程python教程SQL教程access 2010教程
化为XML用于跨系统交换(如传给仓库管理系统),或从第三方XML格式的订单数据中解析出内部订单对象。本实例通过“订单→XML”和“XML→订单”的双向转换,结合LINQ查询XML的实战,带你掌握LINQ to XML的核心用法。
需求分析

  1. 模型定义
    需构建订单相关的实体类,反映真实业务场景:
    Order:订单主信息(订单号、客户名称、订单日期、订单详情列表);
    OrderDetail:订单详情(商品ID、商品名称、数量、单价)。
  2. 功能需求
    序列化:将Order对象(含嵌套的OrderDetail列表)转换为结构清晰的XML文档;
    反序列化:从XML文档解析出Order对象,自动处理嵌套结构;
    LINQ查询:直接对XML文档执行LINQ查询(如:找客户“张三”的所有订单、统计商品“笔记本电脑”的总销量);
    异常处理:捕获XML格式错误、缺失关键节点/属性、数据类型转换失败等异常。
  3. 测试场景
    创建包含2个订单(每个订单含2-3个详情)的测试数据;
    将订单序列化为orders.xml文件;
    从XML解析回订单对象,验证数据一致性;
    用LINQ查询XML中的目标数据。
    代码实现
    csharp
	using System;
	using System.Collections.Generic;
	using System.Linq;
	using System.Xml.Linq;
	using System.IO;
	
	namespace LinqToXmlOrderDemo
	{
	// ==================== 1. 订单相关模型 ====================
	/// <summary>
	/// 订单详情
	/// </summary>
	public class OrderDetail
	{
	public int ProductId { get; set; }
	public string ProductName { get; set; } = string.Empty;
	public int Quantity { get; set; }
	public decimal UnitPrice { get; set; }
	}
	
	/// <summary>
	/// 订单主信息
	/// </summary>
	public class Order
	{
	public string OrderId { get; set; } = string.Empty;
	public string CustomerName { get; set; } = string.Empty;
	public DateTime OrderDate { get; set; }
	public List<OrderDetail> Details { get; set; } = new List<OrderDetail>();
	}
	
	// ==================== 2. LINQ to XML转换工具类 ====================
	public static class XmlOrderConverter
	{
	/// <summary>
	/// 将Order对象序列化为XML字符串
	/// </summary>
	public static string ToXml(Order order)
	{
	if (order == null) throw new ArgumentNullException(nameof(order));
	
	// 构建XML结构:用XElement嵌套表示订单主信息和详情
	var orderElement = new XElement("Order",
	new XAttribute("OrderId", order.OrderId), // 订单号作为属性(更紧凑)
	new XElement("CustomerName", order.CustomerName),
	new XElement("OrderDate", order.OrderDate.ToString("yyyy-MM-dd HH:mm:ss")),
	// 嵌套订单详情:用LINQ Select转换Details列表为XElement集合
	new XElement("OrderDetails",
	order.Details.Select(detail =>
	new XElement("OrderDetail",
	new XElement("ProductId", detail.ProductId),
	new XElement("ProductName", detail.ProductName),
	new XElement("Quantity", detail.Quantity),
	new XElement("UnitPrice", detail.UnitPrice.ToString("F2")) // 保留两位小数
	)
	)
	)
	);
	
	// 包装为XDocument(含XML声明),并返回字符串
	var doc = new XDocument(new XDeclaration("1.0", "utf-8", "yes"), orderElement);
	return doc.ToString();
	}
	
	/// <summary>
	/// 从XML字符串解析为Order对象
	/// </summary>
	public static Order FromXml(string xml)
	{
	if (string.IsNullOrEmpty(xml)) throw new ArgumentNullException(nameof(xml));
	
	try
	{
	var orderElement = XElement.Parse(xml);
	
	// 解析订单主信息:用?.Value处理节点缺失(避免NullReferenceException)
	var order = new Order
	{
	OrderId = orderElement.Attribute("OrderId")?.Value ?? string.Empty,
	CustomerName = orderElement.Element("CustomerName")?.Value ?? string.Empty,
	OrderDate = DateTime.TryParse(orderElement.Element("OrderDate")?.Value, out var date) ? date : DateTime.MinValue
	};
	
	// 解析订单详情:用LINQ查询OrderDetails下的所有OrderDetail节点
	var details = orderElement.Element("OrderDetails")?
	.Elements("OrderDetail")
	.Select(detailElement => new OrderDetail
	{
	ProductId = int.TryParse(detailElement.Element("ProductId")?.Value, out var pid) ? pid : 0,
	ProductName = detailElement.Element("ProductName")?.Value ?? string.Empty,
	Quantity = int.TryParse(detailElement.Element("Quantity")?.Value, out var qty) ? qty : 0,
	UnitPrice = decimal.TryParse(detailElement.Element("UnitPrice")?.Value, out var price) ? price : 0m
	})
	.ToList();
	
	order.Details = details ?? new List<OrderDetail>();
	return order;
	}
	catch (XmlException ex)
	{
	throw new InvalidOperationException("XML格式错误,无法解析订单数据", ex);
	}
	catch (FormatException ex)
	{
	throw new InvalidOperationException("XML数据类型错误(如日期、数字格式不正确)", ex);
	}
	}
	
	/// <summary>
	/// LINQ查询XML:获取指定客户的所有订单(从XML文件)
	/// </summary>
	public static List<Order> GetOrdersByCustomer(string xmlFilePath, string customerName)
	{
	if (!File.Exists(xmlFilePath)) throw new FileNotFoundException("XML文件不存在", xmlFilePath);
	
	var doc = XDocument.Load(xmlFilePath);
	
	// LINQ查询语法:从XML中筛选客户名称匹配的订单
	var orders = from orderElement in doc.Descendants("Order") // 找所有Order节点(不管层级)
	where orderElement.Element("CustomerName")?.Value == customerName
	select FromXml(orderElement.ToString()); // 复用FromXml方法解析单个订单
	
	return orders.ToList();
	}
	}
	
	// ==================== 3. 测试程序 ====================
	class Program
	{
	static void Main(string[] args)
	{
	// 步骤1:创建测试订单数据
	var testOrder = new Order
	{
	OrderId = "ORD20250601001",
	CustomerName = "张三",
	OrderDate = DateTime.Now,
	Details = new List<OrderDetail>
	{
	new OrderDetail { ProductId = 1001, ProductName = "笔记本电脑", Quantity = 1, UnitPrice = 5999.00m },
	new OrderDetail { ProductId = 1002, ProductName = "无线鼠标", Quantity = 2, UnitPrice = 99.00m }
	}
	};
	
	// 步骤2:订单→XML转换
	Console.WriteLine("=== 1. 订单转XML ===");
	string orderXml = XmlOrderConverter.ToXml(testOrder);
	Console.WriteLine(orderXml);
	
	// 保存XML到文件(方便后续查询)
	string xmlFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "orders.xml");
	File.WriteAllText(xmlFilePath, orderXml, System.Text.Encoding.UTF8);
	Console.WriteLine($"
XML已保存到:{xmlFilePath}");
	
	// 步骤3:XML→订单转换
	Console.WriteLine("
=== 2. XML转订单 ===");
	Order parsedOrder = XmlOrderConverter.FromXml(orderXml);
	Console.WriteLine($"订单号:{parsedOrder.OrderId}");
	Console.WriteLine($"客户:{parsedOrder.CustomerName}");
	Console.WriteLine($"订单日期:{parsedOrder.OrderDate}");
	Console.WriteLine("订单详情:");
	foreach (var detail in parsedOrder.Details)
	{
	Console.WriteLine($" - 商品:{detail.ProductName} | 数量:{detail.Quantity} | 单价:{detail.UnitPrice:F2}");
	}
	
	// 步骤4:LINQ查询XML(找客户"张三"的订单)
	Console.WriteLine("
=== 3. LINQ查询XML:客户'张三'的订单 ===");
	var customerOrders = XmlOrderConverter.GetOrdersByCustomer(xmlFilePath, "张三");
	foreach (var order in customerOrders)
	{
	Console.WriteLine($"找到订单:{order.OrderId} | 商品数:{order.Details.Count}");
	}
	}
	}
	}

逐行讲解

  1. 模型类设计
    Order与OrderDetail:采用嵌套结构(Order包含List),贴合真实订单的业务逻辑;
    属性初始化:用?? string.Empty或默认值避免空引用,比如OrderId = ... ?? string.Empty。
  2. 订单→XML转换(ToXml方法)
    XElement构建:用new XElement("节点名", 内容)快速创建XML节点,支持嵌套(如Order包含OrderDetails);
    属性 vs 元素:订单号作为XAttribute(更紧凑,适合唯一标识),其他信息作为XElement(更易读,适合复杂内容);
    LINQ Select转换列表:order.Details.Select(detail => new XElement(...))将订单详情列表直接转为XML节点集合,替代传统循环;
    XDocument包装:添加XML声明(),确保XML格式规范。
  3. XML→订单转换(FromXml方法)
    XElement.Parse:将XML字符串解析为XElement对象(入口节点);
    安全解析:用?.Value(空条件运算符)处理节点/属性缺失,用TryParse处理数据类型转换(如DateTime.TryParse),避免程序崩溃;
    LINQ查询嵌套节点:orderElement.Element("OrderDetails")?.Elements("OrderDetail")快速获取所有订单详情节点,再用Select转换为OrderDetail对象列表。
  4. LINQ查询XML(GetOrdersByCustomer方法)
    Descendants("Order"):查找XML文档中所有层级的Order节点(区别于Elements("Order")仅找直接子节点);
    LINQ查询语法:用from...where...select直接筛选客户名称匹配的订单,复用FromXml方法解析单个订单,代码复用性高;
    延迟执行:LINQ查询直到调用ToList()才执行,节省内存。
    基础知识拓展
  5. LINQ to XML核心类
类名 作用
XElement 表示XML元素(如),是LINQ to XML的核心类,支持嵌套、属性、文本内容;
XAttribute 表示XML属性(如OrderId="ORD2025001"),依附于XElement;
XDocument 表示完整XML文档(含XML声明、根节点),适合保存或加载整个XML文件;
XDeclaration 表示XML声明();
XText 表示XML文本内容(如张三中的“张三”);
  1. LINQ to XML vs 传统XML处理
特性 LINQ to XML 传统XmlDocument
代码简洁性 极高:一行代码构建嵌套XML,直接用LINQ查询; 繁琐:需手动创建节点、遍历列表,查询用XPath(字符串易出错);
类型安全 强类型:返回XElement/XAttribute,无需强制转换; 弱类型:返回XmlNode,需手动转换为具体类型;
LINQ集成度 原生支持LINQ查询(筛选、投影、分组等); 不支持,需额外写循环或XPath;
内存占用 更高效:采用轻量级对象模型,加载速度快; 较笨重:基于DOM模型,内存占用大;
  1. 常见LINQ to XML操作
    筛选节点:doc.Descendants("OrderDetail").Where(d => d.Element("ProductName").Value == "无线鼠标");
    投影数据:doc.Descendants("OrderDetail").Select(d => new { Product = d.Element("ProductName").Value, Total = decimal.Parse(d.Element("Quantity").Value) * decimal.Parse(d.Element("UnitPrice").Value) })(计算每个商品的总销售额);
    修改节点:orderElement.Element("CustomerName").SetValue("李四")(直接修改客户名称);
    删除节点:orderElement.Element("OrderDetails").Elements("OrderDetail").Where(d => d.Element("Quantity").Value == "0").Remove()(删除数量为0的详情)。
  2. XML命名空间处理
    若XML含命名空间(如<ns:Order xmlns:ns="http://example.com/orders">),需用XNamespace处理:
csharp 
	XNamespace ns = "http://example.com/orders";
	// 创建带命名空间的节点
	var orderElement = new XElement(ns + "Order", new XAttribute(XNamespace.Xmlns + "ns", ns));
	// 查询带命名空间的节点
	var orders = doc.Descendants(ns + "Order");

扩展思考
1.批量订单处理:如何将多个Order对象序列化为一个XML文档(根节点为)?
o用new XElement("Orders", orders.Select(o => XmlOrderConverter.ToXml(o).ToXElement()))(需扩展方法将字符串转为XElement);
2.XML Schema验证:如何确保转换后的XML符合指定的XSD schema?
o用XmlSchemaSet加载XSD,然后调用orderElement.Validate(schemaSet, (sender, e) => { throw new XmlSchemaException(e.Message); });
3.大XML文件处理:若XML文件过大(如1GB),如何避免加载整个文件到内存?
o用XmlReader流式读取XML,结合LINQ to XML的XNode.ReadFrom(reader)方法逐节点处理;
4.XML与JSON互转:如何将LINQ to XML生成的XML转换为JSON?
o用System.Text.Json的JsonSerializer.Serialize(orderElement)(需将XElement转为可序列化对象),或第三方库如Newtonsoft.Json的XmlNodeConverter。
总结
LINQ to XML是处理XML数据的“瑞士军刀”——它既保留了XML的结构化优势,又融入了LINQ的强大查询能力,让XML操作从“繁琐的DOM遍历”变成“简洁的声明式查询”。本实例通过订单数据的双向转换,展示了LINQ to XML在序列化、反序列化、查询三个核心场景的用法,同时通过基础知识拓展对比了传统XML处理的不足,帮助你快速掌握这一实用技术。
在实际开发中,LINQ to XML可广泛应用于配置文件解析、跨系统数据交换、日志分析等场景,建议结合LINQ查询语法和方法链,写出高效、易维护的代码。

本站原创,转载请注明出处:https://www.xin3721.com/ArticlecSharp/c49419.html


相关教程