我正在尝试使用XDocument类和XmlSchemaSet类来验证XMl文件。
XML文件已经存在,但我只想添加一个由其他几个元素组成的元素,我只想验证这个节点。
下面是XML文件的一个示例。我想验证的部分是TestConfiguration
节点:
<?xml version="1.0" encoding="ISO-8859-1"?>
<Root>
<AppType>Test App</AppType>
<LabelMap>
<Label0>
<Title>Tests</Title>
<Indexes>1,2,3</Indexes>
</Label0>
</LabelMap>
<TestConfiguration>
<CalculateNumbers>true</CalculateNumbers>
<RoundToDecimalPoint>3</RoundToDecimalPoint>
</TestConfiguration>
</Root>
这是我迄今为止的xsd:
<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="TestConfiguration"
targetNamespace="MyApp_ConfigurationFiles" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="TestConfiguration">
<xs:complexType>
<xs:sequence>
<xs:element name="CalculateNumbers" type="xs:boolean" minOccurs="1" maxOccurs="1"/>
<xs:element name="RoundToDecimalPoint" type="xs:int" minOccurs="1" maxOccurs="1"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
这是我用来验证它的代码:
private bool ValidateXML(string xmlFile, string xsdFile)
{
string xsdFilePath = Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) ?? string.Empty, xsdFile);
Logger.Info("Validating XML file against XSD schema file.");
Logger.Info("XML: " + xmlFile);
Logger.Info("XSD: " + xsdFilePath);
try
{
XDocument xsdDocument = XDocument.Load(xsdFilePath);
XmlSchemaSet schemaSet = new XmlSchemaSet();
schemaSet.Add(XmlSchema.Read(new StringReader(xsdDocument.ToString()), this.XmlValidationEventHandler));
XDocument xmlDocument = XDocument.Load(xmlFile);
xmlDocument.Validate(schemaSet, this.XmlValidationEventHandler);
}
catch (Exception e)
{
Logger.Info("Error parsing XML file: " + xmlFile);
throw new Exception(e.Message);
}
Logger.Info("XML validated against XSD.");
return true;
}
即使验证了完整的XML文件,验证也会成功通过,这会导致我在尝试将XML文件加载到由xsd2code创建的生成类文件时遇到问题,错误为:<Root xmlns=''> was not expected.
。
如何仅验证TestConfiguration
工件?
感谢
这里有一些问题:
-
当整个文档应该失败时,验证它会成功。
发生这种情况是因为根节点对架构是未知的,遇到未知节点被视为验证警告而不是验证错误,即使该未知节点是根元素。要在验证时启用警告,需要设置
XmlSchemaValidationFlags.ReportValidationWarnings
。但是,无法将此标志传递给XDocument.Validate()
。问题XDocument。"验证总是成功的"展示了解决这一问题的一种方法。完成此操作后,还必须在
ValidationEventArgs.Severity == XmlSeverityType.Warning
时在验证处理程序中抛出异常。(至于在XSD中需要某个根元素,这显然是不可能的。)
-
您需要一种方便的方法来验证元素以及文档,这样您就可以验证
<TestConfiguration>
文章。 -
您的XSD和XML不一致。
XSD指定元素位于
targetNamespace="MyApp_ConfigurationFiles" elementFormDefault="qualified"
行的XML命名空间MyApp_ConfigurationFiles
中。事实上,问题中显示的XML元素不在任何命名空间中。如果XSD是正确的,那么您的XML根节点需要看起来像:
<Root xmlns="MyApp_ConfigurationFiles">
如果XML是正确的,那么XSD需要看起来像:
<xs:schema id="TestConfiguration" elementFormDefault="unqualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
在解决了#3中的XSD和XML不一致性之后,可以通过引入以下验证文档和元素的扩展方法来解决问题#1和#2:
public static class XNodeExtensions
{
public static void Validate(this XContainer node, XmlReaderSettings settings)
{
if (node == null)
throw new ArgumentNullException();
using (var innerReader = node.CreateReader())
using (var reader = XmlReader.Create(innerReader, settings))
{
while (reader.Read())
;
}
}
public static void Validate(this XContainer node, XmlSchemaSet schemaSet, XmlSchemaValidationFlags validationFlags, ValidationEventHandler validationEventHandler)
{
var settings = new XmlReaderSettings();
settings.ValidationType = ValidationType.Schema;
settings.ValidationFlags |= validationFlags;
if (validationEventHandler != null)
settings.ValidationEventHandler += validationEventHandler;
settings.Schemas = schemaSet;
node.Validate(settings);
}
}
然后,要验证整个文档,请执行以下操作:
try
{
var xsdDocument = XDocument.Load(xsdFilePath);
var schemaSet = new XmlSchemaSet();
using (var xsdReader = xsdDocument.CreateReader())
schemaSet.Add(XmlSchema.Read(xsdReader, this.XmlSchemaEventHandler));
var xmlDocument = XDocument.Load(xmlFile);
xmlDocument.Validate(schemaSet, XmlSchemaValidationFlags.ReportValidationWarnings, XmlValidationEventHandler);
}
catch (Exception e)
{
Logger.Info("Error parsing XML file: " + xmlFile);
throw new Exception(e.Message);
}
要验证特定节点,可以使用相同的扩展方法:
XNamespace elementNamespace = "MyApp_ConfigurationFiles";
var elementName = elementNamespace + "TestConfiguration";
try
{
var xsdDocument = XDocument.Load(xsdFilePath);
var schemaSet = new XmlSchemaSet();
using (var xsdReader = xsdDocument.CreateReader())
schemaSet.Add(XmlSchema.Read(xsdReader, this.XmlSchemaEventHandler));
var xmlDocument = XDocument.Load(xmlFile);
var element = xmlDocument.Root.Element(elementName);
element.Validate(schemaSet, XmlSchemaValidationFlags.ReportValidationWarnings, this.XmlValidationEventHandler);
}
catch (Exception e)
{
Logger.Info(string.Format("Error validating element {0} of XML file: {1}", elementName, xmlFile));
throw new Exception(e.Message);
}
现在验证整个文档失败,而验证{MyApp_ConfigurationFiles}TestConfiguration
节点成功,使用以下验证事件处理程序:
void XmlSchemaEventHandler(object sender, ValidationEventArgs e)
{
if (e.Severity == XmlSeverityType.Error)
throw new XmlException(e.Message);
else if (e.Severity == XmlSeverityType.Warning)
Logger.Info(e.Message);
}
void XmlValidationEventHandler(object sender, ValidationEventArgs e)
{
if (e.Severity == XmlSeverityType.Error)
throw new XmlException(e.Message);
else if (e.Severity == XmlSeverityType.Warning)
throw new XmlException(e.Message);
}