# Extensible XML authoring

## Introduction

Spring supports adding custom schema-based extensions to the basic Spring XML format for defining and configuring objects. This section is devoted to detailing how you would go about writing your own custom XML object definition parsers and integrating such parsers into the Spring IoC container.

To facilitate the authoring of configuration files using a schema-aware XML editor, Spring's extensible XML configuration mechanism is based on XML Schema. If you are not familiar with Spring's current XML configuration extensions that come with the standard Spring distribution, please first read the appendix entitled .

Creating new XML configuration extensions can be done by following these (relatively) simple steps:

1. Authoring an XML schema to describe your custom element(s).

2. Coding a custom `INamespaceParser` implementation (this is an easy step, don't worry).

3. Coding one or more `IObjectDefinitionParser` implementations (this is where the real work is done).

4. Registering the above artifacts with Spring (this too is an easy step).

What follows is a description of each of these steps. For the example, we will create an XML extension (a custom XML element) that allows us to configure objects of the type `Regex` (from the `System.Text.RegularExpressions` namespace) in an easy manner. When we are done, we will be able to define object definitions of type `Regex` like this:

    <myns:regex id="regex"
                pattern="(^\d{5}$)|(^\d{5}-\d{4}$)"
                options="Compiled"/>

## Authoring the schema

Creating an XML configuration extension for use with Spring's IoC container starts with authoring an XML Schema to describe the extension. What follows is the schema we'll use to configure `Regex` objects.

    <?xml version="1.0" encoding="utf-8" ?>
    <xsd:schema id="myns"
               xmlns="http://www.mycompany.com/schema/myns"
               xmlns:xsd="http://www.w3.org/2001/XMLSchema"
               xmlns:objects="http://www.springframework.net"
               xmlns:vs="http://schemas.microsoft.com/Visual-Studio-Intellisense"
               targetNamespace="http://www.mycompany.com/schema/myns"
               elementFormDefault="qualified"
               attributeFormDefault="unqualified"
               vs:friendlyname="Spring Regex Configuration" vs:ishtmlschema="false"
               vs:iscasesensitive="true" vs:requireattributequotes="true"
               vs:defaultnamespacequalifier="" vs:defaultnsprefix=""
               >

      <xsd:import namespace="http://www.springframework.net"/>

      <xsd:element name="regex">
        <xsd:complexType>
          <xsd:complexContent>
            <xsd:extension base="objects:identifiedType">
              <xsd:attribute name="pattern" type="xsd:string" use="required"/>
              <xsd:attribute name="options" type="xsd:string" use="optional"/>
            </xsd:extension>
          </xsd:complexContent>
        </xsd:complexType>
      </xsd:element>

    </xsd:schema>

The emphasized line contains an extension base for all tags that will be identifiable (meaning they have an `id` attribute that will be used as the object identifier in the container). We are able to use this attribute because we imported the Spring-provided `'objects'` namespace. The `vs:` prefixed elements are for better integration with intellisense in VS.NET.

The above schema will be used to configure `Regex` objects, directly in an XML application context file using the `<myns:regex/>` element.

    <myns:regex id="usZipCodeRegex"
                pattern="(^\d{5}$)|(^\d{5}-\d{4}$)"
                options="Compiled"/>

Note that after we've created the infrastructure classes, the above snippet of XML will essentially be exactly the same as the following XML snippet. In other words, we're just creating an object in the container, identified by the name `'usZipCodeRegex'` of type `Regex`, with a couple of constructor arguments set.

      <object id="usZipCodeRegex" type="System.Text.RegularExpressions.Regex, System">
        <constructor-arg name="pattern" value="(^\d{5}$)|(^\d{5}-\d{4}$)"/>
        <constructor-arg name="options" value="Compiled"/>
      </object>

The schema-based approach to creating configuration format allows for tight integration with an IDE that has a schema-aware XML editor. Using a properly authored schema, you can use intellisense to have a user choose between several configuration options defined in the enumeration. The schema for creating IDbProvider instances shows the use of XSD enumerations.

## Coding a `INamespaceParser`

In addition to the schema, we need an `INamespaceParser` that will parse all elements of this specific namespace Spring encounters while parsing configuration files. The `INamespaceParser` should in our case take care of the parsing of the `myns:regex` element.

The `INamespaceParser` interface is pretty simple in that it features just two methods:

- `Init()` - allows for initialization of the `INamespaceParser` and will be called by Spring before the handler is used

- `IObjectDefinition Parse(Element, ParserContext)` - called when Spring encounters a top-level element (not nested inside a object definition or a different namespace). This method can register object definitions itself and/or return a object definition.

Although it is perfectly possible to code your own `INamespaceParser` for the entire namespace (and hence provide code that parses each and every element in the namespace), it is often the case that each top-level XML element in a Spring XML configuration file results in a single object definition (as in our case, where a single `<myns:regex/>` element results in a single `Regex` object definition). Spring features a number of convenience classes that support this scenario. In this example, we'll make use the `NamespaceParserSupport` class:

    using Spring.Objects.Factory.Xml;

    namespace CustomNamespace
    {
        [NamespaceParser(
            Namespace = "http://www.mycompany.com/schema/myns",
            SchemaLocationAssemblyHint = typeof(MyNamespaceParser),
            SchemaLocation = "/CustomNamespace/myns.xsd"
            )
        ]
        public class MyNamespaceParser : NamespaceParserSupport
        {
            public override void Init()
            {
                RegisterObjectDefinitionParser("regex", new RegexObjectDefinitionParser());
            }
        }
    }

Notice that there isn't actually a whole lot of parsing logic in this class. Indeed... the `NamespaceParserSupport` class has a built in notion of delegation. It supports the registration of any number of `IObjectDefinitionParser` instances, to which it will delegate to when it needs to parse an element in it's namespace. This clean separation of concerns allows an `INamespaceParser` to handle the orchestration of the parsing of all of the custom elements in it's namespace, while delegating to `IObjectDefinitionParsers` to do the grunt work of the XML parsing; this means that each `IObjectDefinitionParser` will contain just the logic for parsing a single custom element, as we can see in the next step.

To help in the registration of the parser for this namespace, the `NamespaceParser` attribute is used to map the XML namespace string, i.e. `http://www.mycompany.com/schema/myns`, to the location of the XML Schema file as an embedded assembly resource.

## Coding an `IObjectDefinitionParser`

A `IObjectDefinitionParser` will be used if the `INamespaceParser` encounters an XML element of the type that has been mapped to the specific object definition parser (which is `'regex'` in this case). In other words, the `IObjectDefinitionParser` is responsible for parsing one distinct top-level XML element defined in the schema. In the parser, we'll have access to the XML element (and thus it's subelements too) so that we can parse our custom XML content, as can be seen in the following example:

    using System;
    using System.Text.RegularExpressions;
    using System.Xml;
    using Spring.Objects.Factory.Support;
    using Spring.Objects.Factory.Xml;
    using Spring.Util;

    namespace CustomNamespace
    {
       public class RegexObjectDefinitionParser : AbstractSimpleObjectDefinitionParser {

       protected override Type GetObjectType(XmlElement element)
       {
         return typeof (Regex);
       }

       protected override void DoParse(XmlElement element, ObjectDefinitionBuilder builder)
       {
           // this will never be null since the schema explicitly requires that a value be supplied
           string pattern = element.GetAttribute("pattern");
           builder.AddConstructorArg(pattern);

           // this however is an optional property
           string options = element.GetAttribute("options");
           if (StringUtils.HasText(options))
           {
              RegexOptions regexOptions = (RegexOptions)Enum.Parse(typeof (RegexOptions), options);
              builder.AddConstructorArg(regexOptions);
           }
       }

       protected override bool ShouldGenerateIdAsFallback
       {
          get { return true; }
       }
    }

We use the Spring-provided `AbstractSingleObjectDefinitionParser` to handle a lot of the basic grunt work of creating a single `IObjectDefinition`.

We supply the `AbstractSingleObjectDefinitionParser` superclass with the type that our single `IObjectDefinition` will represent.

In this simple case, this is all that we need to do. The creation of our single `IObjectDefinition` is handled by the `AbstractSingleObjectDefinitionParser` superclass, as is the extraction and setting of the object definition's unique identifier. The property `ShouldGenerateIdAsFallback` will generate a throw-away object id incase one is not specified, this is useful when nesting object definitions.

## Registering the handler and the schema

The coding is finished! All that remains to be done is to somehow make the Spring XML parsing infrastructure aware of our custom element; we do this by registering our custom `INamespaceParser` using a special configuration section handler. The location of the XML Schema in this example has been directly assoicated with the parser though the use of the `Namespace` attribute.

### `NamespaceParsersSectionHandler`

The custom configuration section handler is of the type `Spring.Context.Support.NamespaceParsersSectionHandler` and is registered with .NET in the normal manner. The custom configuration section will simply point to the `INamespaceParser` implementation that has the `Namespace` attribute. For our example, we need to write the following:

    <configuration>

      <configSections>
        <sectionGroup name="spring">
          <section name="parsers" type="Spring.Context.Support.NamespaceParsersSectionHandler, Spring.Core"/>
         </sectionGroup>
      </configSections>

      <spring>
        <parsers>
          <parser type="CustomNamespace.MyNamespaceParser, CustomNamespace" />
        </parsers>
      </spring>

    </configuration>

## Using a custom extension in your Spring XML configuration

Using a custom extension that you yourself have implemented is no different from using one of the 'custom' extensions that Spring provides straight out of the box. Find below an example of using the custom `<regex/>` element developed in the previous steps in a Spring XML configuration file.

    <?xml version="1.0" encoding="utf-8" ?>
    <objects xmlns="http://www.springframework.net"
             xmlns:myns="http://www.mycompany.com/schema/myns">

      <!-- as a top level object definition -->
      <myns:regex id="usZipCodeRegex"
                  pattern="(^\d{5}$)|(^\d{5}-\d{4}$)"/>

      <object id="jobDetailTemplate" abstract="true">
        <property name="regex">
          <!-- as an inner object definition -->
           <myns:regex pattern="(^\d{5}$)|(^\d{5}-\d{4}$)"
                       options="Compiled"/>
        </property>
      </object>

    </objects>

## Further Resources

Find below links to further resources concerning XML Schema and the extensible XML support described in this chapter.

- The XML Schema Part 1: Structures Second Edition

- The XML Schema Part 2: Datatypes Second Edition