XML验证失败时如何提取父节点属性信息(C#实现)
问题:XML Schema验证失败时提取父节点属性信息
我需要编写C#代码,在XML Schema验证失败时提取属性信息。当前代码能定位到具体错误属性(比如提示“'unitCost'属性无效,空字符串不是有效的Decimal值”),但无法获取父节点的orderNumber、Lot、Sequence等属性信息,求解决方法。
XML示例
<Payload xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlVersion="1.0" createDate="2023-11-07T14:23:08" messageType="TEST"> <Orders> <OrderHeader resultsIndicator="F" orderNumber="2000100"...> <OrderDetail resultsIndicator="F" lot="1234" sequence="01"...> <OrderCostingDetail expenseCode="ADMIN"... unitCost="".../> </OrderDetail> </OrderHeader> </Orders> </Payload>
现有代码
private static void PerformValidation(XmlTextReader xmlTextReader, XmlSchemaSet schemas) { if (schemas == null) { throw new ArgumentNullException("schemas"); } XmlReaderSettings settings = new XmlReaderSettings(); settings.ValidationType = ValidationType.Schema; settings.Schemas = schemas; settings.ValidationFlags = XmlSchemaValidationFlags.ReportValidationWarnings; string chkatt = string.Empty; using (XmlReader reader = XmlReader.Create(xmlTextReader, settings)) { try { do { chkatt = string.Concat("orderNo.: ",reader.GetAttribute("orderNumber"), ", Lot:", reader.GetAttribute("lot"), ", Seq:", reader.GetAttribute("sequence")); } while (reader.Read()); } catch(Exception ex) { string error = ex.Message.ToString() + chkatt; } finally { reader.Close(); } } }
解决方案
原代码的问题在于:验证错误抛出异常时,XmlReader停在错误节点,无法回溯获取父节点属性;且chkatt仅保存最后一次读取的节点属性,并非错误发生时的上下文信息。正确的做法是通过ValidationEventHandler处理验证错误,并在读取XML时跟踪父节点的属性状态。
修改后的代码
private static void PerformValidation(XmlTextReader xmlTextReader, XmlSchemaSet schemas) { if (schemas == null) { throw new ArgumentNullException("schemas"); } XmlReaderSettings settings = new XmlReaderSettings(); settings.ValidationType = ValidationType.Schema; settings.Schemas = schemas; settings.ValidationFlags = XmlSchemaValidationFlags.ReportValidationWarnings; // 跟踪当前上下文的父节点属性 string currentOrderNumber = null; string currentLot = null; string currentSequence = null; // 注册验证事件处理器,错误发生时立即处理 settings.ValidationEventHandler += (sender, e) => { string errorContext = $"orderNo.: {currentOrderNumber}, Lot: {currentLot}, Seq: {currentSequence}"; string fullError = $"{e.Message} | 上下文信息:{errorContext}"; // 这里可以根据需求记录错误到日志或集合中 Console.WriteLine(fullError); }; using (XmlReader reader = XmlReader.Create(xmlTextReader, settings)) { while (reader.Read()) { switch (reader.NodeType) { case XmlNodeType.Element: // 遇到目标节点时记录属性值 if (reader.Name == "OrderHeader") { currentOrderNumber = reader.GetAttribute("orderNumber"); } else if (reader.Name == "OrderDetail") { currentLot = reader.GetAttribute("lot"); currentSequence = reader.GetAttribute("sequence"); } break; case XmlNodeType.EndElement: // 离开节点时清空对应属性,避免上下文混乱 if (reader.Name == "OrderHeader") { currentOrderNumber = null; } else if (reader.Name == "OrderDetail") { currentLot = null; currentSequence = null; } break; } } } }
关键说明
- ValidationEventHandler:替代try-catch捕获异常,能在验证错误发生时立即触发,保留当前的XML读取上下文。
- 上下文跟踪:通过读取元素的开始/结束节点,维护当前有效的
orderNumber、lot、sequence值,确保错误发生时能获取到对应的父节点属性。 - 避免回溯:
XmlReader是向前只读的,无法直接获取父节点属性,因此必须在读取过程中主动记录上下文信息。
内容的提问来源于stack exchange,提问作者Sheva
相关产品推荐
相关产品推荐

