user247702
user247702

Reputation: 24222

XmlDocument.Validate does not check for an invalid namespace

I use the following code to validate an XML file against an XSD file. It succesfully invokes the validation handler when errors are found and the value of xmlns in the XML file is valid. When it is invalid, the validation handler is not invoked.

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;
    }
}

Update An example for the accepted answer:

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);

Upvotes: 2

Views: 3123

Answers (3)

Aleksei Poliakov
Aleksei Poliakov

Reputation: 1332

@PetruGardea - big thanks for your answer!!!

I just put some code in here to demonstrate your solution so others do not have to google it:

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);
});

Upvotes: 1

Petru Gardea
Petru Gardea

Reputation: 21658

The way I handle this is to actually check first that for the Document Element (the root element) there is an XmlSchemaElement in your XmlReaderSettings.Schemas; if there isn't, you can't run the validation, which is why you get no error.

So, make sure that your XmlSchemaSet is compiled; then build an XmlQualifiedName using the LocalName and NamespaceUri; use that to lookup an XmlSchemaElement, using GlobalElements.

You should attempt to validate only if i) your schemas compile successfully and ii) you actually have a definition for the root element of the document.

Hope it helps...

Upvotes: 5

jasso
jasso

Reputation: 13986

If the namespace of the root element in your document doesn't match the target namespace of your schema, then the validator cannot find a schema that has definitions for the root element (or any of the elements, most likely). This means that the validator cannot report invalid structure, because it has no knowledge of the correct structure. In such case validators generally can skip validation, perform lax validation (validate only the elements, for which schema definitions are found) or raise a warning about not finding schema definitions.

Quickly thinking you have at least two choices: 1) read the namespace from the document and use separate check to verify if it is correct or 2) check if there is a possibility to change the behaviour of the validator by changing its settings so that it would notify about not finding definitions for given namespace.

Upvotes: 1

Related Questions