My Technical Notes

Wednesday, 28 January 2015

An Example XML/XSD Pair

In the following xsd, the first (root) element expected is called "example" - of type `example`. `example` requires an element "firstElem" and an attribute "myAttr", both of type `xs:string`.

XSD:


<?xml version="1.0" encoding="utf-8"?>
<xs:schema
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  targetNamespace="urn:tahirhassan:example"  
  xmlns="urn:tahirhassan:example"
  elementFormDefault="qualified">

  <xs:complexType name="example">
    <xs:sequence>
      <xs:element name="firstElem" type="xs:string" />
    </xs:sequence>
    <xs:attribute name="myAttr" type="xs:string" />
  </xs:complexType>

  <xs:element name="example" type="example" />
</xs:schema>

XML:


<example 
  xmlns="urn:tahirhassan:example"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="urn:tahirhassan:example Example.xsd"
  myAttr="random attribute value">
  <firstElem>first elem value</firstElem>
</example>

In the `xsi:schemaLocation` attribute, we specify a schema (or namespace) and then where to find the corresponding xsd file. In general:


xsi:schemaLocation="<schema> <path-to-xsd>"
If you want to give the path to multiple xsd files, we do:

xsi:schemaLocation="<schema-1> <path-to-xsd-1> <schema-2> <path-to-xsd-2> ... <schema-n> <path-to-xsd-n>"
For example:

<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:aop="http://www.springframework.org/schema/aop"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
  http://www.springframework.org/schema/aop
  http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">

  ...

</beans>

EDIT: If you want to add a `xsi:schemaLocation` but do not have a namespace, then use the `xsi:noNamespaceSchemaLocation` attribute.

EDIT: The following method, `ValidateDocumentInternal` validates the document (passed in as a string, which is turned into a stream using `StringToStream`) and returns an `XmlValidationResult`.


private static XmlValidationResult ValidateDocumentInternal(string document, params Stream[] xsdStreams)
{
    XmlReaderSettings settings = new XmlReaderSettings
    {
        ValidationType = ValidationType.Schema
    };

    foreach (var xsdStream in xsdStreams)
    {
        using (xsdStream)
        {
            XmlReader xmlReader = XmlReader.Create(xsdStream);

            try
            {
                settings.Schemas.Add(null, xmlReader);
            }
            finally
            {
                xmlReader.Close();
            }
        }
    }

    var validationErrors = new List<string>();

    settings.ValidationEventHandler += (object sender, System.Xml.Schema.ValidationEventArgs e) =>
    {
        validationErrors.Add(e.Message);
    };

    using (var stream = StringToStream(document))
    {
        var reader = XmlReader.Create(stream, settings);

        while (reader.Read())
        {
        }
    }

    return new XmlValidationResult
    {
        Success = validationErrors.Count == 0,
        ValidationErrors = validationErrors
    };
}

StringToStream:


public static Stream StringToStream(string s)
{
    return new MemoryStream(Encoding.UTF8.GetBytes(s ?? ""));
}

XmlValidationResult:


public class XmlValidationResult
{
    public bool Success { get; set; }
    public IList<string> ValidationErrors { get; set; }
}

No comments: