Contents
Introduction
Usually when parsing a schema document, developers will prefer to make custom objects for attribute and element extensions. XMLSchema supports this through an extension registry mechanism. This document explains how this extension mechanism works by going through two complete examples. These two examples are included as test cases with the source release.
Example Extension
Following are two example schema documents that contain external attributes/elements
This schema demonstrates the use of an extension attribute
<schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://soapinterop.org/types" xmlns:ext="http://customattrib.org" targetNamespace="http://soapinterop.org/types"> <complexType name="Struct" ext:customAttrib="toplevel:type"> <sequence> <element name="varString" type="xsd:string" ext:customAttrib="inner:element"/> <element name="varInt" type="xsd:int" ext:customAttrib="inner:element"/> <element name="varFloat" type="xsd:float" ext:customAttrib="inner:element"/> <element name="varStruct" type="tns:Struct" ext:customAttrib="inner:element"/> </sequence> </complexType> <element name="attrTest" type="tns:Struct" ext:customAttrib="toplevel:element"/> </schema>
This schema demonstrates the use of an extension element
<schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://soapinterop.org/types" xmlns:ext="http://customattrib.org" targetNamespace="http://soapinterop.org/types"> <complexType name="Struct"> <ext:customElt prefix="ext" suffix="type"/> <sequence> <element name="varString" type="xsd:string"/> <element name="varInt" type="xsd:int" /> <element name="varFloat" type="xsd:float" /> <element name="varStruct" type="tns:Struct" /> </sequence> </complexType> <element name="attrTest" type="tns:Struct" > <ext:customElt prefix="ext" suffix="elt"/> </element> </schema>
A developer would like the parser to make custom objects when it encounters customAttrib or customElt. This can be achieved by writing a custom extension deserializer and serializer and registering them with the extension registry. The next section briefly explains the important classes involved in this process.
Important classes
Following are the important classes in writing an extension
org.apache.ws.commons.schema.extensions.ExtensionRegistry
org.apache.ws.commons.schema.extensions.ExtensionDeserializer
org.apache.ws.commons.schema.extensions.ExtensionSerializer
Last two classes are interfaces that should be implemented by the respective implementations.
Code for a Deserializer
The deserializer needs to implement the
org.apache.ws.commons.schema.extensions.ExtensionDeserializer
interface.
Following is a code fragment of the Extension deserializer that deserializes the extension
attribute into a custom object. Note that once the custom object is made it is attached
to the meta info map of the relevant XMLSchema object with the QName as the key
public void deserialize(XmlSchemaObject schemaObject, QName name, Node domNode) {
if (CustomAttribute.CUSTOM_ATTRIBUTE_QNAME.equals(name)){
Attr attrib = (Attr)domNode;
String value = attrib.getValue();
//break the attrib into
CustomAttribute customAttrib = new CustomAttribute();
String[] strings = value.split(":");
customAttrib.setPrefix(strings[0]);
customAttrib.setSuffix(strings[1]);
//put this in the schema object meta info map
schemaObject.addMetaInfo(CustomAttribute.CUSTOM_ATTRIBUTE_QNAME,customAttrib);
}
}
Note that prior knowledge is required about the format of the string of the attribute value.
The complete custom attribute deserializer is available in
tests.customext.attrib.CustomAttributeDeserializer
Following is a code fragment of the Extension deserializer that deserializes the extension element into a custom object. This is similar to the attribute case but now the node passed is the actual extension element itself.
public void deserialize(XmlSchemaObject schemaObject, QName name, Node domNode) {
if (CustomElement.CUSTOM_ELT_QNAME.equals(name)){
Element elt = (Element)domNode;
CustomElement customElement = new CustomElement();
customElement.setPrefix(elt.getAttribute("prefix"));
customElement.setSuffix(elt.getAttribute("suffix"));
//put this in the schema object meta info map
schemaObject.addMetaInfo(CustomElement.CUSTOM_ELT_QNAME,customElement);
}
}
The complete custom attribute deserializer is available in
tests.customext.elt.CustomElementDeserializer
Code for a Serializer
The serializer needs to implement the
org.apache.ws.commons.schema.extensions.ExtensionSerializer
interface.
Following is a code fragment of the Extension serializer that serializes a given custom
object into an attributeObject. Note that XMLSchema serialization mechanism is to create
a DOM tree and serialize it. Hence the custom serializers needs to create the
appropriate DOM node and attach it.
public void serialize(XmlSchemaObject schemaObject, Class classOfType, Node domNode) {
Map metaInfoMap = schemaObject.getMetaInfoMap();
CustomAttribute att = (CustomAttribute)metaInfoMap.get(CustomAttribute.CUSTOM_ATTRIBUTE_QNAME);
Element elt = (Element)domNode;
Attr att1 = elt.getOwnerDocument().createAttributeNS(CustomAttribute.CUSTOM_ATTRIBUTE_QNAME.getNamespaceURI(),
CustomAttribute.CUSTOM_ATTRIBUTE_QNAME.getLocalPart());
att1.setValue(att.getPrefix() + ":" + att.getSuffix());
elt.setAttributeNodeNS(att1);
}
Note that prior knowledge is required about the format of the string of the attribute value. DomNode
passed in would be the parent node of the serialized DOM tree.The complete custom attribute serializer is available in
tests.customext.attrib.CustomAttributeSerializer
Following is a code fragment of the Extension serializer that serializes the custom object into an extension element. This is similar to the attribute case.
public void serialize(XmlSchemaObject schemaObject, Class classOfType, Node domNode) {
Map metaInfoMap = schemaObject.getMetaInfoMap();
CustomElement customElt = (CustomElement)metaInfoMap.get(CustomElement.CUSTOM_ELT_QNAME);
Element elt = (Element)domNode;
Element extElt = elt.getOwnerDocument().createElementNS(CustomElement.CUSTOM_ELT_QNAME.getNamespaceURI(),
CustomElement.CUSTOM_ELT_QNAME.getLocalPart());
extElt.setAttribute("prefix",customElt.getPrefix());
extElt.setAttribute("suffix",customElt.getSuffix());
elt.appendChild(extElt);
}
The complete custom element serializer is available in
tests.customext.elt.CustomElementSerializer
Registering Types and Using a Custom Extension Registry
Once the serilizers are made they need to be registered with the registry. This can be done by the following way.
//register our custom type
registerDeserializer(CustomElement.CUSTOM_ELT_QNAME,new CustomElementDeserializer());
registerSerializer(CustomElement.class,new CustomElementSerializer());
It can be a more convenient if the extension types are registered inside a subclass
of the org.apache.ws.commons.schema.extensions.ExtensionRegistry
to
avoid any confusions.
If the system property"org.apache.ws.commons.extensions.ExtensionRegistry"
is present
the extension registry will be instantiated with the class specified. Following is an example of
how this can be done
System.setProperty(Constants.SystemConstants.EXTENSION_REGISTRY_KEY,
CustomExtensionRegistry.class.getName());
This behavior is quite useful when the XMlSchema object models are used internally with no direct access to the extension registry.