为何C#中XSD未自动触发必填字段等验证异常?
我的XML文件存在以下不符合XSD规则的问题:
- 部分
<Record>元素缺失必填的logical属性 is_city_saver属性使用了"Yes"而非合法布尔值true/false- 部分
logical属性值为非数字(如"dt")
但使用C#代码校验时,XML竟通过了验证,未抛出任何错误,调试时还出现attributeSchemaInfo空引用异常,现分析原因并给出解决办法。
待校验的XML文件
<?xml version="1.0" encoding="utf-8"?> <Zones xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.keaneaustralia.com/Nts" xsi:schemaLocation="http://schemas.keaneaustralia.com/Nts Zones.xsd" version="1" major_version="434" minor_version="0" start_date="2023-07-09T00:00:00+10:00"> <Record long_desc="City Saver Zone"/> <Record logical="2" physical="1" short_desc="Zone 1" long_desc="Zone 1" is_city_saver="Yes" /> <Record logical="3" physical="2" short_desc="Zone 2" long_desc="Zone 2" is_city_saver="false" /> <Record logical="dt" physical="3" short_desc="Zone 3" long_desc="Zone 3" is_city_saver="false" /> <Record logical="5" physical="4" short_desc="Zone 4" long_desc="Zone 4" is_city_saver="false" /> <Record logical="6" physical="5" short_desc="Zone 5" long_desc="Zone 5" is_city_saver="false" /> </Zones>
对应的XSD Schema
<?xml version="1.0" encoding="utf-8"?> <xs:schema xmlns:tns="http://schemas.keaneaustralia.com/Nts" elementFormDefault="qualified" targetNamespace="http://schemas.keaneaustralia.com/Nts" xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="Zones" nillable="true" type="tns:ZoneCollection" /> <xs:complexType name="ZoneCollection"> <xs:complexContent mixed="false"> <xs:extension base="tns:DataElementOfZone" /> </xs:complexContent> </xs:complexType> <xs:complexType name="DataElementOfZone"> <xs:sequence> <xs:element minOccurs="0" maxOccurs="unbounded" name="Record" type="tns:Zone" /> </xs:sequence> <xs:attribute name="version" type="xs:int" use="required" /> <xs:attribute name="major_version" type="xs:int" use="required" /> <xs:attribute name="minor_version" type="xs:int" use="required" /> <xs:attribute name="start_date" type="xs:dateTime" use="required" /> <xs:attribute default="false" name="is_delta" type="xs:boolean" /> <xs:attribute default="0" name="delta_major_version" type="xs:int" /> <xs:attribute default="0" name="delta_minor_version" type="xs:int" /> </xs:complexType> <xs:complexType name="Zone"> <xs:attribute name="logical" type="xs:unsignedByte" use="required" /> <xs:attribute name="physical" type="xs:unsignedByte" use="required" /> <xs:attribute name="short_desc" type="xs:string" /> <xs:attribute name="long_desc" type="xs:string" /> <xs:attribute name="is_city_saver" type="xs:boolean" use="required" /> </xs:complexType> </xs:schema>
用于校验的C#代码
private static bool ValidateXmlAgainstXsd(string xmlFilePath, string xsdFilePath, ILogger fileLogger) { try { int numErreur = 0; XmlSchemaSet schemaSet = new XmlSchemaSet(); schemaSet.Add(null, xsdFilePath); schemaSet.Compile(); XmlReaderSettings settings = new XmlReaderSettings(); settings.Schemas.Add(schemaSet); settings.ValidationType = ValidationType.Schema; settings.ValidationFlags = XmlSchemaValidationFlags.ReportValidationWarnings | XmlSchemaValidationFlags.ProcessIdentityConstraints | XmlSchemaValidationFlags.ProcessInlineSchema; settings.ValidationEventHandler += (sender, e) => { LogValidationError(xmlFilePath, e.Message, e.Exception, e.Exception.LineNumber, e.Exception.LinePosition, e.Severity, fileLogger, ref numErreur); }; using (XmlReader reader = XmlReader.Create(xmlFilePath, settings)) { while (reader.Read()) { //process code } } return numErreur > 0 ? false : true; } catch (Exception ex) { Console.WriteLine($"Error validating XML '{xmlFilePath}' against XSD '{xsdFilePath}': {ex.Message}"); return false; } }
问题原因分析
命名空间匹配错误:
XSD中Record元素属于目标命名空间http://schemas.keaneaustralia.com/Nts,但代码中XmlSchemaSet.Add(null, xsdFilePath)未指定命名空间,导致校验器无法将XML中的Record与XSD中的tns:Zone类型关联,直接跳过了属性规则校验。ValidationFlags缺少关键选项:
未启用XmlSchemaValidationFlags.ProcessSchemaLocation,校验器会忽略XML中的xsi:schemaLocation声明,影响Schema关联的完整性。attributeSchemaInfo空引用:
当校验器未正确关联Schema时,reader.AttributeSchemaInfo返回null,若调试时直接访问该属性会触发空引用异常。
解决办法
1. 修正Schema集合的命名空间关联
将schemaSet.Add(null, xsdFilePath)改为指定XSD的目标命名空间,确保校验器能正确匹配XML元素:
schemaSet.Add("http://schemas.keaneaustralia.com/Nts", xsdFilePath);
2. 补充ValidationFlags必要选项
添加ProcessSchemaLocation,确保校验器处理XML中的Schema位置声明:
settings.ValidationFlags = XmlSchemaValidationFlags.ReportValidationWarnings | XmlSchemaValidationFlags.ProcessIdentityConstraints | XmlSchemaValidationFlags.ProcessInlineSchema | XmlSchemaValidationFlags.ProcessSchemaLocation;
3. 修复日志方法中的空引用问题
在LogValidationError调用前,先判断e.Exception是否为null,避免空引用:
int lineNumber = e.Exception?.LineNumber ?? 0; int linePosition = e.Exception?.LinePosition ?? 0; LogValidationError(xmlFilePath, e.Message, e.Exception, lineNumber, linePosition, e.Severity, fileLogger, ref numErreur);
4. 验证修正效果
修改后重新校验XML,会正确触发以下错误:
- 第一个
<Record>缺失logical、physical、is_city_saver必填属性 - 第二个
<Record>的is_city_saver="Yes"不符合布尔值格式 - 第四个
<Record>的logical="dt"不符合xs:unsignedByte类型要求
内容的提问来源于stack exchange,提问作者Ayushi Ramsurn

