blob: 24c00bd88926924db930494defa8e42e06b693ac [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.ws.commons.schema;
import org.apache.ws.commons.schema.XmlSchemaCollection.SchemaKey;
import org.apache.ws.commons.schema.constants.Constants;
import org.apache.ws.commons.schema.extensions.ExtensionRegistry;
import org.apache.ws.commons.schema.utils.NodeNamespaceContext;
import org.apache.ws.commons.schema.utils.TargetNamespaceValidator;
import org.apache.ws.commons.schema.utils.XDOMUtil;
import org.apache.ws.commons.schema.utils.DOMUtil;
import org.w3c.dom.*;
import org.xml.sax.InputSource;
import javax.xml.namespace.NamespaceContext;
import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilderFactory;
import java.lang.ref.SoftReference;
import java.util.Hashtable;
import java.util.StringTokenizer;
import java.util.Vector;
public class SchemaBuilder {
Document doc;
XmlSchema schema;
XmlSchemaCollection collection;
private final TargetNamespaceValidator validator;
DocumentBuilderFactory docFac;
/**
* The extension registry to be used while building the
* schema model
*/
private ExtensionRegistry extReg = null;
public ExtensionRegistry getExtReg() {
return extReg;
}
public void setExtReg(ExtensionRegistry extReg) {
this.extReg = extReg;
}
/*
* cache of previously resolved schema documents.
*
* This cache might be usefull when an application has multiple webservices that each have WSDL documents
* that import the same schema, for example. On app startup, we may wish to cache XmlSchema objects so we
* don't build up the schema graph multiple times.
*
* key - use a combination of thread id and all three parameters passed to resolveXmlSchema to give minimal thread safety*
* value - XmlSchema object wrapped in a SoftReference to encourage GC in low memory situations
*
* *CAUTION: XmlSchema objects are not likely to be thread-safe. This cache should
* only be used, then cleared, by callers aware of its existence. It is VERY important that users of this
* cache call clearCache() after they are done.
*
* Usage of the cache is controlled by calling initCache() which will initialize resolvedSchemas to non-null
* Clearing of cache is done by calling clearCache() which will clear and nullify resolvedSchemas
*
*/
private static Hashtable resolvedSchemas = null;
/**
* Schema builder constructor
* @param collection
*/
SchemaBuilder(XmlSchemaCollection collection,
TargetNamespaceValidator validator) {
this.collection = collection;
this.validator = validator;
if (collection.getExtReg() != null) {
this.extReg = collection.getExtReg();
}
schema = new XmlSchema();
}
public static synchronized void initCache() {
if (resolvedSchemas == null) {
resolvedSchemas = new Hashtable();
}
}
public static synchronized void clearCache() {
if (resolvedSchemas != null) {
resolvedSchemas.clear(); // necessary?
resolvedSchemas = null;
}
}
/**
* build method taking in a document and a validation handler
* @param doc
* @param uri
* @param veh
*/
XmlSchema build(Document doc, String uri, ValidationEventHandler veh) {
Element schemaEl = doc.getDocumentElement();
XmlSchema xmlSchema = handleXmlSchemaElement(schemaEl, uri);
xmlSchema.setInputEncoding(DOMUtil.getInputEncoding(doc));
return xmlSchema;
}
/**
* handles the schema element
* @param schemaEl
* @param uri
*/
XmlSchema handleXmlSchemaElement(Element schemaEl, String uri) {
// get all the attributes along with the namespace declns
schema.setNamespaceContext(NodeNamespaceContext.getNamespaceContext(schemaEl));
setNamespaceAttributes(schema, schemaEl);
XmlSchemaCollection.SchemaKey schemaKey = new XmlSchemaCollection.SchemaKey(
schema.logicalTargetNamespace, uri);
if (!collection.containsSchema(schemaKey)) {
collection.addSchema(schemaKey, schema);
schema.parent = collection; // establish parentage now.
} else {
throw new XmlSchemaException("Schema name conflict in collection. Namespace: " + schema.logicalTargetNamespace);
}
schema.setElementFormDefault(this.getFormDefault(schemaEl,
"elementFormDefault"));
schema.setAttributeFormDefault(this.getFormDefault(schemaEl,
"attributeFormDefault"));
schema.setBlockDefault(this.getDerivation(schemaEl, "blockDefault"));
schema.setFinalDefault(this.getDerivation(schemaEl, "finalDefault"));
/* set id attribute */
if (schemaEl.hasAttribute("id")) {
schema.id = schemaEl.getAttribute("id");
}
schema.setSourceURI(uri);
/***********
* for ( each childElement)
* if( simpleTypeElement)
* handleSimpleType
* else if( complexType)
* handleComplexType
* else if( element)
* handleElement
* else if( include)
* handleInclude
* else if( import)
* handleImport
* else if (group)
* handleGroup
* else if (attributeGroup)
* handleattributeGroup
* else if( attribute)
* handleattribute
* else if (redefine)
* handleRedefine
* else if(notation)
* handleNotation
* else if (annotation)
* handleAnnotation
*/
Element el = XDOMUtil.getFirstChildElementNS(schemaEl,
XmlSchema.SCHEMA_NS);
if (el == null
&& XDOMUtil.getFirstChildElementNS(schemaEl,
"http://www.w3.org/1999/XMLSchema") != null) {
throw new XmlSchemaException(
"Schema defined using \"http://www.w3.org/1999/XMLSchema\" is not supported. "
+ "Please update the schema to the \""
+ XmlSchema.SCHEMA_NS + "\" namespace");
}
for (; el != null; el = XDOMUtil.getNextSiblingElementNS(el,
XmlSchema.SCHEMA_NS)) {
// String elPrefix = el.getPrefix() == null ? "" : el.getPrefix();
//if(elPrefix.equals(schema.schema_ns_prefix)) {
if (el.getLocalName().equals("simpleType")) {
XmlSchemaType type = handleSimpleType(schema, el, schemaEl);
schema.addType(type);
schema.items.add(type);
collection.resolveType(type.getQName(), type);
} else if (el.getLocalName().equals("complexType")) {
XmlSchemaType type = handleComplexType(schema, el, schemaEl);
schema.addType(type);
schema.items.add(type);
collection.resolveType(type.getQName(), type);
} else if (el.getLocalName().equals("element")) {
XmlSchemaElement element = handleElement(schema, el, schemaEl,
true);
if (element.qualifiedName != null)
schema.elements.collection.put(element.qualifiedName,
element);
else if (element.refName != null)
schema.elements.collection.put(element.refName, element);
schema.items.add(element);
} else if (el.getLocalName().equals("include")) {
XmlSchemaInclude include = handleInclude(schema, el, schemaEl);
schema.includes.add(include);
schema.items.add(include);
} else if (el.getLocalName().equals("import")) {
XmlSchemaImport schemaImport = handleImport(schema, el,
schemaEl);
schema.includes.add(schemaImport);
schema.items.add(schemaImport);
} else if (el.getLocalName().equals("group")) {
XmlSchemaGroup group = handleGroup(schema, el, schemaEl);
schema.groups.collection.put(group.name, group);
schema.items.add(group);
} else if (el.getLocalName().equals("attributeGroup")) {
XmlSchemaAttributeGroup group = handleAttributeGroup(schema,
el, schemaEl);
schema.attributeGroups.collection.put(group.name, group);
schema.items.add(group);
} else if (el.getLocalName().equals("attribute")) {
XmlSchemaAttribute attr = handleAttribute(schema, el, schemaEl,
true); //pass true to indicate that it is a top level child
schema.attributes.collection.put(attr.qualifiedName, attr);
schema.items.add(attr);
} else if (el.getLocalName().equals("redefine")) {
XmlSchemaRedefine redefine = handleRedefine(schema, el,
schemaEl);
schema.includes.add(redefine);
} else if (el.getLocalName().equals("notation")) {
XmlSchemaNotation notation = handleNotation(el);
schema.notations.collection.put(new QName(schema
.getTargetNamespace(), notation.name), notation);
schema.items.add(notation);
} else if (el.getLocalName().equals("annotation")) {
XmlSchemaAnnotation annotation = handleAnnotation(el);
schema.setAnnotation(annotation);
}
}
//add the extesibility components
processExtensibilityComponents(schema, schemaEl);
return schema;
}
private XmlSchemaNotation handleNotation(Element notationEl) {
XmlSchemaNotation notation = new XmlSchemaNotation();
if (notationEl.hasAttribute("id")) {
notation.id = notationEl.getAttribute("id");
}
if (notationEl.hasAttribute("name")) {
notation.name = notationEl.getAttribute("name");
}
if (notationEl.hasAttribute("public")) {
notation.publicNotation = notationEl.getAttribute("public");
}
if (notationEl.hasAttribute("system")) {
notation.system = notationEl.getAttribute("system");
}
Element annotationEl = XDOMUtil.getFirstChildElementNS(notationEl,
XmlSchema.SCHEMA_NS, "annotation");
if (annotationEl != null) {
XmlSchemaAnnotation annotation = handleAnnotation(annotationEl);
notation.setAnnotation(annotation);
}
return notation;
}
/**
* Handle redefine
* @param schema
* @param redefineEl
* @param schemaEl
* @return
*/
private XmlSchemaRedefine handleRedefine(XmlSchema schema,
Element redefineEl, Element schemaEl) {
XmlSchemaRedefine redefine = new XmlSchemaRedefine();
redefine.schemaLocation = redefineEl.getAttribute("schemaLocation");
final TargetNamespaceValidator validator = newIncludeValidator(schema);
if (schema.getSourceURI() != null) {
redefine.schema = resolveXmlSchema(schema.logicalTargetNamespace,
redefine.schemaLocation, schema.getSourceURI(), validator);
} else {
redefine.schema = resolveXmlSchema(schema.logicalTargetNamespace,
redefine.schemaLocation, validator);
}
/*
* FIXME - This seems not right. Since the redefine should take into account
* the attributes of the original element we cannot just build the type
* defined in the redefine section - what we need to do is to get the original type
* object and modify it. However one may argue (quite reasonably) that the purpose
* of this object model is to provide just the representation and not the validation
* (as it has been always the case)
*/
for (Element el = XDOMUtil.getFirstChildElementNS(redefineEl,
XmlSchema.SCHEMA_NS); el != null; el = XDOMUtil
.getNextSiblingElementNS(el, XmlSchema.SCHEMA_NS)) {
if (el.getLocalName().equals("simpleType")) {
XmlSchemaType type = handleSimpleType(schema, el, schemaEl);
redefine.schemaTypes.collection.put(type.getQName(), type);
redefine.items.add(type);
} else if (el.getLocalName().equals("complexType")) {
XmlSchemaType type = handleComplexType(schema, el, schemaEl);
redefine.schemaTypes.collection.put(type.getQName(), type);
redefine.items.add(type);
} else if (el.getLocalName().equals("group")) {
XmlSchemaGroup group = handleGroup(schema, el, schemaEl);
redefine.groups.collection.put(group.name, group);
redefine.items.add(group);
} else if (el.getLocalName().equals("attributeGroup")) {
XmlSchemaAttributeGroup group = handleAttributeGroup(schema,
el, schemaEl);
redefine.attributeGroups.collection.put(group.name, group);
redefine.items.add(group);
} else if (el.getLocalName().equals("annotation")) {
XmlSchemaAnnotation annotation = handleAnnotation(el);
redefine.setAnnotation(annotation);
}
// }
}
return redefine;
}
void setNamespaceAttributes(XmlSchema schema, Element schemaEl) {
//no targetnamespace found !
if (schemaEl.getAttributeNode("targetNamespace") != null) {
String contain = schemaEl.getAttribute("targetNamespace");
schema.setTargetNamespace(contain);
} else {
//do nothing here
}
if (validator != null) {
validator.validate(schema);
}
}
/**
* Handles simple types
* @param schema
* @param simpleEl
* @param schemaEl
*/
XmlSchemaSimpleType handleSimpleType(XmlSchema schema, Element simpleEl,
Element schemaEl) {
XmlSchemaSimpleType simpleType = new XmlSchemaSimpleType(schema);
if (simpleEl.hasAttribute("name")) {
simpleType.name = simpleEl.getAttribute("name");
}
if (simpleEl.hasAttribute("final")) {
String finalstr = simpleEl.getAttribute("final");
if (finalstr.equalsIgnoreCase("all")
| finalstr.equalsIgnoreCase("#all"))
simpleType.setFinal(new XmlSchemaDerivationMethod(
Constants.BlockConstants.ALL));
else
simpleType.setFinal(new XmlSchemaDerivationMethod(finalstr));
}
Element simpleTypeAnnotationEl = XDOMUtil.getFirstChildElementNS(
simpleEl, XmlSchema.SCHEMA_NS, "annotation");
if (simpleTypeAnnotationEl != null) {
XmlSchemaAnnotation simpleTypeAnnotation = handleAnnotation(simpleTypeAnnotationEl);
simpleType.setAnnotation(simpleTypeAnnotation);
}
Element unionEl, listEl, restrictionEl;
if ((restrictionEl = XDOMUtil.getFirstChildElementNS(simpleEl,
XmlSchema.SCHEMA_NS, "restriction")) != null) {
XmlSchemaSimpleTypeRestriction restriction = new XmlSchemaSimpleTypeRestriction();
Element restAnnotationEl = XDOMUtil.getFirstChildElementNS(
restrictionEl, XmlSchema.SCHEMA_NS, "annotation");
if (restAnnotationEl != null) {
XmlSchemaAnnotation restAnnotation = handleAnnotation(restAnnotationEl);
restriction.setAnnotation(restAnnotation);
}
/** if (restriction has a base attribute )
* set the baseTypeName and look up the base type
* else if( restricion has a SimpleType Element as child)
* get that element and do a handleSimpleType;
* get the children of restriction other than annotation
* and simpleTypes and construct facets from it;
*
* set the restriction has the content of the simpleType
*
**/
Element inlineSimpleType = XDOMUtil.getFirstChildElementNS(
restrictionEl, XmlSchema.SCHEMA_NS, "simpleType");
if (restrictionEl.hasAttribute("base")) {
NamespaceContext ctx = NodeNamespaceContext.getNamespaceContext(restrictionEl);
restriction.baseTypeName = getRefQName(restrictionEl
.getAttribute("base"), ctx);
} else if (inlineSimpleType != null) {
restriction.baseType = handleSimpleType(schema,
inlineSimpleType, schemaEl);
}
for (Element el = XDOMUtil.getFirstChildElementNS(restrictionEl,
XmlSchema.SCHEMA_NS); el != null; el = XDOMUtil
.getNextSiblingElementNS(el, XmlSchema.SCHEMA_NS)) {
if (!el.getLocalName().equals("annotation")
&& !el.getLocalName().equals("simpleType")) {
XmlSchemaFacet facet = XmlSchemaFacet.construct(el);
Element annotation = XDOMUtil.getFirstChildElementNS(el,
XmlSchema.SCHEMA_NS, "annotation");
if (annotation != null) {
XmlSchemaAnnotation facetAnnotation = handleAnnotation(annotation);
facet.setAnnotation(facetAnnotation);
}
restriction.facets.add(facet);
}
}
simpleType.content = restriction;
} else if ((listEl = XDOMUtil.getFirstChildElementNS(simpleEl,
XmlSchema.SCHEMA_NS, "list")) != null) {
XmlSchemaSimpleTypeList list = new XmlSchemaSimpleTypeList();
/******
* if( list has an itemType attribute )
* set the baseTypeName and look up the base type
* else if( list has a SimpleTypeElement as child)
* get that element and do a handleSimpleType
*
* set the list has the content of the simpleType
*/
Element inlineListType, listAnnotationEl;
if (listEl.hasAttribute("itemType")) {
String name = listEl.getAttribute("itemType");
list.itemTypeName = getRefQName(name, listEl);
} else if ((inlineListType = XDOMUtil.getFirstChildElementNS(
listEl, XmlSchema.SCHEMA_NS, "simpleType")) != null) {
list.itemType = handleSimpleType(schema, inlineListType,
schemaEl);
}
if ((listAnnotationEl = XDOMUtil.getFirstChildElementNS(listEl,
XmlSchema.SCHEMA_NS, "annotation")) != null) {
XmlSchemaAnnotation listAnnotation = handleAnnotation(listAnnotationEl);
list.setAnnotation(listAnnotation);
}
simpleType.content = list;
} else if ((unionEl = XDOMUtil.getFirstChildElementNS(simpleEl,
XmlSchema.SCHEMA_NS, "union")) != null) {
XmlSchemaSimpleTypeUnion union = new XmlSchemaSimpleTypeUnion();
/******
* if( union has a memberTypes attribute )
* add the memberTypeSources string
* for (each memberType in the list )
* lookup(memberType)
* for( all SimpleType child Elements)
* add the simpleTypeName (if any) to the memberType Sources
* do a handleSimpleType with the simpleTypeElement
*/
if (unionEl.hasAttribute("memberTypes")) {
String memberTypes = unionEl.getAttribute("memberTypes");
union.memberTypesSource = memberTypes;
Vector v = new Vector();
StringTokenizer tokenizer = new StringTokenizer(memberTypes,
" ");
while (tokenizer.hasMoreTokens()) {
String member = tokenizer.nextToken();
v.add(getRefQName(member, unionEl));
}
union.memberTypesQNames = new QName[v.size()];
v.copyInto(union.memberTypesQNames);
}
Element inlineUnionType = XDOMUtil.getFirstChildElementNS(unionEl,
XmlSchema.SCHEMA_NS, "simpleType");
while (inlineUnionType != null) {
XmlSchemaSimpleType unionSimpleType = handleSimpleType(schema,
inlineUnionType, schemaEl);
union.baseTypes.add(unionSimpleType);
if (unionSimpleType.name != null) {
union.memberTypesSource += " " + unionSimpleType.name;
}
inlineUnionType = XDOMUtil.getNextSiblingElementNS(
inlineUnionType, XmlSchema.SCHEMA_NS, "simpleType");
}
//NodeList annotations = unionEl.getElementsByTagNameNS(
//XmlSchema.SCHEMA_NS, "annotation");
Element unionAnnotationEl = XDOMUtil.getFirstChildElementNS(
unionEl, XmlSchema.SCHEMA_NS, "annotation");
if (unionAnnotationEl != null) {
XmlSchemaAnnotation unionAnnotation = handleAnnotation(unionAnnotationEl);
union.setAnnotation(unionAnnotation);
}
simpleType.content = union;
}
//process extra attributes and elements
processExtensibilityComponents(simpleType, simpleEl);
return simpleType;
}
private QName getRefQName(String pName, Node pNode) {
return getRefQName(pName, NodeNamespaceContext.getNamespaceContext(pNode));
}
private QName getRefQName(String pName, NamespaceContext pContext) {
final int offset = pName.indexOf(':');
String uri;
final String localName;
final String prefix;
if (offset == -1) {
uri = pContext.getNamespaceURI(Constants.DEFAULT_NS_PREFIX);
if (Constants.NULL_NS_URI.equals(uri)) {
return new QName(Constants.NULL_NS_URI, pName);
}
localName = pName;
prefix = Constants.DEFAULT_NS_PREFIX;
} else {
prefix = pName.substring(0, offset);
uri = pContext.getNamespaceURI(prefix);
if (uri == null || Constants.NULL_NS_URI.equals(uri)) {
if (schema.parent != null
&& schema.parent.getNamespaceContext() != null) {
uri = schema.parent.getNamespaceContext().getNamespaceURI(
prefix);
}
}
if (uri == null || Constants.NULL_NS_URI.equals(uri)) {
throw new IllegalStateException("The prefix " + prefix
+ " is not bound.");
}
localName = pName.substring(offset + 1);
}
return new QName(uri, localName, prefix);
}
/**
* Handle complex types
* @param schema
* @param complexEl
* @param schemaEl
*/
XmlSchemaComplexType handleComplexType(XmlSchema schema, Element complexEl,
Element schemaEl) {
/******
* set the complexTypeName if any
* for( eachChildNode)
* if ( simpleContent)
* if( restrcition)
* handle_simple_content_restriction
* else if( extension)
* handle_simple_content_extension
* break; // it has to be the only child
* else if( complexContent)
* if( restriction)
* handle_complex_content_restriction
* else if( extension)
* handle_complex_content_extension
* break; // it has to be the only child
* else if( group)
* if( group has ref)
* store the group name
* else
* handleGroup
* else if( sequence )
* handleSequence
* else if( all )
* handleAll
* else if(choice)
* handleChoice
* else if(attribute)
* handleAttribute
* else if(attributeGroup)
* handleAttributeGroup
* else if(anyAttribute)
* handleAnyAttribute
*/
XmlSchemaComplexType ct = new XmlSchemaComplexType(schema);
if (complexEl.hasAttribute("name")) {
//String namespace = (schema.targetNamespace==null)?
// "":schema.targetNamespace;
ct.name = complexEl.getAttribute("name");
}
for (Element el = XDOMUtil.getFirstChildElementNS(complexEl,
XmlSchema.SCHEMA_NS); el != null; el = XDOMUtil
.getNextSiblingElementNS(el, XmlSchema.SCHEMA_NS)) {
//String elPrefix = el.getPrefix() == null ? "" :
//el.getPrefix();
//if(elPrefix.equals(schema.schema_ns_prefix)) {
if (el.getLocalName().equals("sequence")) {
ct.particle = handleSequence(schema, el, schemaEl);
} else if (el.getLocalName().equals("choice")) {
ct.particle = handleChoice(schema, el, schemaEl);
} else if (el.getLocalName().equals("all")) {
ct.particle = handleAll(schema, el, schemaEl);
} else if (el.getLocalName().equals("attribute")) {
ct.attributes.add(handleAttribute(schema, el, schemaEl));
} else if (el.getLocalName().equals("attributeGroup")) {
ct.attributes.add(handleAttributeGroupRef(el));
} else if (el.getLocalName().equals("group")) {
XmlSchemaGroupRef group = handleGroupRef(schema, el, schemaEl);
ct.particle = (group.particle == null) ? (XmlSchemaParticle) group
: group.particle;
} else if (el.getLocalName().equals("simpleContent")) {
ct.contentModel = handleSimpleContent(schema, el, schemaEl);
} else if (el.getLocalName().equals("complexContent")) {
ct.contentModel = handleComplexContent(schema, el, schemaEl);
} else if (el.getLocalName().equals("annotation")) {
ct.setAnnotation(handleAnnotation(el));
} else if (el.getLocalName().equals("anyAttribute")) {
ct.setAnyAttribute(handleAnyAttribute(schema, el, schemaEl));
}
//}
}
if (complexEl.hasAttribute("block")) {
String blockStr = complexEl.getAttribute("block");
if (blockStr.equalsIgnoreCase("all")
| blockStr.equalsIgnoreCase("#all")) {
ct.setBlock(new XmlSchemaDerivationMethod(
Constants.BlockConstants.ALL));
} else
ct.setBlock(new XmlSchemaDerivationMethod(blockStr));
//ct.setBlock(new XmlSchemaDerivationMethod(block));
}
if (complexEl.hasAttribute("final")) {
String finalstr = complexEl.getAttribute("final");
if (finalstr.equalsIgnoreCase("all")
| finalstr.equalsIgnoreCase("#all")) {
ct.setFinal(new XmlSchemaDerivationMethod(
Constants.BlockConstants.ALL));
} else
ct.setFinal(new XmlSchemaDerivationMethod(finalstr));
}
if (complexEl.hasAttribute("abstract")) {
String abs = complexEl.getAttribute("abstract");
if (abs.equalsIgnoreCase("true"))
ct.setAbstract(true);
else
ct.setAbstract(false);
}
if (complexEl.hasAttribute("mixed")) {
String mixed = complexEl.getAttribute("mixed");
if (mixed.equalsIgnoreCase("true"))
ct.setMixed(true);
else
ct.setMixed(false);
}
//process extra attributes and elements
processExtensibilityComponents(ct, complexEl);
return ct;
}
private XmlSchemaSimpleContent handleSimpleContent(XmlSchema schema,
Element simpleEl, Element schemaEl) {
XmlSchemaSimpleContent simpleContent = new XmlSchemaSimpleContent();
for (Element el = XDOMUtil.getFirstChildElementNS(simpleEl,
XmlSchema.SCHEMA_NS); el != null; el = XDOMUtil
.getNextSiblingElementNS(el, XmlSchema.SCHEMA_NS)) {
if (el.getLocalName().equals("restriction")) {
simpleContent.content = handleSimpleContentRestriction(schema,
el, schemaEl);
} else if (el.getLocalName().equals("extension")) {
simpleContent.content = handleSimpleContentExtension(schema,
el, schemaEl);
} else if (el.getLocalName().equals("annotation")) {
simpleContent.setAnnotation(handleAnnotation(el));
}
}
return simpleContent;
}
private XmlSchemaComplexContent handleComplexContent(XmlSchema schema,
Element complexEl, Element schemaEl) {
XmlSchemaComplexContent complexContent = new XmlSchemaComplexContent();
for (Element el = XDOMUtil.getFirstChildElementNS(complexEl,
XmlSchema.SCHEMA_NS); el != null; el = XDOMUtil
.getNextSiblingElementNS(el, XmlSchema.SCHEMA_NS)) {
if (el.getLocalName().equals("restriction")) {
complexContent.content = handleComplexContentRestriction(
schema, el, schemaEl);
} else if (el.getLocalName().equals("extension")) {
complexContent.content = handleComplexContentExtension(schema,
el, schemaEl);
} else if (el.getLocalName().equals("annotation")) {
complexContent.setAnnotation(handleAnnotation(el));
}
}
if (complexEl.hasAttribute("mixed")) {
String mixed = complexEl.getAttribute("mixed");
if (mixed.equalsIgnoreCase("true"))
complexContent.setMixed(true);
else
complexContent.setMixed(false);
}
return complexContent;
}
private XmlSchemaSimpleContentRestriction handleSimpleContentRestriction(
XmlSchema schema, Element restrictionEl, Element schemaEl) {
XmlSchemaSimpleContentRestriction restriction = new XmlSchemaSimpleContentRestriction();
if (restrictionEl.hasAttribute("base")) {
String name = restrictionEl.getAttribute("base");
restriction.baseTypeName = getRefQName(name, restrictionEl);
}
if (restrictionEl.hasAttribute("id"))
restriction.id = restrictionEl.getAttribute("id");
// check back simpleContent tag children to add attributes and simpleType if any occur
for (Element el = XDOMUtil.getFirstChildElementNS(restrictionEl,
XmlSchema.SCHEMA_NS); el != null; el = XDOMUtil
.getNextSiblingElementNS(el, XmlSchema.SCHEMA_NS)) {
if (el.getLocalName().equals("attribute")) {
XmlSchemaAttribute attr = handleAttribute(schema, el, schemaEl);
restriction.attributes.add(attr);
} else if (el.getLocalName().equals("attributeGroup")) {
XmlSchemaAttributeGroupRef attrGroup = handleAttributeGroupRef(el);
restriction.attributes.add(attrGroup);
} else if (el.getLocalName().equals("simpleType")) {
restriction.baseType = handleSimpleType(schema, el, schemaEl);
} else if (el.getLocalName().equals("anyAttribute")) {
restriction.anyAttribute = handleAnyAttribute(schema, el,
schemaEl);
} else if (el.getLocalName().equals("annotation")) {
restriction.setAnnotation(handleAnnotation(el));
} else {
XmlSchemaFacet facet = XmlSchemaFacet.construct(el);
NodeList annotations = el.getElementsByTagNameNS(
XmlSchema.SCHEMA_NS, "annotation");
if (annotations.getLength() > 0) {
XmlSchemaAnnotation facetAnnotation = handleAnnotation(el);
facet.setAnnotation(facetAnnotation);
}
restriction.facets.add(facet);
}
}
return restriction;
}
private XmlSchemaSimpleContentExtension handleSimpleContentExtension(
XmlSchema schema, Element extEl, Element schemaEl) {
XmlSchemaSimpleContentExtension ext = new XmlSchemaSimpleContentExtension();
if (extEl.hasAttribute("base")) {
String name = extEl.getAttribute("base");
ext.baseTypeName = getRefQName(name, extEl);
}
for (Element el = XDOMUtil.getFirstChildElementNS(extEl,
XmlSchema.SCHEMA_NS); el != null; el = XDOMUtil
.getNextSiblingElementNS(el, XmlSchema.SCHEMA_NS)) {
if (el.getLocalName().equals("attribute")) {
XmlSchemaAttribute attr = handleAttribute(schema, el, schemaEl);
ext.attributes.add(attr);
} else if (el.getLocalName().equals("attributeGroup")) {
XmlSchemaAttributeGroupRef attrGroup = handleAttributeGroupRef(el);
ext.attributes.add(attrGroup);
} else if (el.getLocalName().equals("anyAttribute")) {
ext.anyAttribute = handleAnyAttribute(schema, el, schemaEl);
} else if (el.getLocalName().equals("annotation")) {
XmlSchemaAnnotation ann = handleAnnotation(el);
ext.setAnnotation(ann);
}
}
return ext;
}
private XmlSchemaComplexContentRestriction handleComplexContentRestriction(
XmlSchema schema, Element restrictionEl, Element schemaEl) {
XmlSchemaComplexContentRestriction restriction = new XmlSchemaComplexContentRestriction();
if (restrictionEl.hasAttribute("base")) {
String name = restrictionEl.getAttribute("base");
restriction.baseTypeName = getRefQName(name, restrictionEl);
}
for (Element el = XDOMUtil.getFirstChildElementNS(restrictionEl,
XmlSchema.SCHEMA_NS); el != null; el = XDOMUtil
.getNextSiblingElementNS(el, XmlSchema.SCHEMA_NS)) {
if (el.getLocalName().equals("sequence")) {
restriction.particle = handleSequence(schema, el, schemaEl);
} else if (el.getLocalName().equals("choice")) {
restriction.particle = handleChoice(schema, el, schemaEl);
} else if (el.getLocalName().equals("all")) {
restriction.particle = handleAll(schema, el, schemaEl);
} else if (el.getLocalName().equals("attribute")) {
restriction.attributes
.add(handleAttribute(schema, el, schemaEl));
} else if (el.getLocalName().equals("attributeGroup")) {
restriction.attributes.add(handleAttributeGroupRef(el));
} else if (el.getLocalName().equals("group")) {
restriction.particle = handleGroupRef(schema, el, schemaEl);
} else if (el.getLocalName().equals("anyAttribute")) {
restriction.anyAttribute = handleAnyAttribute(schema, el,
schemaEl);
} else if (el.getLocalName().equals("annotation")) {
restriction.setAnnotation(handleAnnotation(el));
}
}
return restriction;
}
private XmlSchemaComplexContentExtension handleComplexContentExtension(
XmlSchema schema, Element extEl, Element schemaEl) {
XmlSchemaComplexContentExtension ext = new XmlSchemaComplexContentExtension();
if (extEl.hasAttribute("base")) {
String name = extEl.getAttribute("base");
ext.baseTypeName = getRefQName(name, extEl);
}
for (Element el = XDOMUtil.getFirstChildElementNS(extEl,
XmlSchema.SCHEMA_NS); el != null; el = XDOMUtil
.getNextSiblingElementNS(el, XmlSchema.SCHEMA_NS)) {
if (el.getLocalName().equals("sequence")) {
ext.particle = handleSequence(schema, el, schemaEl);
} else if (el.getLocalName().equals("choice")) {
ext.particle = handleChoice(schema, el, schemaEl);
} else if (el.getLocalName().equals("all")) {
ext.particle = handleAll(schema, el, schemaEl);
} else if (el.getLocalName().equals("attribute")) {
ext.attributes.add(handleAttribute(schema, el, schemaEl));
} else if (el.getLocalName().equals("attributeGroup")) {
ext.attributes.add(handleAttributeGroupRef(el));
} else if (el.getLocalName().equals("group")) {
ext.particle = handleGroupRef(schema, el, schemaEl);
} else if (el.getLocalName().equals("anyAttribute")) {
ext.anyAttribute = handleAnyAttribute(schema, el, schemaEl);
} else if (el.getLocalName().equals("annotation")) {
ext.setAnnotation(handleAnnotation(el));
}
}
return ext;
}
private XmlSchemaAttributeGroupRef handleAttributeGroupRef(
Element attrGroupEl) {
XmlSchemaAttributeGroupRef attrGroup = new XmlSchemaAttributeGroupRef();
if (attrGroupEl.hasAttribute("ref")) {
String ref = attrGroupEl.getAttribute("ref");
attrGroup.refName = getRefQName(ref, attrGroupEl);
}
if (attrGroupEl.hasAttribute("id"))
attrGroup.id = attrGroupEl.getAttribute("id");
Element annotationEl = XDOMUtil.getFirstChildElementNS(attrGroupEl,
XmlSchema.SCHEMA_NS, "annotation");
if (annotationEl != null) {
XmlSchemaAnnotation annotation = handleAnnotation(annotationEl);
attrGroup.setAnnotation(annotation);
}
return attrGroup;
}
private XmlSchemaSequence handleSequence(XmlSchema schema,
Element sequenceEl, Element schemaEl) {
XmlSchemaSequence sequence = new XmlSchemaSequence();
//handle min and max occurences
sequence.minOccurs = getMinOccurs(sequenceEl);
sequence.maxOccurs = getMaxOccurs(sequenceEl);
for (Element el = XDOMUtil.getFirstChildElementNS(sequenceEl,
XmlSchema.SCHEMA_NS); el != null; el = XDOMUtil
.getNextSiblingElementNS(el, XmlSchema.SCHEMA_NS)) {
if (el.getLocalName().equals("sequence")) {
XmlSchemaSequence seq = handleSequence(schema, el, schemaEl);
sequence.items.add(seq);
} else if (el.getLocalName().equals("element")) {
XmlSchemaElement element = handleElement(schema, el, schemaEl,
false);
sequence.items.add(element);
} else if (el.getLocalName().equals("group")) {
XmlSchemaGroupRef group = handleGroupRef(schema, el, schemaEl);
sequence.items.add(group);
} else if (el.getLocalName().equals("choice")) {
XmlSchemaChoice choice = handleChoice(schema, el, schemaEl);
sequence.items.add(choice);
} else if (el.getLocalName().equals("any")) {
XmlSchemaAny any = handleAny(schema, el, schemaEl);
sequence.items.add(any);
} else if (el.getLocalName().equals("annotation")) {
XmlSchemaAnnotation annotation = handleAnnotation(el);
sequence.setAnnotation(annotation);
}
}
return sequence;
}
/** @noinspection UnusedParameters*/
private XmlSchemaAny handleAny(XmlSchema schema, Element anyEl,
Element schemaEl) {
XmlSchemaAny any = new XmlSchemaAny();
if (anyEl.hasAttribute("namespace"))
any.namespace = anyEl.getAttribute("namespace");
if (anyEl.hasAttribute("processContents")) {
String processContent = getEnumString(anyEl, "processContents");
any.processContent = new XmlSchemaContentProcessing(processContent);
}
Element annotationEl = XDOMUtil.getFirstChildElementNS(anyEl,
XmlSchema.SCHEMA_NS, "annotation");
if (annotationEl != null) {
XmlSchemaAnnotation annotation = handleAnnotation(annotationEl);
any.setAnnotation(annotation);
}
any.minOccurs = getMinOccurs(anyEl);
any.maxOccurs = getMaxOccurs(anyEl);
return any;
}
private XmlSchemaChoice handleChoice(XmlSchema schema, Element choiceEl,
Element schemaEl) {
XmlSchemaChoice choice = new XmlSchemaChoice();
if (choiceEl.hasAttribute("id"))
choice.id = choiceEl.getAttribute("id");
choice.minOccurs = getMinOccurs(choiceEl);
choice.maxOccurs = getMaxOccurs(choiceEl);
for (Element el = XDOMUtil.getFirstChildElementNS(choiceEl,
XmlSchema.SCHEMA_NS); el != null; el = XDOMUtil
.getNextSiblingElementNS(el, XmlSchema.SCHEMA_NS)) {
if (el.getLocalName().equals("sequence")) {
XmlSchemaSequence seq = handleSequence(schema, el, schemaEl);
choice.items.add(seq);
} else if (el.getLocalName().equals("element")) {
XmlSchemaElement element = handleElement(schema, el, schemaEl,
false);
choice.items.add(element);
} else if (el.getLocalName().equals("group")) {
XmlSchemaGroupRef group = handleGroupRef(schema, el, schemaEl);
choice.items.add(group);
} else if (el.getLocalName().equals("choice")) {
XmlSchemaChoice choiceItem = handleChoice(schema, el, schemaEl);
choice.items.add(choiceItem);
} else if (el.getLocalName().equals("any")) {
XmlSchemaAny any = handleAny(schema, el, schemaEl);
choice.items.add(any);
} else if (el.getLocalName().equals("annotation")) {
XmlSchemaAnnotation annotation = handleAnnotation(el);
choice.setAnnotation(annotation);
}
}
return choice;
}
private XmlSchemaAll handleAll(XmlSchema schema, Element allEl,
Element schemaEl) {
XmlSchemaAll all = new XmlSchemaAll();
//handle min and max occurences
all.minOccurs = getMinOccurs(allEl);
all.maxOccurs = getMaxOccurs(allEl);
for (Element el = XDOMUtil.getFirstChildElementNS(allEl,
XmlSchema.SCHEMA_NS); el != null; el = XDOMUtil
.getNextSiblingElementNS(el, XmlSchema.SCHEMA_NS)) {
if (el.getLocalName().equals("element")) {
XmlSchemaElement element = handleElement(schema, el, schemaEl,
false);
all.items.add(element);
} else if (el.getLocalName().equals("annotation")) {
XmlSchemaAnnotation annotation = handleAnnotation(el);
all.setAnnotation(annotation);
}
}
return all;
}
private XmlSchemaGroup handleGroup(XmlSchema schema, Element groupEl,
Element schemaEl) {
XmlSchemaGroup group = new XmlSchemaGroup();
group.name = new QName(schema.getTargetNamespace(), groupEl
.getAttribute("name"));
for (Element el = XDOMUtil.getFirstChildElementNS(groupEl,
XmlSchema.SCHEMA_NS); el != null; el = XDOMUtil
.getNextSiblingElementNS(el, XmlSchema.SCHEMA_NS)) {
if (el.getLocalName().equals("all")) {
group.particle = handleAll(schema, el, schemaEl);
} else if (el.getLocalName().equals("sequence")) {
group.particle = handleSequence(schema, el, schemaEl);
} else if (el.getLocalName().equals("choice")) {
group.particle = handleChoice(schema, el, schemaEl);
} else if (el.getLocalName().equals("annotation")) {
XmlSchemaAnnotation groupAnnotation = handleAnnotation(el);
group.setAnnotation(groupAnnotation);
}
}
return group;
}
private XmlSchemaAttributeGroup handleAttributeGroup(XmlSchema schema,
Element groupEl, Element schemaEl) {
XmlSchemaAttributeGroup attrGroup = new XmlSchemaAttributeGroup();
if (groupEl.hasAttribute("name"))
attrGroup.name = new QName(schema.getTargetNamespace(), groupEl
.getAttribute("name"));
if (groupEl.hasAttribute("id"))
attrGroup.id = groupEl.getAttribute("id");
for (Element el = XDOMUtil.getFirstChildElementNS(groupEl,
XmlSchema.SCHEMA_NS); el != null; el = XDOMUtil
.getNextSiblingElementNS(el, XmlSchema.SCHEMA_NS)) {
if (el.getLocalName().equals("attribute")) {
XmlSchemaAttribute attr = handleAttribute(schema, el, schemaEl);
attrGroup.attributes.add(attr);
} else if (el.getLocalName().equals("attributeGroup")) {
XmlSchemaAttributeGroupRef attrGroupRef = handleAttributeGroupRef(el);
attrGroup.attributes.add(attrGroupRef);
} else if (el.getLocalName().equals("anyAttribute")) {
attrGroup.anyAttribute = handleAnyAttribute(schema, el,
schemaEl);
} else if (el.getLocalName().equals("annotation")) {
XmlSchemaAnnotation ann = handleAnnotation(el);
attrGroup.setAnnotation(ann);
}
}
return attrGroup;
}
/** @noinspection UnusedParameters*/
private XmlSchemaAnyAttribute handleAnyAttribute(XmlSchema schema,
Element anyAttrEl, Element schemaEl) {
XmlSchemaAnyAttribute anyAttr = new XmlSchemaAnyAttribute();
if (anyAttrEl.hasAttribute("namespace"))
anyAttr.namespace = anyAttrEl.getAttribute("namespace");
if (anyAttrEl.hasAttribute("processContents")) {
String contentProcessing = getEnumString(anyAttrEl,
"processContents");
anyAttr.processContent = new XmlSchemaContentProcessing(
contentProcessing);
}
if (anyAttrEl.hasAttribute("id"))
anyAttr.id = anyAttrEl.getAttribute("id");
Element annotationEl = XDOMUtil.getFirstChildElementNS(anyAttrEl,
XmlSchema.SCHEMA_NS, "annotation");
if (annotationEl != null) {
XmlSchemaAnnotation annotation = handleAnnotation(annotationEl);
anyAttr.setAnnotation(annotation);
}
return anyAttr;
}
private XmlSchemaGroupRef handleGroupRef(XmlSchema schema, Element groupEl,
Element schemaEl) {
XmlSchemaGroupRef group = new XmlSchemaGroupRef();
group.maxOccurs = getMaxOccurs(groupEl);
group.minOccurs = getMinOccurs(groupEl);
Element annotationEl = XDOMUtil.getFirstChildElementNS(groupEl,
XmlSchema.SCHEMA_NS, "annotation");
if (annotationEl != null) {
XmlSchemaAnnotation annotation = handleAnnotation(annotationEl);
group.setAnnotation(annotation);
}
if (groupEl.hasAttribute("ref")) {
String ref = groupEl.getAttribute("ref");
group.refName = getRefQName(ref, groupEl);
return group;
}
for (Element el = XDOMUtil.getFirstChildElementNS(groupEl,
XmlSchema.SCHEMA_NS); el != null; el = XDOMUtil
.getNextSiblingElement(el)) {
if (el.getLocalName().equals("sequence")) {
group.particle = handleSequence(schema, el, schemaEl);
} else if (el.getLocalName().equals("all")) {
group.particle = handleAll(schema, el, schemaEl);
} else if (el.getLocalName().equals("choice")) {
group.particle = handleChoice(schema, el, schemaEl);
}
}
return group;
}
private QName newLocalQName(String pLocalName) {
String uri = schema.logicalTargetNamespace;
if (uri == null) {
uri = Constants.NULL_NS_URI;
}
return new QName(uri, pLocalName);
}
/**
* Process non-toplevel attributes
* @param schema
* @param attrEl
* @param schemaEl
* @return
*/
private XmlSchemaAttribute handleAttribute(XmlSchema schema,
Element attrEl, Element schemaEl) {
return handleAttribute(schema, attrEl, schemaEl, false);
}
/**
* Process attributes
* @param schema
* @param attrEl
* @param schemaEl
* @param topLevel
* @return
*/
private XmlSchemaAttribute handleAttribute(XmlSchema schema,
Element attrEl, Element schemaEl, boolean topLevel) {
//todo: need to implement different rule of attribute such as
//restriction between ref and name. This can be implemented
//in the compile function
XmlSchemaAttribute attr = new XmlSchemaAttribute();
if (attrEl.hasAttribute("name")) {
String name = attrEl.getAttribute("name");
//String namespace = (schema.targetNamespace==null)?
// "" :schema.targetNamespace;
attr.name = name;
}
boolean isQualified = schema.getAttributeFormDefault().getValue()
.equals(XmlSchemaForm.QUALIFIED);
if (attr.name != null) {
final String name = attr.name;
if (topLevel) {
attr.qualifiedName = newLocalQName(name);
} else {
attr.qualifiedName = (isQualified) ? newLocalQName(name)
: new QName(name);
}
}
if (attrEl.hasAttribute("type")) {
String name = attrEl.getAttribute("type");
attr.schemaTypeName = getRefQName(name, attrEl);
}
if (attrEl.hasAttribute("default"))
attr.defaultValue = attrEl.getAttribute("default");
if (attrEl.hasAttribute("fixed"))
attr.fixedValue = attrEl.getAttribute("fixed");
if (attrEl.hasAttribute("form")) {
String formValue = getEnumString(attrEl, "form");
attr.form = new XmlSchemaForm(formValue);
}
if (attrEl.hasAttribute("id"))
attr.id = attrEl.getAttribute("id");
if (attrEl.hasAttribute("use")) {
String useType = getEnumString(attrEl, "use");
attr.use = new XmlSchemaUse(useType);
}
if (attrEl.hasAttribute("ref")) {
String name = attrEl.getAttribute("ref");
attr.refName = getRefQName(name, attrEl);
attr.name = name;
}
Element simpleTypeEl = XDOMUtil.getFirstChildElementNS(attrEl,
XmlSchema.SCHEMA_NS, "simpleType");
if (simpleTypeEl != null) {
attr.schemaType = handleSimpleType(schema, simpleTypeEl, schemaEl);
}
Element annotationEl = XDOMUtil.getFirstChildElementNS(attrEl,
XmlSchema.SCHEMA_NS, "annotation");
if (annotationEl != null) {
XmlSchemaAnnotation annotation = handleAnnotation(annotationEl);
attr.setAnnotation(annotation);
}
NamedNodeMap attrNodes = attrEl.getAttributes();
Vector attrs = new Vector();
NodeNamespaceContext ctx = null;
for (int i = 0; i < attrNodes.getLength(); i++) {
Attr att = (Attr) attrNodes.item(i);
String attName = att.getName();
if (!attName.equals("name") && !attName.equals("type")
&& !attName.equals("default") && !attName.equals("fixed")
&& !attName.equals("form") && !attName.equals("id")
&& !attName.equals("use") && !attName.equals("ref")) {
attrs.add(att);
String value = att.getValue();
if (value.indexOf(":") > -1) {
// there is a possiblily of some namespace mapping
String prefix = value.substring(0, value.indexOf(":"));
if (ctx == null) {
ctx = NodeNamespaceContext.getNamespaceContext(attrEl);
}
String namespace = ctx.getNamespaceURI(prefix);
if (!Constants.NULL_NS_URI.equals(namespace)) {
Attr nsAttr = attrEl.getOwnerDocument()
.createAttribute("xmlns:" + prefix);
nsAttr.setValue(namespace);
attrs.add(nsAttr);
}
}
}
}
if (attrs.size() > 0)
attr.setUnhandledAttributes((Attr[]) attrs.toArray(new Attr[0]));
//process extra attributes and elements
processExtensibilityComponents(attr, attrEl);
return attr;
}
/*
* handle_simple_content_restriction
*
* if( restriction has base attribute )
* set the baseType
* else if( restriciton has an inline simpleType )
* handleSimpleType
* add facets if any to the restriction
*/
/*
* handle_simple_content_extension
*
* extension should have a base name and cannot have any inline defn
* for( each childNode )
* if( attribute)
* handleAttribute
* else if( attributeGroup)
* handleAttributeGroup
* else if( anyAttribute)
* handleAnyAttribute
*/
/*
* ********
* handle_complex_content_restriction
*/
/**
* handle elements
* @param schema
* @param el
* @param schemaEl
* @param isGlobal
*/
XmlSchemaElement handleElement(XmlSchema schema, Element el,
Element schemaEl, boolean isGlobal) {
XmlSchemaElement element = new XmlSchemaElement();
if (el.getAttributeNode("name") != null)
element.name = el.getAttribute("name");
// String namespace = (schema.targetNamespace==null)?
// "" : schema.targetNamespace;
boolean isQualified = schema.getElementFormDefault().getValue().equals(
XmlSchemaForm.QUALIFIED);
if (el.hasAttribute("form")) {
String formDef = el.getAttribute("form");
element.form = new XmlSchemaForm(formDef);
isQualified = formDef.equals(XmlSchemaForm.QUALIFIED);
}
if (element.name != null) {
final String name = element.name;
element.qualifiedName = (isQualified || isGlobal) ? newLocalQName(name)
: new QName(Constants.NULL_NS_URI, name);
}
Element annotationEl = XDOMUtil.getFirstChildElementNS(el,
XmlSchema.SCHEMA_NS, "annotation");
if (annotationEl != null) {
XmlSchemaAnnotation annotation = handleAnnotation(annotationEl);
element.setAnnotation(annotation);
}
if (el.getAttributeNode("type") != null) {
String typeName = el.getAttribute("type");
QName typeQName = element.schemaTypeName = getRefQName(typeName, el);
XmlSchemaType type = collection.getTypeByQName(typeQName);
if (type == null) {
// Could be a forward reference...
collection.addUnresolvedType(typeQName, element);
}
element.schemaType = type;
} else if (el.getAttributeNode("ref") != null) {
String refName = el.getAttribute("ref");
QName refQName = getRefQName(refName, el);
element.setRefName(refQName);
element.name = refQName.getLocalPart();
}
Element simpleTypeEl, complexTypeEl, keyEl, keyrefEl, uniqueEl;
if ((simpleTypeEl = XDOMUtil.getFirstChildElementNS(el,
XmlSchema.SCHEMA_NS, "simpleType")) != null) {
XmlSchemaSimpleType simpleType = handleSimpleType(schema,
simpleTypeEl, schemaEl);
element.schemaType = simpleType;
element.schemaTypeName = simpleType.getQName();
} else if ((complexTypeEl = XDOMUtil.getFirstChildElementNS(el,
XmlSchema.SCHEMA_NS, "complexType")) != null) {
element.schemaType = handleComplexType(schema, complexTypeEl,
schemaEl);
}
if ((keyEl = XDOMUtil.getFirstChildElementNS(el, XmlSchema.SCHEMA_NS,
"key")) != null) {
while (keyEl != null) {
element.constraints.add(handleConstraint(keyEl, "Key"));
keyEl = XDOMUtil.getNextSiblingElement(keyEl, "key");
}
}
if ((keyrefEl = XDOMUtil.getFirstChildElementNS(el,
XmlSchema.SCHEMA_NS, "keyref")) != null) {
while (keyrefEl != null) {
XmlSchemaKeyref keyRef = (XmlSchemaKeyref) handleConstraint(
keyrefEl, "Keyref");
if (keyrefEl.hasAttribute("refer")) {
String name = keyrefEl.getAttribute("refer");
keyRef.refer = getRefQName(name, el);
}
element.constraints.add(keyRef);
keyrefEl = XDOMUtil.getNextSiblingElement(keyrefEl, "keyref");
}
}
if ((uniqueEl = XDOMUtil.getFirstChildElementNS(el,
XmlSchema.SCHEMA_NS, "unique")) != null) {
while (uniqueEl != null) {
element.constraints.add(handleConstraint(uniqueEl, "Unique"));
uniqueEl = XDOMUtil.getNextSiblingElement(uniqueEl, "unique");
}
}
if (el.hasAttribute("abstract")) {
element.isAbstract = Boolean.valueOf(el.getAttribute("abstract"))
.booleanValue();
}
if (el.hasAttribute("block"))
element.block = getDerivation(el, "block");
if (el.hasAttribute("default"))
element.defaultValue = el.getAttribute("default");
if (el.hasAttribute("final"))
element.finalDerivation = getDerivation(el, "final");
if (el.hasAttribute("fixed"))
element.fixedValue = el.getAttribute("fixed");
if (el.hasAttribute("id"))
element.id = el.getAttribute("id");
if (el.hasAttribute("nillable"))
element.isNillable = Boolean.valueOf(el.getAttribute("nillable"))
.booleanValue();
if (el.hasAttribute("substitutionGroup")) {
String substitutionGroup = el.getAttribute("substitutionGroup");
element.setSubstitutionGroup(getRefQName(substitutionGroup, el));
}
element.minOccurs = getMinOccurs(el);
element.maxOccurs = getMaxOccurs(el);
//process extra attributes and elements
processExtensibilityComponents(element, el);
return element;
}
private XmlSchemaIdentityConstraint handleConstraint(Element constraintEl,
String type) {
try {
XmlSchemaIdentityConstraint constraint = (XmlSchemaIdentityConstraint) Class
.forName("org.apache.ws.commons.schema.XmlSchema" + type)
.newInstance();
if (constraintEl.hasAttribute("name"))
constraint.name = constraintEl.getAttribute("name");
if (constraintEl.hasAttribute("refer")) {
String name = constraintEl.getAttribute("refer");
((XmlSchemaKeyref) constraint).refer = getRefQName(name,
constraintEl);
}
for (Element el = XDOMUtil.getFirstChildElementNS(constraintEl,
XmlSchema.SCHEMA_NS); el != null; el = XDOMUtil
.getNextSiblingElementNS(el, XmlSchema.SCHEMA_NS)) {
// String elPrefix = el.getPrefix() == null ? ""
// : el.getPrefix();
//if(elPrefix.equals(schema.schema_ns_prefix)) {
if (el.getLocalName().equals("selector")) {
XmlSchemaXPath selectorXPath = new XmlSchemaXPath();
selectorXPath.xpath = el.getAttribute("xpath");
Element annotationEl = XDOMUtil.getFirstChildElementNS(el,
XmlSchema.SCHEMA_NS, "annotation");
if (annotationEl != null) {
XmlSchemaAnnotation annotation = handleAnnotation(annotationEl);
selectorXPath.setAnnotation(annotation);
}
constraint.selector = selectorXPath;
} else if (el.getLocalName().equals("field")) {
XmlSchemaXPath fieldXPath = new XmlSchemaXPath();
fieldXPath.xpath = el.getAttribute("xpath");
constraint.fields.add(fieldXPath);
Element annotationEl = XDOMUtil.getFirstChildElementNS(el,
XmlSchema.SCHEMA_NS, "annotation");
if (annotationEl != null) {
XmlSchemaAnnotation annotation = handleAnnotation(annotationEl);
fieldXPath.setAnnotation(annotation);
}
} else if (el.getLocalName().equals("annotation")) {
XmlSchemaAnnotation constraintAnnotation = handleAnnotation(el);
constraint.setAnnotation(constraintAnnotation);
}
}
return constraint;
} catch (ClassNotFoundException e) {
throw new XmlSchemaException(e.getMessage());
} catch (InstantiationException e) {
throw new XmlSchemaException(e.getMessage());
} catch (IllegalAccessException e) {
throw new XmlSchemaException(e.getMessage());
}
}
/**
* Hanlde the import
* @param schema
* @param importEl
* @param schemaEl
* @return XmlSchemaObject
*/
XmlSchemaImport handleImport(XmlSchema schema, Element importEl,
Element schemaEl) {
XmlSchemaImport schemaImport = new XmlSchemaImport();
Element annotationEl = XDOMUtil.getFirstChildElementNS(importEl,
XmlSchema.SCHEMA_NS, "annotation");
if (annotationEl != null) {
XmlSchemaAnnotation importAnnotation = handleAnnotation(annotationEl);
schemaImport.setAnnotation(importAnnotation);
}
final String uri = schemaImport.namespace = importEl
.getAttribute("namespace");
schemaImport.schemaLocation = importEl.getAttribute("schemaLocation");
TargetNamespaceValidator validator = new TargetNamespaceValidator() {
private boolean isEmpty(String pValue) {
return pValue == null || Constants.NULL_NS_URI.equals(pValue);
}
public void validate(XmlSchema pSchema) {
final boolean valid;
if (isEmpty(uri)) {
valid = isEmpty(pSchema.syntacticalTargetNamespace);
} else {
valid = pSchema.syntacticalTargetNamespace.equals(uri);
}
if (!valid) {
throw new XmlSchemaException(
"An imported schema was announced to have the namespace "
+ uri + ", but has the namespace "
+ pSchema.syntacticalTargetNamespace);
}
}
};
if ((schemaImport.schemaLocation != null)
&& (!schemaImport.schemaLocation.equals(""))) {
if (schema.getSourceURI() != null) {
schemaImport.schema = resolveXmlSchema(uri,
schemaImport.schemaLocation, schema.getSourceURI(),
validator);
} else {
schemaImport.schema = resolveXmlSchema(schemaImport.namespace,
schemaImport.schemaLocation, validator);
}
}
return schemaImport;
}
/**
* Handles the include
* @param schema
* @param includeEl
* @param schemaEl
*/
XmlSchemaInclude handleInclude(final XmlSchema schema, Element includeEl,
Element schemaEl) {
XmlSchemaInclude include = new XmlSchemaInclude();
Element annotationEl = XDOMUtil.getFirstChildElementNS(includeEl,
XmlSchema.SCHEMA_NS, "annotation");
if (annotationEl != null) {
XmlSchemaAnnotation includeAnnotation = handleAnnotation(annotationEl);
include.setAnnotation(includeAnnotation);
}
include.schemaLocation = includeEl.getAttribute("schemaLocation");
//includes are not supposed to have a target namespace
// we should be passing in a null in place of the target
//namespace
final TargetNamespaceValidator validator = newIncludeValidator(schema);
if (schema.getSourceURI() != null) {
include.schema = resolveXmlSchema(schema.logicalTargetNamespace,
include.schemaLocation, schema.getSourceURI(), validator);
} else {
include.schema = resolveXmlSchema(schema.logicalTargetNamespace,
include.schemaLocation, validator);
}
//process extra attributes and elements
processExtensibilityComponents(include, includeEl);
return include;
}
private TargetNamespaceValidator newIncludeValidator(final XmlSchema schema) {
return new TargetNamespaceValidator() {
private boolean isEmpty(String pValue) {
return pValue == null || Constants.NULL_NS_URI.equals(pValue);
}
public void validate(XmlSchema pSchema) {
if (isEmpty(pSchema.syntacticalTargetNamespace)) {
pSchema.logicalTargetNamespace = schema.logicalTargetNamespace;
} else {
if (!pSchema.syntacticalTargetNamespace
.equals(schema.logicalTargetNamespace)) {
String msg = "An included schema was announced to have the default target namespace";
if (!isEmpty(schema.logicalTargetNamespace)) {
msg += " or the target namespace "
+ schema.logicalTargetNamespace;
}
throw new XmlSchemaException(msg
+ ", but has the target namespace "
+ pSchema.logicalTargetNamespace);
}
}
}
};
}
/**
* Handles the annotation
* Traversing if encounter appinfo or documentation
* add it to annotation collection
*
*/
XmlSchemaAnnotation handleAnnotation(Element annotEl) {
XmlSchemaObjectCollection content = new XmlSchemaObjectCollection();
XmlSchemaAppInfo appInfoObj;
XmlSchemaDocumentation docsObj;
for (Element appinfo = XDOMUtil.getFirstChildElementNS(annotEl,
XmlSchema.SCHEMA_NS, "appinfo"); appinfo != null; appinfo = XDOMUtil
.getNextSiblingElementNS(appinfo, XmlSchema.SCHEMA_NS,
"appinfo")) {
appInfoObj = handleAppInfo(appinfo);
if (appInfoObj != null) {
content.add(appInfoObj);
}
}
for (Element documentation = XDOMUtil.getFirstChildElementNS(annotEl,
XmlSchema.SCHEMA_NS, "documentation"); documentation != null; documentation = XDOMUtil
.getNextSiblingElementNS(documentation,
XmlSchema.SCHEMA_NS, "documentation")) {
docsObj = handleDocumentation(documentation);
if (docsObj != null) {
content.add(docsObj);
}
}
XmlSchemaAnnotation annotation = new XmlSchemaAnnotation();
annotation.items = content;
//process extra attributes and elements
processExtensibilityComponents(annotation, annotEl);
return annotation;
}
/**
* create new XmlSchemaAppinfo and add value goten from element
* to this obj
* @param content
*/
XmlSchemaAppInfo handleAppInfo(Element content) {
XmlSchemaAppInfo appInfo = new XmlSchemaAppInfo();
NodeList markup = getChildren(content);
if (!content.hasAttribute("source")
&& (markup == null || markup.getLength() <= 0)) {
return null;
}
appInfo.setSource(getAttribute(content, "source"));
appInfo.setMarkup(markup);
return appInfo;
}
//iterate each documentation element, create new XmlSchemaAppinfo and add to collection
XmlSchemaDocumentation handleDocumentation(Element content) {
XmlSchemaDocumentation documentation = new XmlSchemaDocumentation();
NodeList markup = getChildren(content);
if (!content.hasAttribute("source")
&& !content.hasAttribute("xml:lang")
&& (markup == null || markup.getLength() <= 0))
return null;
documentation.setSource(getAttribute(content, "source"));
documentation.setLanguage(getAttribute(content, "xml:lang"));
documentation.setMarkup(getChildren(content));
return documentation;
}
private String getAttribute(Element content, String attrName) {
if (content.hasAttribute(attrName))
return content.getAttribute(attrName);
return null;
}
private NodeList getChildren(Element content) {
NodeList childs = content.getChildNodes();
if (childs.getLength() > 0)
return childs;
return null;
}
long getMinOccurs(Element el) {
try {
if (el.getAttributeNode("minOccurs") != null) {
String value = el.getAttribute("minOccurs");
if (value.equals("unbounded"))
return Long.MAX_VALUE;
else
return Long.parseLong(value);
}
return 1;
} catch (java.lang.NumberFormatException e) {
return 1;
}
}
long getMaxOccurs(Element el) {
try {
if (el.getAttributeNode("maxOccurs") != null) {
String value = el.getAttribute("maxOccurs");
if (value.equals("unbounded"))
return Long.MAX_VALUE;
else
return Long.parseLong(value);
}
return 1;
} catch (java.lang.NumberFormatException e) {
return 1;
}
}
XmlSchemaForm getFormDefault(Element el, String attrName) {
if (el.getAttributeNode(attrName) != null) {
String value = el.getAttribute(attrName);
return new XmlSchemaForm(value);
} else
return new XmlSchemaForm("unqualified");
}
//Check value entered by user and change according to .net spec,
//according to w3c spec have to be "#all"
//but in .net the valid enum value is "all".
XmlSchemaDerivationMethod getDerivation(Element el, String attrName) {
if (el.hasAttribute(attrName) && !el.getAttribute(attrName).equals("")) {
//#all | List of (extension | restriction | substitution
String derivationMethod = el.getAttribute(attrName).trim();
if (derivationMethod.equals("#all"))
return new XmlSchemaDerivationMethod(
Constants.BlockConstants.ALL);
else
return new XmlSchemaDerivationMethod(derivationMethod);
}
return new XmlSchemaDerivationMethod(Constants.BlockConstants.NONE);
}
//Check value entered by user and change according to .net spec, user
String getEnumString(Element el, String attrName) {
if (el.hasAttribute(attrName)) {
return el.getAttribute(attrName).trim();
}
return Constants.BlockConstants.NONE;
}
/**
* Resolve the schemas
* @param targetNamespace
* @param schemaLocation
*/
XmlSchema resolveXmlSchema(String targetNamespace, String schemaLocation,
String baseUri, TargetNamespaceValidator validator) {
String schemaKey = null;
if (resolvedSchemas != null) { // cache is initialized, use it
// Not being very smart about this at the moment. One could, for example,
// see that the schemaLocation or baseUri is the same as another, but differs
// only by a trailing slash. As it is now, we assume a single character difference
// means it's a schema that has yet to be resolved.
schemaKey = Thread.currentThread().getId() + targetNamespace + schemaLocation + baseUri;
SoftReference softref = (SoftReference)resolvedSchemas.get(schemaKey);
if (softref != null) {
XmlSchema resolvedSchema = (XmlSchema)softref.get();
if (resolvedSchema != null) {
return resolvedSchema;
}
}
}
//use the entity resolver provided if the schema location is present null
if (schemaLocation != null && !"".equals(schemaLocation)) {
InputSource source = collection.getSchemaResolver().resolveEntity(
targetNamespace, schemaLocation, baseUri);
//the entity resolver was unable to resolve this!!
if (source == null) {
//try resolving it with the target namespace only with the
//known namespace map
XmlSchema schema = collection.getKnownSchema(targetNamespace);
if (schema != null) {
return schema;
}else{
return null;
}
}
final String systemId = source.getSystemId() == null ? schemaLocation
: source.getSystemId();
// Push repaired system id back into source where read sees it.
// It is perhaps a bad thing to patch the source, but this fixes
// a problem.
source.setSystemId(systemId);
final SchemaKey key = new XmlSchemaCollection.SchemaKey(
targetNamespace, systemId);
XmlSchema schema = collection.getSchema(key);
if (schema != null) {
return schema;
}
if (collection.check(key)) {
collection.push(key);
try {
XmlSchema readSchema = collection.read(source, null, validator);
if (resolvedSchemas != null) {
resolvedSchemas.put(schemaKey, new SoftReference(readSchema));
}
return readSchema;
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
collection.pop();
}
}
}else{
XmlSchema schema = collection.getKnownSchema(targetNamespace);
if (schema != null) {
return schema;
}
}
return null;
}
/**
* Resolve the schemas
* @param targetNamespace
* @param schemaLocation
*/
XmlSchema resolveXmlSchema(String targetNamespace, String schemaLocation,
TargetNamespaceValidator validator) {
return resolveXmlSchema(targetNamespace, schemaLocation,
collection.baseUri, validator);
}
/**
* A generic method to process the extra attributes and the the extra
* elements present within the schema.
* What are considered extensions are child elements with non schema namespace
* and child attributes with any namespace
* @param schemaObject
* @param parentElement
*/
private void processExtensibilityComponents(XmlSchemaObject schemaObject,
Element parentElement) {
if (extReg != null) {
//process attributes
NamedNodeMap attributes = parentElement.getAttributes();
for (int i = 0; i < attributes.getLength(); i++) {
Attr attribute = (Attr) attributes.item(i);
String namespaceURI = attribute.getNamespaceURI();
String name = attribute.getLocalName();
if (namespaceURI != null
&& !"".equals(namespaceURI)
&& //ignore unqualified attributes
!namespaceURI
.startsWith(Constants.XMLNS_ATTRIBUTE_NS_URI) && //ignore namespaces
!Constants.URI_2001_SCHEMA_XSD.equals(namespaceURI))
//does not belong to the schema namespace by any chance!
{
QName qName = new QName(namespaceURI, name);
extReg.deserializeExtension(schemaObject, qName, attribute);
}
}
//process elements
Node child = parentElement.getFirstChild();
while (child != null) {
if (child.getNodeType() == Node.ELEMENT_NODE) {
Element extElement = (Element) child;
String namespaceURI = extElement.getNamespaceURI();
String name = extElement.getLocalName();
if (namespaceURI != null
&& !Constants.URI_2001_SCHEMA_XSD
.equals(namespaceURI))
//does not belong to the schema namespace
{
QName qName = new QName(namespaceURI, name);
extReg.deserializeExtension(schemaObject, qName,
extElement);
}
}
child = child.getNextSibling();
}
}
}
}