Sunday, May 16, 2010

Demystifying elementFormDefault

elementFormDefault attribute is useful when instead of mentioning form attribute to each element of schema we want to set form for all element to schema. In the schema below if we don't want to mention form attribute for each element we can use elementFormDefault="qualified".

<schema xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="child" xmlns:tns="child"
<element name="EmpDetails">
<complexType>
<sequence>
<element name="fullname" form="qualified" type="string" />
<element name="name" form="qualified" type="string" />
</sequence>
</complexType>
</element>
</schema>

elementFormDefault becomes confusing when we start mixing namespace in schema. To make is simple lets start with some thumb rule.

1. Global Element(direct child of schema element) will always appear with name space in xml instance.

2. elementFormDefault is just a switch for local elements, if schema developer wants them to appear with namespace or without namespace in xml instance.

3. elementFormDefault attribute is applicable to only local elements of the schema in which it is defined and not to the local elements of imported schema.


Lets take one XML instance.

<tns:Emp xmlns:tns="parent" xmlns:tns1="child" >
<ID>ID</ID>
<tns1:EmpDetails>
<fullname>fullname</fullname>
</tns1:EmpDetails>
<EmpAddress>
<Street>Street</Street>
</EmpAddress>
</tns:Emp>

Lets take example of xml instance mentioned above and try to deduce schema "elementFormDefault" from this.

First thing to notice is, since instance has two namespace so one schema is importing another. From the first element we can say that in main schema elementFormDefault is unqulaified since instance doesn't has a default namespace and ID is local element defined in main schema. EmpDetails belongs to different namespace so its clear that EmpDetails exist as global element in the another schema. But what about elementFormDefault from default attribute of other schema. "fullname" which is local element in other schema and doesn't have any namespace, we can say that elementFromDefault in other schema is unqualified.

Now lets derive a possible schema from the above instance.

schema1

<schema xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="parent"
xmlns:tns="parent" xmlns:child="child"
elementFormDefault="unqualified">
<import namespace="child" schemaLocation="NewXMLSchemaChild.xsd" />
<element name="Emp">
<complexType>
<sequence>
<element name="ID" type="string" />
<element ref="child:EmpDetails" />
<element name="EmpAddress" type="child:Address" />
</sequence>
</complexType>
</element>
</schema>

schema2

<schema xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="child" xmlns:tns="child"
elementFormDefault="qualified">
<element name="EmpDetails">
<complexType>
<sequence>
<element name="fullname" type="string" />
</sequence>
</complexType>
</element>
<complexType name="Address">
<sequence>
<element name="Street" type="string" />
</sequence>
</complexType>
</schema>



XML instance mentioned below shows change in XML instance due to change in elementFormDefault attribute in schema1 and schema2

unqualified/qualified

<tns:Emp xmlns:tns="parent" xmlns:tns1="child" >
<ID>ID</ID>
<tns1:EmpDetails>
<tns1:fullname>tns1:fullname</tns1:fullname>
</tns1:EmpDetails>
<EmpAddress>
<tns1:Street>tns1:Street</tns1:Street>
</EmpAddress>
</tns:Emp>

qualified/unqualified

<tns:Emp xmlns:tns="parent" xmlns:tns1="child" >
<tns:ID>tns:ID</tns:ID>
<tns1:EmpDetails>
<fullname>fullname</fullname>
</tns1:EmpDetails>
<tns:EmpAddress>
<Street>Street</Street>
</tns:EmpAddress>
</tns:Emp>


qualified/qualified
<tns:Emp xmlns:tns="parent" xmlns:tns1="child" >
<tns:ID>tns:ID</tns:ID>
<tns1:EmpDetails>
<tns1:fullname>tns1:fullname</tns1:fullname>
</tns1:EmpDetails>
<tns:EmpAddress>
<tns1:Street>tns1:Street</tns1:Street>
</tns:EmpAddress>
</tns:Emp>


You can use below code to see if different instance are valid corresponding to respective schema.

import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;

public class XMLValidator {
public static void main(String[] argv) throws Exception {
String schemaLang = "http://www.w3.org/2001/XMLSchema";
SchemaFactory factory = SchemaFactory.newInstance(schemaLang);
Schema schema = factory.newSchema(new StreamSource("NewXMLSchema.xsd"));
Validator validator = schema.newValidator();
validator.validate(new StreamSource("NewXMLSchema.xml"));
System.out.println("Validated Successfully");
}
}