使用 XSD 验证部分 XML 文件 [英] Partial XML file validation using XSD
问题描述
我正在尝试使用 XDocument 类和 XmlSchemaSet 类来验证 XMl 文件.
XML 文件已经存在,但我只想添加一个由其他几个元素组成的元素,我只想验证这个节点.
这是 XML 文件的示例.我想验证的部分是 TestConfiguration
节点:
<根><AppType>测试应用</AppType><标签地图><标签0><Title>测试</Title><索引>1,2,3</索引></Label0></LabelMap><测试配置><CalculateNumbers>true</CalculateNumbers><RoundToDecimalPoint>3</RoundToDecimalPoint></TestConfiguration></Root>
到目前为止,这是我的 xsd:
<xs:element name="TestConfiguration"><xs:complexType><xs:序列><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("根据 XSD 架构文件验证 XML 文件.");Logger.Info("XML:" + xmlFile);Logger.Info("XSD:" + xsdFilePath);尝试{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);}捕获(例外 e){Logger.Info("解析 XML 文件时出错:" + xmlFile);抛出新的异常(e.Message);}Logger.Info("XML 针对 XSD 进行了验证.");返回真;}
即使验证完整的 XML 文件,验证也会成功通过,导致我在尝试将 XML 文件加载到 xsd2code 创建的生成的类文件中时遇到问题,错误:<Root xmlns=''>不是预期的.
.
如何仅验证 TestConfiguration
部分?
谢谢
这里有几个问题:
当整个文档应该失败时验证它会成功.
发生这种情况是因为模式未知根节点,遇到未知节点被视为验证警告而不是验证错误 - 即使该未知节点是根元素.要在验证时启用警告,您需要设置
XmlSchemaValidationFlags.ReportValidationWarnings
.但是,无法将此标志传递给 <代码>XDocument.Validate().问题 XDocument.Validate 总是成功 显示了一种解决此问题的方法.>完成此操作后,当
ValidationEventArgs.Severity == XmlSeverityType.Warning
时,您还必须在验证处理程序中抛出异常.(至于在 XSD 中要求某个根元素,这显然是不可能的.)
您需要一种方便的方法来验证 元素 以及文档,以便验证您的
部分.您的 XSD 和 XML 不一致.
您的 XSD 指定您的元素位于
targetNamespace="MyApp_ConfigurationFiles" elementFormDefault="qualified"
行中的 XML 命名空间MyApp_ConfigurationFiles
中.事实上,您的问题中显示的 XML 元素不在任何命名空间中.如果 XSD 正确,您的 XML 根节点需要如下所示:
如果 XML 正确,您的 XSD 需要如下所示:
解决 #3 中的 XSD 和 XML 不一致后,您可以通过引入以下验证文档和元素的扩展方法来解决问题 #1 和 #2:
公共静态类 XNodeExtensions{public static void Validate(这个XContainer节点,XmlReaderSettings设置){如果(节点==空)抛出新的 ArgumentNullException();使用 (var innerReader = node.CreateReader())使用 (var reader = XmlReader.Create(innerReader, settings)){而 (reader.Read());}}public static void Validate(这个XContainer节点,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;节点验证(设置);}}
然后,要验证整个文档,请执行以下操作:
试试{var xsdDocument = XDocument.Load(xsdFilePath);var schemaSet = new XmlSchemaSet();使用 (var xsdReader = xsdDocument.CreateReader())schemaSet.Add(XmlSchema.Read(xsdReader, this.XmlSchemaEventHandler));var xmlDocument = XDocument.Load(xmlFile);xmlDocument.Validate(schemaSet, XmlSchemaValidationFlags.ReportValidationWarnings, XmlValidationEventHandler);}捕获(例外 e){Logger.Info("解析 XML 文件时出错:" + xmlFile);抛出新的异常(e.Message);}
并且要验证特定节点,您可以使用相同的扩展方法:
XNamespace elementNamespace = "MyApp_ConfigurationFiles";var elementName = elementNamespace + "TestConfiguration";尝试{var xsdDocument = XDocument.Load(xsdFilePath);var schemaSet = new XmlSchemaSet();使用 (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);}捕获(例外 e){Logger.Info(string.Format("Error validating element {0} of XML file: {1}", elementName, xmlFile));抛出新的异常(e.Message);}
现在验证整个文档失败,而验证 {MyApp_ConfigurationFiles}TestConfiguration
节点成功,使用以下验证事件处理程序:
void XmlSchemaEventHandler(object sender, ValidationEventArgs e){if (e.Severity == XmlSeverityType.Error)抛出新的 XmlException(e.Message);否则如果(e.Severity == XmlSeverityType.Warning)Logger.Info(e.Message);}void XmlValidationEventHandler(object sender, ValidationEventArgs e){if (e.Severity == XmlSeverityType.Error)抛出新的 XmlException(e.Message);否则如果(e.Severity == XmlSeverityType.Warning)抛出新的 XmlException(e.Message);}
I am trying to use the XDocument class and XmlSchemaSet class to validate an XMl file.
The XML file already exists but I want to add in just a single element consisting of a couple other elements and I only want to validate this node.
Here is an example of the XML file. The piece I would like to validate is the TestConfiguration
node:
<?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>
Here is my xsd so far:
<?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>
Here is the code I use to validate it:
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;
}
Even validating the full XML file, the validation will pass successfully causing me to run into problems when I try to load the XML file into the generated class file created by xsd2code, the error: <Root xmlns=''> was not expected.
.
How can I validate just the TestConfiguration
piece?
Thanks
You have a few issues here:
Validating the entire document succeeds when it should fail.
This happens because the root node is unknown to the schema, and encountering an unknown node is considered a validation warning not a validation error - even if that unknown node is the root element. To enable warnings while validating, you need to set
XmlSchemaValidationFlags.ReportValidationWarnings
. However, there's no way to pass this flag toXDocument.Validate()
. The question XDocument.Validate is always successful shows one way to work around this.Having done this, you must also throw an exception in your validation handler when
ValidationEventArgs.Severity == XmlSeverityType.Warning
.(As for requiring a certain root element in your XSD, this is apparently not possible.)
You need a convenient way to validate elements as well as documents, so you can validate your
<TestConfiguration>
piece.Your XSD and XML are inconsistent.
You XSD specifies that your elements are in the XML namespace
MyApp_ConfigurationFiles
in the linetargetNamespace="MyApp_ConfigurationFiles" elementFormDefault="qualified"
. In fact the XML elements shown in your question are not in any namespace.If the XSD is correct, your XML root node needs to look like:
<Root xmlns="MyApp_ConfigurationFiles">
If the XML is correct, your XSD needs to look like:
<xs:schema id="TestConfiguration" elementFormDefault="unqualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
After you have resolved the XSD and XML inconsistency from #3, you can solve issues #1 and #2 by introducing the following extension methods that validate both documents and elements:
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);
}
}
Then, to validate the entire document, do:
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);
}
And to validate a specific node, you can use the same extension methods:
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);
}
Now validating the entire document fails while validating the {MyApp_ConfigurationFiles}TestConfiguration
node succeeds, using the following validation event handlers:
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);
}
这篇关于使用 XSD 验证部分 XML 文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!