<?xml version="1.0" encoding="ISO-8859-1"?> | |
<document> | |
<properties> | |
<title>:: Apache XmlSchema Extension Tutorial ::</title> | |
</properties> | |
<head> | |
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1"/> | |
<meta content="text/html; charset=iso-8859-1"/> | |
</head> | |
<body> | |
<section name="Contents"> | |
<ul> | |
<li><a href="#intro">Introduction</a></li> | |
<li><a href="#example">Example Extension</a></li> | |
<li><a href="#iclasses">Important classes</a></li> | |
<li><a href="#deser">Code for a Deserializer</a></li> | |
<li><a href="#ser">Code for a Serializer</a></li> | |
<li><a href="#reg">Registering types and using a custom extension registry</a></li> | |
<!--<li><a href="#default">Default Behavior</a></li>--> | |
<li><a href="#conclusion">Conclusion</a></li> | |
</ul> | |
</section> | |
<a name="intro"></a> | |
<section name="Introduction"> | |
<p>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.</p> | |
</section> | |
<a name="example"></a> | |
<section name="Example Extension"> | |
<p>Following are two example schema documents that contain external attributes/elements</p> | |
<p>This schema demonstrates the use of an extension attribute | |
<pre> | |
<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> | |
</pre> | |
</p> | |
<p>This schema demonstrates the use of an extension element | |
<pre> | |
<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> | |
</pre> | |
</p> | |
<p>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.</p> | |
</section> | |
<a name="iclasses"></a> | |
<section name="Important classes"> | |
<p>Following are the important classes in writing an extension</p> | |
<ul> | |
<li><code>org.apache.ws.commons.schema.extensions.ExtensionRegistry</code></li> | |
<li><code>org.apache.ws.commons.schema.extensions.ExtensionDeserializer</code></li> | |
<li><code>org.apache.ws.commons.schema.extensions.ExtensionSerializer</code></li> | |
</ul> | |
<p>Last two classes are interfaces that should be implemented by the respective | |
implementations.</p> | |
</section> | |
<a name="deser"></a> | |
<section name="Code for a Deserializer"> | |
<p>The deserializer needs to implement the | |
<code>org.apache.ws.commons.schema.extensions.ExtensionDeserializer</code> 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</p> | |
<p> | |
<pre> | |
<code> | |
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); | |
} | |
} | |
</code> | |
</pre> | |
</p> | |
<p>Note that prior knowledge is required about the format of the string of the attribute value. | |
The complete custom attribute deserializer is available in | |
<code>tests.customext.attrib.CustomAttributeDeserializer</code></p> | |
<p> 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.</p> | |
<p> | |
<pre> | |
<code> | |
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); | |
} | |
} | |
</code> | |
</pre> | |
</p> | |
<p>The complete custom attribute deserializer is available in | |
<code>tests.customext.elt.CustomElementDeserializer</code></p> | |
</section> | |
<a name="ser"></a> | |
<section name="Code for a Serializer"> | |
<p>The serializer needs to implement the | |
<code>org.apache.ws.commons.schema.extensions.ExtensionSerializer</code> 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.</p> | |
<p> | |
<pre> | |
<code> | |
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); | |
} | |
</code> | |
</pre> | |
</p> | |
<p>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 | |
<code>tests.customext.attrib.CustomAttributeSerializer</code></p> | |
<p> 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.</p> | |
<p> | |
<pre> | |
<code> | |
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); | |
} | |
</code> | |
</pre> | |
</p> | |
<p>The complete custom element serializer is available in | |
<code>tests.customext.elt.CustomElementSerializer</code></p> | |
</section> | |
<a name="reg"></a> | |
<section name="Registering Types and Using a Custom Extension Registry"> | |
<p>Once the serilizers are made they need to be registered with the registry. | |
This can be done by the following way.</p> | |
<p> | |
<pre> | |
<code> | |
//register our custom type | |
registerDeserializer(CustomElement.CUSTOM_ELT_QNAME,new CustomElementDeserializer()); | |
registerSerializer(CustomElement.class,new CustomElementSerializer()); | |
</code> | |
</pre> | |
</p> | |
<p>It can be a more convenient if the extension types are registered inside a subclass | |
of the <code>org.apache.ws.commons.schema.extensions.ExtensionRegistry</code> to | |
avoid any confusions.</p> | |
<p>If the system property<code>"org.apache.ws.commons.extensions.ExtensionRegistry"</code> is present | |
the extension registry will be instantiated with the class specified. Following is an example of | |
how this can be done</p> | |
<p> | |
<pre> | |
<code> | |
System.setProperty(Constants.SystemConstants.EXTENSION_REGISTRY_KEY, | |
CustomExtensionRegistry.class.getName()); | |
</code> | |
</pre> | |
</p> | |
<p>This behavior is quite useful when the XMlSchema object models are used internally with | |
no direct access to the extension registry.</p> | |
</section> | |
<a name="conclusion"></a> | |
<section name="Conclusion"> | |
The extension mechanism of the XMLSchema object model allows the users to add their custom | |
objects to the standard XMLSchema objects. | |
</section> | |
</body> | |
</document> |