XmlDocument.Validate不检查无效的命名空间

时间:2011-12-15 14:07:31

标签: .net xml xsd xml-namespaces

我使用以下代码根据XSD文件验证XML文件。当找到错误并且XML文件中xmlns的值有效时,它会成功调用验证处理程序。如果它无效,则不会调用验证处理程序。

private void ui_validate_Click(object sender, EventArgs e)
{
    try
    {
        ui_output.Text = "";

        XmlDocument xml_document = new XmlDocument();
        xml_document.LoadXml(ui_XML.Text);
        xml_document.Schemas.Add(null, XmlReader.Create(new System.IO.StringReader(ui_XSD.Text)));
        xml_document.Validate(validation_handler);
    }
    catch (Exception ex)
    {
        ui_output.Text = "Exception: " + ex.Message;
    }
}

private void validation_handler(object sender, ValidationEventArgs e)
{
    switch (e.Severity)
    {
        case XmlSeverityType.Error:
            ui_output.Text += "Error: " + e.Message + Environment.NewLine;
            break;
        case XmlSeverityType.Warning:
            ui_output.Text += "Warning: " + e.Message + Environment.NewLine;
            break;
    }
}

更新 接受答案的一个例子:

XmlDocument xml_document = new XmlDocument();
xml_document.Load(@"C:\temp\example.xml");
xml_document.Schemas.Add(null, @"C:\temp\example.xsd");
xml_document.Schemas.Compile();

XmlQualifiedName xml_qualified_name = new XmlQualifiedName(xml_document.DocumentElement.LocalName, xml_document.DocumentElement.NamespaceURI);
bool valid_root = xml_document.Schemas.GlobalElements.Contains(xml_qualified_name);

3 个答案:

答案 0 :(得分:5)

我处理这个问题的方法是首先检查文档元素(根元素)中是否存在XmlReaderSettings.Schemas中的XmlSchemaElement;如果没有,则无法运行验证,这就是没有错误的原因。

所以,请确保你的XmlSchemaSet is compiled;然后使用XmlQualifiedNameLocalName构建NamespaceUri;用它来XmlSchemaElement查找GlobalElements

只有在i)您的模式编译成功并且ii)您实际上有文档根元素的定义时,您才应该尝试验证。

希望它有所帮助...

答案 1 :(得分:1)

如果文档中根元素的名称空间与模式的目标名称空间不匹配,则验证程序无法找到具有根元素(或任何元素,最有可能)定义的模式。这意味着验证器无法报告无效结构,因为它不知道正确的结构。在这种情况下,验证器通常可以跳过验证,执行宽松验证(仅验证找到模式定义的元素)或发出有关未查找模式定义的警告。

快速认为您至少有两个选择:1)从文档中读取命名空间并使用单独的检查来验证它是否正确或2)检查是否有可能通过更改其设置来更改验证器的行为这样它就会通知没有找到给定命名空间的定义。

答案 2 :(得分:0)

@PetruGardea - 非常感谢你的回答!!!

我只是在这里添加一些代码来演示您的解决方案,以便其他人不必谷歌它:

var doc = new XmlDocument();
var set = new XmlSchemaSet();

var xsdString = @"<xs:schema
  xmlns=""http://www.sample.ru/system""
  targetNamespace=""http://www.sample.ru/system""
  xmlns:xs=""http://www.w3.org/2001/XMLSchema""
  elementFormDefault=""qualified"">

  <xs:element name=""Test"">
    <xs:complexType>
      <xs:sequence>
        <xs:element name=""B"" >
        </xs:element>
      </xs:sequence>
    </xs:complexType>
  </xs:element>

</xs:schema>";

using (var memStream = new MemoryStream())
{
    var data = Encoding.Default.GetBytes(xsdString);
    memStream.Write(data, 0, data.Length);
    memStream.Position = 0;
    using (var reader = XmlReader.Create(memStream))
    {
        set.Add(@"http://www.sample.ru/system", reader);
    }
}

//doc.LoadXml(@"<a1:Test xmlns:a1=""http://www.sample.ru/system""><a1:B /></a1:Test>"); // valid xml - no errors
//doc.LoadXml(@"<a1:Test xmlns:a1=""http://www.sample.ru/system""><a1:B1 /></a1:Test>"); // invalid xml - error about B1
doc.LoadXml(@"<a1:Test xmlns:a1=""http://www.sample.ru/system1""><a1:B1 /></a1:Test>"); // invalid xml with bad namespace - error about namespace
//doc.LoadXml(@""); // no need to worry that doc.FirstChild is null - in this case this line throws exception

doc.Schemas.Add(set);

// !!!! you need to add this code to check for wrong namespace !!!! 
var baseUri = doc.FirstChild.NamespaceURI;
if (!doc.Schemas.Contains(baseUri))
{
    Console.WriteLine("Error: there is not xsd to validate this document (uri = {0})", baseUri);
}

// the rest of the code just prints validation errors and warnings
doc.Validate((sender, e) =>
{
    Console.WriteLine(e.Message);
});