C#提取XML嵌套节点遍历所有订单行批量插入SQL的问题
代码问题修正方案
核心问题定位
- 遍历逻辑缺失:当前代码通过
FirstOrDefault()只取了OrderLineCollection下第一个OrderLine节点的ProductCode,没有对所有订单行节点做循环处理,因此只会插入第一条产品数据。 - 节点路径匹配错误:提取
Type字段(对应XML中的DocketSubType)时,代码错误查找了不存在的Type节点,实际XML中对应路径为Order/DocketSubType/Code,该字段值实际永远为空。 - SQL传参逻辑缺失:原有拼接的SQL语句没有传入
ProductCode参数,即使拿到了所有产品编码也无法写入数据库。 - 路径写法冗余:
XDocument加载完成后,Root属性已经对应最外层的UniversalShipment节点,从xmlDocument下再嵌套查找UniversalShipment属于多写了一层无效路径。 - SQL拼接存在风险:通过字符串拼接生成SQL的方式,遇到字段值包含单引号、特殊字符会直接报错,且存在SQL注入隐患,需要替换为参数化查询。
修正后的可运行逻辑
1. 提取订单公共字段
先定位节点路径,提取所有与具体订单行无关的公共字段(这些字段在同一张订单的所有行中值完全一致,只需提取一次):
// 直接从根节点定位Shipment、Order,避免冗余长路径 XElement shipmentNode = xmlDocument.Root.Element(ns + "Shipment"); XElement orderNode = shipmentNode?.Element(ns + "Order"); // 定位对应类型的Client节点 XElement clientNode = shipmentNode.Descendants(ns + "OrganizationAddress") .FirstOrDefault(x => x.Element(ns + "AddressType")?.Value == "SendersLocalClient"); // 提取公共字段 string client = clientNode?.Element(ns + "CompanyName")?.Value; string warehouse = orderNode?.Element(ns + "Warehouse")?.Element(ns + "Name")?.Value; string orderReference = orderNode?.Element(ns + "OrderNumber")?.Value; string customerReference = orderNode?.Element(ns + "ClientReference")?.Value; string orderType = orderNode?.Element(ns + "DocketSubType")?.Element(ns + "Code")?.Value;
2. 循环遍历所有订单行完成插入
所有订单行共用同一个数据库连接,避免重复打开/关闭连接的性能损耗,逐行提取ProductCode并传参插入:
// 获取所有订单行节点,为空时返回空集合避免空引用报错 IEnumerable<XElement> orderLineNodes = orderNode?.Element(ns + "OrderLineCollection") ?.Elements(ns + "OrderLine") ?? Enumerable.Empty<XElement>(); string connectionString = "Data Source=My Server;Initial Catalog=MyDB;User ID=MyUser;Password=MyPassword"; // using语法自动释放数据库连接资源 using (SqlConnection connection = new SqlConnection(connectionString)) { connection.Open(); // 提前初始化命令对象,循环内只改参数值,不重复新建命令 using (SqlCommand command = new SqlCommand("InsertXML", connection)) { command.CommandType = CommandType.StoredProcedure; // 绑定存储过程参数 command.Parameters.Add("@Client", SqlDbType.NVarChar, 100); command.Parameters.Add("@Warehouse", SqlDbType.NVarChar, 100); command.Parameters.Add("@OrderReference", SqlDbType.NVarChar, 50); command.Parameters.Add("@CustomerReference", SqlDbType.NVarChar, 50); command.Parameters.Add("@Type", SqlDbType.NVarChar, 50); command.Parameters.Add("@ProductCode", SqlDbType.NVarChar, 50); // 逐行遍历订单行 foreach (XElement line in orderLineNodes) { string productCode = line.Element(ns + "Product")?.Element(ns + "Code")?.Value; if (string.IsNullOrEmpty(productCode)) continue; // 跳过无效空行 // 给参数赋值 command.Parameters["@Client"].Value = client; command.Parameters["@Warehouse"].Value = warehouse; command.Parameters["@OrderReference"].Value = orderReference; command.Parameters["@CustomerReference"].Value = customerReference; command.Parameters["@Type"].Value = orderType; command.Parameters["@ProductCode"].Value = productCode; // 执行插入 command.ExecuteNonQuery(); } } }
批量处理文件夹下上千个XML的扩展方法
后续扩展批量能力时,只需在最外层增加文件遍历逻辑即可:
- 用
Directory.EnumerateFiles("你的XML文件夹路径", "*.xml")拿到所有XML文件的完整路径 - 对每个文件加载XDocument,执行上述提取、插入逻辑
- 增加基础异常捕获,遇到损坏、格式不符的XML文件跳过处理,不中断整体批量流程
内容的提问来源于stack exchange,提问作者Seb Soum
相关产品推荐
相关产品推荐

