blob: 10af77c748f272afd5d7410083aa24b0762d2fd2 [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 java.lang.ref.SoftReference;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.Vector;
import javax.xml.namespace.NamespaceContext;
import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
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;
/**
* Object used to build a schema from a schema document. This object includes a cache of previously resolved
* schema documents. This cache might be useful 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
*/
public class SchemaBuilder {
// default access for unit tests.
static ThreadLocal<Map<String, SoftReference<XmlSchema>>> resolvedSchemas =
new ThreadLocal<Map<String, SoftReference<XmlSchema>>>();
private static final Set<String> RESERVED_ATTRIBUTES = new HashSet<String>();
private static final String[] RESERVED_ATTRIBUTES_LIST = {
"name", "type", "default", "fixed", "form", "id", "use", "ref"
};
XmlSchemaCollection collection;
Document currentDocument;
XmlSchema currentSchema;
DocumentBuilderFactory docFac;
private final TargetNamespaceValidator currentValidator;
/**
* The extension registry to be used while building the schema model
*/
private ExtensionRegistry extReg;
static {
for (String s : RESERVED_ATTRIBUTES_LIST) {
RESERVED_ATTRIBUTES.add(s);
}
}
/**
* Schema builder constructor
*
* @param collection
* @param validator
*/
SchemaBuilder(XmlSchemaCollection collection, TargetNamespaceValidator validator) {
this.collection = collection;
this.currentValidator = validator;
if (collection.getExtReg() != null) {
this.extReg = collection.getExtReg();
}
currentSchema = new XmlSchema();
}
/**
* Remove any entries from the cache for the current thread. Entries for other threads are not altered.
*/
public static void clearCache() {
Map<String, SoftReference<XmlSchema>> threadResolvedSchemas = resolvedSchemas.get();
if (threadResolvedSchemas != null) {
// goose the gc a bit.
threadResolvedSchemas.clear();
resolvedSchemas.remove();
}
}
/**
* Setup the cache to be used by the current thread of execution. Multiple threads can use the cache, and
* each one must call this method at some point prior to attempting to resolve the first schema, or the
* cache will not be used on that thread. IMPORTANT: The thread MUST call clearCache() when it is done
* with the schemas or a large amount of memory may remain in-use.
*/
public static void initCache() {
Map<String, SoftReference<XmlSchema>> threadResolvedSchemas = resolvedSchemas.get();
// If there is no entry yet for this thread ID, then create one
if (threadResolvedSchemas == null) {
threadResolvedSchemas =
Collections.synchronizedMap(new HashMap<String, SoftReference<XmlSchema>>());
resolvedSchemas.set(threadResolvedSchemas);
}
}
public ExtensionRegistry getExtReg() {
return extReg;
}
public void setExtReg(ExtensionRegistry extReg) {
this.extReg = extReg;
}
/**
* build method taking in a document and a uri
*
* @param doc
* @param uri
*/
XmlSchema build(Document doc, String uri) {
Element schemaEl = doc.getDocumentElement();
XmlSchema xmlSchema = handleXmlSchemaElement(schemaEl, uri);
xmlSchema.setInputEncoding(doc.getInputEncoding());
return xmlSchema;
}
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();
return XmlSchemaDerivationMethod.schemaValueOf(derivationMethod);
}
return XmlSchemaDerivationMethod.NONE;
}
String getEnumString(Element el, String attrName) {
if (el.hasAttribute(attrName)) {
return el.getAttribute(attrName).trim();
}
return "none"; // local convention for empty value.
}
XmlSchemaForm getFormDefault(Element el, String attrName) {
if (el.getAttributeNode(attrName) != null) {
String value = el.getAttribute(attrName);
return XmlSchemaForm.schemaValueOf(value);
} else {
return XmlSchemaForm.UNQUALIFIED;
}
}
long getMaxOccurs(Element el) {
try {
if (el.getAttributeNode("maxOccurs") != null) {
String value = el.getAttribute("maxOccurs");
if ("unbounded".equals(value)) {
return Long.MAX_VALUE;
} else {
return Long.parseLong(value);
}
}
return 1;
} catch (java.lang.NumberFormatException e) {
return 1;
}
}
long getMinOccurs(Element el) {
try {
if (el.getAttributeNode("minOccurs") != null) {
String value = el.getAttribute("minOccurs");
if ("unbounded".equals(value)) {
return Long.MAX_VALUE;
} else {
return Long.parseLong(value);
}
}
return 1;
} catch (java.lang.NumberFormatException e) {
return 1;
}
}
/**
* Handles the annotation Traversing if encounter appinfo or documentation add it to annotation collection
*/
XmlSchemaAnnotation handleAnnotation(Element annotEl) {
XmlSchemaAnnotation annotation = new XmlSchemaAnnotation();
List<XmlSchemaAnnotationItem> content = annotation.getItems();
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);
}
}
// process extra attributes and elements
processExtensibilityComponents(annotation, annotEl, true);
return annotation;
}
/**
* create new XmlSchemaAppinfo and add value gotten from element to this obj
*
* @param content
*/
XmlSchemaAppInfo handleAppInfo(Element content) {
XmlSchemaAppInfo appInfo = new XmlSchemaAppInfo();
NodeList markup = new DocumentFragmentNodeList(content);
if (!content.hasAttribute("source") && markup.getLength() == 0) {
return null;
}
appInfo.setSource(getAttribute(content, "source"));
appInfo.setMarkup(markup);
return appInfo;
}
/**
* Handle complex types
*
* @param schema
* @param complexEl
* @param schemaEl
* @param topLevel
*/
XmlSchemaComplexType handleComplexType(XmlSchema schema, Element complexEl, Element schemaEl,
boolean topLevel) {
XmlSchemaComplexType ct = new XmlSchemaComplexType(schema, topLevel);
if (complexEl.hasAttribute("name")) {
// String namespace = (schema.targetNamespace==null)?
// "":schema.targetNamespace;
ct.setName(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.setParticle(handleSequence(schema, el, schemaEl));
} else if (el.getLocalName().equals("choice")) {
ct.setParticle(handleChoice(schema, el, schemaEl));
} else if (el.getLocalName().equals("all")) {
ct.setParticle(handleAll(schema, el, schemaEl));
} else if (el.getLocalName().equals("attribute")) {
ct.getAttributes().add(handleAttribute(schema, el, schemaEl));
} else if (el.getLocalName().equals("attributeGroup")) {
ct.getAttributes().add(handleAttributeGroupRef(schema, el));
} else if (el.getLocalName().equals("group")) {
XmlSchemaGroupRef group = handleGroupRef(schema, el, schemaEl);
if (group.getParticle() == null) {
ct.setParticle(group);
} else {
ct.setParticle(group.getParticle());
}
} else if (el.getLocalName().equals("simpleContent")) {
ct.setContentModel(handleSimpleContent(schema, el, schemaEl));
} else if (el.getLocalName().equals("complexContent")) {
ct.setContentModel(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");
ct.setBlock(XmlSchemaDerivationMethod.schemaValueOf(blockStr));
// ct.setBlock(new XmlSchemaDerivationMethod(block));
}
if (complexEl.hasAttribute("final")) {
String finalstr = complexEl.getAttribute("final");
ct.setFinal(XmlSchemaDerivationMethod.schemaValueOf(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, true);
return ct;
}
// iterate each documentation element, create new XmlSchemaAppinfo and add
// to collection
XmlSchemaDocumentation handleDocumentation(Element content) {
XmlSchemaDocumentation documentation = new XmlSchemaDocumentation();
List<Node> markup = getChildren(content);
if (!content.hasAttribute("source") && !content.hasAttribute("xml:lang") && markup == null) {
return null;
}
documentation.setSource(getAttribute(content, "source"));
documentation.setLanguage(getAttribute(content, "xml:lang"));
documentation.setMarkup(new DocumentFragmentNodeList(content));
return documentation;
}
/*
* 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(schema, isGlobal);
if (el.getAttributeNode("name") != null) {
element.setName(el.getAttribute("name"));
}
// String namespace = (schema.targetNamespace==null)?
// "" : schema.targetNamespace;
boolean isQualified = schema.getElementFormDefault() == XmlSchemaForm.QUALIFIED;
isQualified = handleElementForm(el, element, isQualified);
handleElementName(isGlobal, element, isQualified);
handleElementAnnotation(el, element);
handleElementGlobalType(el, element);
Element simpleTypeEl;
Element complexTypeEl;
Element keyEl;
Element keyrefEl;
Element uniqueEl;
simpleTypeEl = XDOMUtil.getFirstChildElementNS(el, XmlSchema.SCHEMA_NS, "simpleType");
if (simpleTypeEl != null) {
XmlSchemaSimpleType simpleType = handleSimpleType(schema, simpleTypeEl, schemaEl, false);
element.setSchemaType(simpleType);
element.setSchemaTypeName(simpleType.getQName());
} else {
complexTypeEl = XDOMUtil.getFirstChildElementNS(el, XmlSchema.SCHEMA_NS, "complexType");
if (complexTypeEl != null) {
element.setSchemaType(handleComplexType(schema, complexTypeEl, schemaEl, false));
}
}
keyEl = XDOMUtil.getFirstChildElementNS(el, XmlSchema.SCHEMA_NS, "key");
if (keyEl != null) {
while (keyEl != null) {
element.getConstraints().add(handleConstraint(keyEl, XmlSchemaKey.class));
keyEl = XDOMUtil.getNextSiblingElementNS(keyEl, XmlSchema.SCHEMA_NS, "key");
}
}
keyrefEl = XDOMUtil.getFirstChildElementNS(el, XmlSchema.SCHEMA_NS, "keyref");
if (keyrefEl != null) {
while (keyrefEl != null) {
XmlSchemaKeyref keyRef = (XmlSchemaKeyref)handleConstraint(keyrefEl, XmlSchemaKeyref.class);
if (keyrefEl.hasAttribute("refer")) {
String name = keyrefEl.getAttribute("refer");
keyRef.refer = getRefQName(name, el);
}
element.getConstraints().add(keyRef);
keyrefEl = XDOMUtil.getNextSiblingElementNS(keyrefEl, XmlSchema.SCHEMA_NS, "keyref");
}
}
uniqueEl = XDOMUtil.getFirstChildElementNS(el, XmlSchema.SCHEMA_NS, "unique");
if (uniqueEl != null) {
while (uniqueEl != null) {
element.getConstraints().add(handleConstraint(uniqueEl, XmlSchemaUnique.class));
uniqueEl = XDOMUtil.getNextSiblingElementNS(uniqueEl, XmlSchema.SCHEMA_NS, "unique");
}
}
if (el.hasAttribute("abstract")) {
element.setAbstractElement(Boolean.valueOf(el.getAttribute("abstract")).booleanValue());
}
if (el.hasAttribute("block")) {
element.setBlock(getDerivation(el, "block"));
}
if (el.hasAttribute("default")) {
element.setDefaultValue(el.getAttribute("default"));
}
if (el.hasAttribute("final")) {
element.setFinalDerivation(getDerivation(el, "final"));
}
if (el.hasAttribute("fixed")) {
element.setFixedValue(el.getAttribute("fixed"));
}
if (el.hasAttribute("id")) {
element.setId(el.getAttribute("id"));
}
if (el.hasAttribute("nillable")) {
element.setNillable(Boolean.valueOf(el.getAttribute("nillable")).booleanValue());
}
if (el.hasAttribute("substitutionGroup")) {
String substitutionGroup = el.getAttribute("substitutionGroup");
element.setSubstitutionGroup(getRefQName(substitutionGroup, el));
}
element.setMinOccurs(getMinOccurs(el));
element.setMaxOccurs(getMaxOccurs(el));
// process extra attributes and elements
processExtensibilityComponents(element, el, true);
return element;
}
/**
* Handle the import
*
* @param schema
* @param importEl
* @param schemaEl
* @return XmlSchemaObject
*/
XmlSchemaImport handleImport(XmlSchema schema, Element importEl, Element schemaEl) {
XmlSchemaImport schemaImport = new XmlSchemaImport(schema);
Element annotationEl = XDOMUtil.getFirstChildElementNS(importEl, XmlSchema.SCHEMA_NS, "annotation");
if (annotationEl != null) {
XmlSchemaAnnotation importAnnotation = handleAnnotation(annotationEl);
schemaImport.setAnnotation(importAnnotation);
}
schemaImport.namespace = importEl.getAttribute("namespace");
final String uri = schemaImport.namespace;
schemaImport.schemaLocation = importEl.getAttribute("schemaLocation");
TargetNamespaceValidator validator = new TargetNamespaceValidator() {
public void validate(XmlSchema pSchema) {
final boolean valid;
if (isEmpty(uri)) {
valid = isEmpty(pSchema.getSyntacticalTargetNamespace());
} else {
valid = pSchema.getSyntacticalTargetNamespace().equals(uri);
}
if (!valid) {
throw new XmlSchemaException("An imported schema was announced to have the namespace "
+ uri + ", but has the namespace "
+ pSchema.getSyntacticalTargetNamespace());
}
}
private boolean isEmpty(String pValue) {
return pValue == null || Constants.NULL_NS_URI.equals(pValue);
}
};
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(schema);
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.getLogicalTargetNamespace(), include.schemaLocation,
schema.getSourceURI(), validator);
} else {
include.schema =
resolveXmlSchema(schema.getLogicalTargetNamespace(), include.schemaLocation, validator);
}
// process extra attributes and elements
processExtensibilityComponents(include, includeEl, true);
return include;
}
/**
* Handles simple types
*
* @param schema
* @param simpleEl
* @param schemaEl
*/
XmlSchemaSimpleType handleSimpleType(XmlSchema schema, Element simpleEl, Element schemaEl,
boolean topLevel) {
XmlSchemaSimpleType simpleType = new XmlSchemaSimpleType(schema, topLevel);
if (simpleEl.hasAttribute("name")) {
simpleType.setName(simpleEl.getAttribute("name"));
}
handleSimpleTypeFinal(simpleEl, simpleType);
Element simpleTypeAnnotationEl =
XDOMUtil.getFirstChildElementNS(simpleEl, XmlSchema.SCHEMA_NS, "annotation");
if (simpleTypeAnnotationEl != null) {
XmlSchemaAnnotation simpleTypeAnnotation = handleAnnotation(simpleTypeAnnotationEl);
simpleType.setAnnotation(simpleTypeAnnotation);
}
Element unionEl;
Element listEl;
Element restrictionEl;
restrictionEl = XDOMUtil.getFirstChildElementNS(simpleEl, XmlSchema.SCHEMA_NS, "restriction");
listEl = XDOMUtil.getFirstChildElementNS(simpleEl, XmlSchema.SCHEMA_NS, "list");
unionEl = XDOMUtil.getFirstChildElementNS(simpleEl, XmlSchema.SCHEMA_NS, "union");
if (restrictionEl != null) {
handleSimpleTypeRestriction(schema, schemaEl, simpleType, restrictionEl);
} else if (listEl != null) {
handleSimpleTypeList(schema, schemaEl, simpleType, listEl);
} else if (unionEl != null) {
handleSimpleTypeUnion(schema, schemaEl, simpleType, unionEl);
}
// process extra attributes and elements
processExtensibilityComponents(simpleType, simpleEl, true);
return simpleType;
}
/**
* handles the schema element
*
* @param schemaEl
* @param systemId
*/
XmlSchema handleXmlSchemaElement(Element schemaEl, String systemId) {
// get all the attributes along with the namespace declns
currentSchema.setNamespaceContext(NodeNamespaceContext.getNamespaceContext(schemaEl));
setNamespaceAttributes(currentSchema, schemaEl);
XmlSchemaCollection.SchemaKey schemaKey =
new XmlSchemaCollection.SchemaKey(currentSchema.getLogicalTargetNamespace(), systemId);
handleSchemaElementBasics(schemaEl, systemId, schemaKey);
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)) {
handleSchemaElementChild(schemaEl, el);
}
// add the extensibility components
processExtensibilityComponents(currentSchema, schemaEl, false);
return currentSchema;
}
/**
* Resolve the schemas
*
* @param targetNamespace
* @param schemaLocation
*/
XmlSchema resolveXmlSchema(String targetNamespace, String schemaLocation, String baseUri,
TargetNamespaceValidator validator) {
if (getCachedSchema(targetNamespace, schemaLocation, baseUri) != null) {
return getCachedSchema(targetNamespace, schemaLocation, baseUri);
}
// 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
return collection.getKnownSchema(targetNamespace);
}
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, validator);
putCachedSchema(targetNamespace, schemaLocation, baseUri, readSchema);
return readSchema;
} 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);
}
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 (currentValidator != null) {
currentValidator.validate(schema);
}
}
private String getAttribute(Element content, String attrName) {
if (content.hasAttribute(attrName)) {
return content.getAttribute(attrName);
}
return null;
}
/**
* Return a cached schema if one exists for this thread. In order for schemas to be cached the thread must
* have done an initCache() previously. The parameters are used to construct a key used to lookup the
* schema
*
* @param targetNamespace
* @param schemaLocation
* @param baseUri
* @return The cached schema if one exists for this thread or null.
*/
private XmlSchema getCachedSchema(String targetNamespace, String schemaLocation, String baseUri) {
XmlSchema resolvedSchema = null;
if (resolvedSchemas != null) { // cache is initialized, use it
Map<String, SoftReference<XmlSchema>> threadResolvedSchemas = resolvedSchemas.get();
if (threadResolvedSchemas != null) {
// 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.
String schemaKey = targetNamespace + schemaLocation + baseUri;
SoftReference<XmlSchema> softref = threadResolvedSchemas.get(schemaKey);
if (softref != null) {
resolvedSchema = softref.get();
}
}
}
return resolvedSchema;
}
private List<Node> getChildren(Element content) {
List<Node> result = new ArrayList<Node>();
for (Node n = content.getFirstChild(); n != null; n = n.getNextSibling()) {
result.add(n);
}
if (result.size() == 0) {
return null;
} else {
return result;
}
}
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) && currentSchema.getParent() != null
&& currentSchema.getParent().getNamespaceContext() != null) {
uri = currentSchema.getParent().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);
}
private QName getRefQName(String pName, Node pNode) {
return getRefQName(pName, NodeNamespaceContext.getNamespaceContext(pNode));
}
private XmlSchemaAll handleAll(XmlSchema schema, Element allEl, Element schemaEl) {
XmlSchemaAll all = new XmlSchemaAll();
// handle min and max occurences
all.setMinOccurs(getMinOccurs(allEl));
all.setMaxOccurs(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.getItems().add(element);
} else if (el.getLocalName().equals("annotation")) {
XmlSchemaAnnotation annotation = handleAnnotation(el);
all.setAnnotation(annotation);
}
}
return all;
}
private XmlSchemaAny handleAny(XmlSchema schema, Element anyEl, Element schemaEl) {
XmlSchemaAny any = new XmlSchemaAny();
any.setTargetNamespace(schema.getLogicalTargetNamespace());
if (anyEl.hasAttribute("namespace")) {
any.setNamespace(anyEl.getAttribute("namespace"));
}
if (anyEl.hasAttribute("processContents")) {
String processContent = getEnumString(anyEl, "processContents");
any.setProcessContent(XmlSchemaContentProcessing.schemaValueOf(processContent));
}
Element annotationEl = XDOMUtil.getFirstChildElementNS(anyEl, XmlSchema.SCHEMA_NS, "annotation");
if (annotationEl != null) {
XmlSchemaAnnotation annotation = handleAnnotation(annotationEl);
any.setAnnotation(annotation);
}
any.setMinOccurs(getMinOccurs(anyEl));
any.setMaxOccurs(getMaxOccurs(anyEl));
return any;
}
/** @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 = XmlSchemaContentProcessing.schemaValueOf(contentProcessing);
}
if (anyAttrEl.hasAttribute("id")) {
anyAttr.setId(anyAttrEl.getAttribute("id"));
}
Element annotationEl = XDOMUtil.getFirstChildElementNS(anyAttrEl, XmlSchema.SCHEMA_NS, "annotation");
if (annotationEl != null) {
XmlSchemaAnnotation annotation = handleAnnotation(annotationEl);
anyAttr.setAnnotation(annotation);
}
return anyAttr;
}
/**
* 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) {
XmlSchemaAttribute attr = new XmlSchemaAttribute(schema, topLevel);
if (attrEl.hasAttribute("name")) {
String name = attrEl.getAttribute("name");
attr.setName(name);
}
if (attrEl.hasAttribute("type")) {
String name = attrEl.getAttribute("type");
attr.setSchemaTypeName(getRefQName(name, attrEl));
}
if (attrEl.hasAttribute("default")) {
attr.setDefaultValue(attrEl.getAttribute("default"));
}
if (attrEl.hasAttribute("fixed")) {
attr.setFixedValue(attrEl.getAttribute("fixed"));
}
if (attrEl.hasAttribute("form")) {
String formValue = getEnumString(attrEl, "form");
attr.setForm(XmlSchemaForm.schemaValueOf(formValue));
}
if (attrEl.hasAttribute("id")) {
attr.setId(attrEl.getAttribute("id"));
}
if (attrEl.hasAttribute("use")) {
String useType = getEnumString(attrEl, "use");
attr.setUse(XmlSchemaUse.schemaValueOf(useType));
}
if (attrEl.hasAttribute("ref")) {
String name = attrEl.getAttribute("ref");
attr.getRef().setTargetQName(getRefQName(name, attrEl));
}
Element simpleTypeEl = XDOMUtil.getFirstChildElementNS(attrEl, XmlSchema.SCHEMA_NS, "simpleType");
if (simpleTypeEl != null) {
attr.setSchemaType(handleSimpleType(schema, simpleTypeEl, schemaEl, false));
}
Element annotationEl = XDOMUtil.getFirstChildElementNS(attrEl, XmlSchema.SCHEMA_NS, "annotation");
if (annotationEl != null) {
XmlSchemaAnnotation annotation = handleAnnotation(annotationEl);
attr.setAnnotation(annotation);
}
NamedNodeMap attrNodes = attrEl.getAttributes();
List<Attr> attrs = new ArrayList<Attr>();
NodeNamespaceContext ctx = null;
for (int i = 0; i < attrNodes.getLength(); i++) {
Attr att = (Attr)attrNodes.item(i);
String attName = att.getName();
if (!RESERVED_ATTRIBUTES.contains(attName)) {
attrs.add(att);
String value = att.getValue();
if (value.indexOf(":") > -1) {
// there is a possibility 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().createAttributeNS(Constants.XMLNS_ATTRIBUTE_NS_URI,
"xmlns:" + prefix);
nsAttr.setValue(namespace);
attrs.add(nsAttr);
}
}
}
}
if (attrs.size() > 0) {
attr.setUnhandledAttributes(attrs.toArray(new Attr[attrs.size()]));
}
// process extra attributes and elements
processExtensibilityComponents(attr, attrEl, true);
return attr;
}
private XmlSchemaAttributeGroup handleAttributeGroup(XmlSchema schema,
Element groupEl, Element schemaEl) {
XmlSchemaAttributeGroup attrGroup = new XmlSchemaAttributeGroup(schema);
if (groupEl.hasAttribute("name")) {
attrGroup.setName(groupEl.getAttribute("name"));
}
if (groupEl.hasAttribute("id")) {
attrGroup.setId(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.getAttributes().add(attr);
} else if (el.getLocalName().equals("attributeGroup")) {
XmlSchemaAttributeGroupRef attrGroupRef = handleAttributeGroupRef(schema, el);
attrGroup.getAttributes().add(attrGroupRef);
} else if (el.getLocalName().equals("anyAttribute")) {
attrGroup.setAnyAttribute(handleAnyAttribute(schema, el, schemaEl));
} else if (el.getLocalName().equals("annotation")) {
XmlSchemaAnnotation ann = handleAnnotation(el);
attrGroup.setAnnotation(ann);
}
}
return attrGroup;
}
private XmlSchemaAttributeGroupRef handleAttributeGroupRef(XmlSchema schema, Element attrGroupEl) {
XmlSchemaAttributeGroupRef attrGroup = new XmlSchemaAttributeGroupRef(schema);
if (attrGroupEl.hasAttribute("ref")) {
String ref = attrGroupEl.getAttribute("ref");
attrGroup.getRef().setTargetQName(getRefQName(ref, attrGroupEl));
}
if (attrGroupEl.hasAttribute("id")) {
attrGroup.setId(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 XmlSchemaChoice handleChoice(XmlSchema schema, Element choiceEl, Element schemaEl) {
XmlSchemaChoice choice = new XmlSchemaChoice();
if (choiceEl.hasAttribute("id")) {
choice.setId(choiceEl.getAttribute("id"));
}
choice.setMinOccurs(getMinOccurs(choiceEl));
choice.setMaxOccurs(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.getItems().add(seq);
} else if (el.getLocalName().equals("element")) {
XmlSchemaElement element = handleElement(schema, el, schemaEl, false);
choice.getItems().add(element);
} else if (el.getLocalName().equals("group")) {
XmlSchemaGroupRef group = handleGroupRef(schema, el, schemaEl);
choice.getItems().add(group);
} else if (el.getLocalName().equals("choice")) {
XmlSchemaChoice choiceItem = handleChoice(schema, el, schemaEl);
choice.getItems().add(choiceItem);
} else if (el.getLocalName().equals("any")) {
XmlSchemaAny any = handleAny(schema, el, schemaEl);
choice.getItems().add(any);
} else if (el.getLocalName().equals("annotation")) {
XmlSchemaAnnotation annotation = handleAnnotation(el);
choice.setAnnotation(annotation);
}
}
return choice;
}
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 XmlSchemaComplexContentExtension handleComplexContentExtension(XmlSchema schema, Element extEl,
Element schemaEl) {
XmlSchemaComplexContentExtension ext = new XmlSchemaComplexContentExtension();
if (extEl.hasAttribute("base")) {
String name = extEl.getAttribute("base");
ext.setBaseTypeName(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.setParticle(handleSequence(schema, el, schemaEl));
} else if (el.getLocalName().equals("choice")) {
ext.setParticle(handleChoice(schema, el, schemaEl));
} else if (el.getLocalName().equals("all")) {
ext.setParticle(handleAll(schema, el, schemaEl));
} else if (el.getLocalName().equals("attribute")) {
ext.getAttributes().add(handleAttribute(schema, el, schemaEl));
} else if (el.getLocalName().equals("attributeGroup")) {
ext.getAttributes().add(handleAttributeGroupRef(schema, el));
} else if (el.getLocalName().equals("group")) {
ext.setParticle(handleGroupRef(schema, el, schemaEl));
} else if (el.getLocalName().equals("anyAttribute")) {
ext.setAnyAttribute(handleAnyAttribute(schema, el, schemaEl));
} else if (el.getLocalName().equals("annotation")) {
ext.setAnnotation(handleAnnotation(el));
}
}
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.setBaseTypeName(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.setParticle(handleSequence(schema, el, schemaEl));
} else if (el.getLocalName().equals("choice")) {
restriction.setParticle(handleChoice(schema, el, schemaEl));
} else if (el.getLocalName().equals("all")) {
restriction.setParticle(handleAll(schema, el, schemaEl));
} else if (el.getLocalName().equals("attribute")) {
restriction.getAttributes().add(handleAttribute(schema, el, schemaEl));
} else if (el.getLocalName().equals("attributeGroup")) {
restriction.getAttributes().add(handleAttributeGroupRef(schema, el));
} else if (el.getLocalName().equals("group")) {
restriction.setParticle(handleGroupRef(schema, el, schemaEl));
} else if (el.getLocalName().equals("anyAttribute")) {
restriction.setAnyAttribute(handleAnyAttribute(schema, el, schemaEl));
} else if (el.getLocalName().equals("annotation")) {
restriction.setAnnotation(handleAnnotation(el));
}
}
return restriction;
}
private XmlSchemaIdentityConstraint
handleConstraint(Element constraintEl,
Class<? extends XmlSchemaIdentityConstraint> typeClass) {
try {
XmlSchemaIdentityConstraint constraint = typeClass.newInstance();
if (constraintEl.hasAttribute("name")) {
constraint.setName(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.setSelector(selectorXPath);
} else if (el.getLocalName().equals("field")) {
XmlSchemaXPath fieldXPath = new XmlSchemaXPath();
fieldXPath.xpath = el.getAttribute("xpath");
constraint.getFields().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 (InstantiationException e) {
throw new XmlSchemaException(e.getMessage());
} catch (IllegalAccessException e) {
throw new XmlSchemaException(e.getMessage());
}
}
private void handleElementAnnotation(Element el, XmlSchemaElement element) {
Element annotationEl = XDOMUtil.getFirstChildElementNS(el, XmlSchema.SCHEMA_NS, "annotation");
if (annotationEl != null) {
XmlSchemaAnnotation annotation = handleAnnotation(annotationEl);
element.setAnnotation(annotation);
}
}
private boolean handleElementForm(Element el, XmlSchemaElement element, boolean isQualified) {
if (el.hasAttribute("form")) {
String formDef = el.getAttribute("form");
element.setForm(XmlSchemaForm.schemaValueOf(formDef));
}
isQualified = element.getForm() == XmlSchemaForm.QUALIFIED;
return isQualified;
}
private void handleElementGlobalType(Element el, XmlSchemaElement element) {
if (el.getAttributeNode("type") != null) {
String typeName = el.getAttribute("type");
element.setSchemaTypeName(getRefQName(typeName, el));
QName typeQName = element.getSchemaTypeName();
XmlSchemaType type = collection.getTypeByQName(typeQName);
if (type == null) {
// Could be a forward reference...
collection.addUnresolvedType(typeQName, element);
}
element.setSchemaType(type);
} else if (el.getAttributeNode("ref") != null) {
String refName = el.getAttribute("ref");
QName refQName = getRefQName(refName, el);
element.getRef().setTargetQName(refQName);
}
}
private void handleElementName(boolean isGlobal, XmlSchemaElement element, boolean isQualified) {
}
/*
* handle_simple_content_restriction if( restriction has base attribute ) set the baseType else if(
* restriction 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
*/
private XmlSchemaGroup handleGroup(XmlSchema schema, Element groupEl, Element schemaEl) {
XmlSchemaGroup group = new XmlSchemaGroup(schema);
group.setName(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.setParticle(handleAll(schema, el, schemaEl));
} else if (el.getLocalName().equals("sequence")) {
group.setParticle(handleSequence(schema, el, schemaEl));
} else if (el.getLocalName().equals("choice")) {
group.setParticle(handleChoice(schema, el, schemaEl));
} else if (el.getLocalName().equals("annotation")) {
XmlSchemaAnnotation groupAnnotation = handleAnnotation(el);
group.setAnnotation(groupAnnotation);
}
}
return group;
}
private XmlSchemaGroupRef handleGroupRef(XmlSchema schema, Element groupEl, Element schemaEl) {
XmlSchemaGroupRef group = new XmlSchemaGroupRef();
group.setMaxOccurs(getMaxOccurs(groupEl));
group.setMinOccurs(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.setRefName(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.setParticle(handleSequence(schema, el, schemaEl));
} else if (el.getLocalName().equals("all")) {
group.setParticle(handleAll(schema, el, schemaEl));
} else if (el.getLocalName().equals("choice")) {
group.setParticle(handleChoice(schema, el, schemaEl));
}
}
return group;
}
private XmlSchemaNotation handleNotation(XmlSchema schema, Element notationEl) {
XmlSchemaNotation notation = new XmlSchemaNotation(schema);
if (notationEl.hasAttribute("id")) {
notation.setId(notationEl.getAttribute("id"));
}
if (notationEl.hasAttribute("name")) {
notation.setName(notationEl.getAttribute("name"));
}
if (notationEl.hasAttribute("public")) {
notation.setPublicNotation(notationEl.getAttribute("public"));
}
if (notationEl.hasAttribute("system")) {
notation.setSystem(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(schema);
redefine.schemaLocation = redefineEl.getAttribute("schemaLocation");
final TargetNamespaceValidator validator = newIncludeValidator(schema);
if (schema.getSourceURI() != null) {
redefine.schema =
resolveXmlSchema(schema.getLogicalTargetNamespace(), redefine.schemaLocation,
schema.getSourceURI(), validator);
} else {
redefine.schema =
resolveXmlSchema(schema.getLogicalTargetNamespace(), 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, false);
redefine.getSchemaTypes().put(type.getQName(), type);
redefine.getItems().add(type);
} else if (el.getLocalName().equals("complexType")) {
XmlSchemaType type = handleComplexType(schema, el, schemaEl, true);
redefine.getSchemaTypes().put(type.getQName(), type);
redefine.getItems().add(type);
} else if (el.getLocalName().equals("group")) {
XmlSchemaGroup group = handleGroup(schema, el, schemaEl);
redefine.getGroups().put(group.getQName(), group);
redefine.getItems().add(group);
} else if (el.getLocalName().equals("attributeGroup")) {
XmlSchemaAttributeGroup group = handleAttributeGroup(schema, el, schemaEl);
redefine.getAttributeGroups().put(group.getQName(), group);
redefine.getItems().add(group);
} else if (el.getLocalName().equals("annotation")) {
XmlSchemaAnnotation annotation = handleAnnotation(el);
redefine.setAnnotation(annotation);
}
// }
}
return redefine;
}
private void handleSchemaElementBasics(Element schemaEl, String systemId,
XmlSchemaCollection.SchemaKey schemaKey) {
if (!collection.containsSchema(schemaKey)) {
collection.addSchema(schemaKey, currentSchema);
currentSchema.setParent(collection); // establish parentage now.
} else {
throw new XmlSchemaException("Schema name conflict in collection. Namespace: "
+ currentSchema.getLogicalTargetNamespace());
}
currentSchema.setElementFormDefault(this.getFormDefault(schemaEl, "elementFormDefault"));
currentSchema.setAttributeFormDefault(this.getFormDefault(schemaEl, "attributeFormDefault"));
currentSchema.setBlockDefault(this.getDerivation(schemaEl, "blockDefault"));
currentSchema.setFinalDefault(this.getDerivation(schemaEl, "finalDefault"));
/* set id attribute */
if (schemaEl.hasAttribute("id")) {
currentSchema.setId(schemaEl.getAttribute("id"));
}
currentSchema.setSourceURI(systemId);
}
private void handleSchemaElementChild(Element schemaEl, Element el) {
if (el.getLocalName().equals("simpleType")) {
XmlSchemaType type = handleSimpleType(currentSchema, el, schemaEl, true);
collection.resolveType(type.getQName(), type);
} else if (el.getLocalName().equals("complexType")) {
XmlSchemaType type = handleComplexType(currentSchema, el, schemaEl, true);
collection.resolveType(type.getQName(), type);
} else if (el.getLocalName().equals("element")) {
handleElement(currentSchema, el, schemaEl, true);
} else if (el.getLocalName().equals("include")) {
handleInclude(currentSchema, el, schemaEl);
} else if (el.getLocalName().equals("import")) {
handleImport(currentSchema, el, schemaEl);
} else if (el.getLocalName().equals("group")) {
handleGroup(currentSchema, el, schemaEl);
} else if (el.getLocalName().equals("attributeGroup")) {
handleAttributeGroup(currentSchema, el, schemaEl);
} else if (el.getLocalName().equals("attribute")) {
handleAttribute(currentSchema, el, schemaEl, true);
} else if (el.getLocalName().equals("redefine")) {
handleRedefine(currentSchema, el, schemaEl);
} else if (el.getLocalName().equals("notation")) {
handleNotation(currentSchema, el);
} else if (el.getLocalName().equals("annotation")) {
XmlSchemaAnnotation annotation = handleAnnotation(el);
currentSchema.setAnnotation(annotation);
}
}
private XmlSchemaSequence handleSequence(XmlSchema schema, Element sequenceEl, Element schemaEl) {
XmlSchemaSequence sequence = new XmlSchemaSequence();
// handle min and max occurences
sequence.setMinOccurs(getMinOccurs(sequenceEl));
sequence.setMaxOccurs(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.getItems().add(seq);
} else if (el.getLocalName().equals("element")) {
XmlSchemaElement element = handleElement(schema, el, schemaEl, false);
sequence.getItems().add(element);
} else if (el.getLocalName().equals("group")) {
XmlSchemaGroupRef group = handleGroupRef(schema, el, schemaEl);
sequence.getItems().add(group);
} else if (el.getLocalName().equals("choice")) {
XmlSchemaChoice choice = handleChoice(schema, el, schemaEl);
sequence.getItems().add(choice);
} else if (el.getLocalName().equals("any")) {
XmlSchemaAny any = handleAny(schema, el, schemaEl);
sequence.getItems().add(any);
} else if (el.getLocalName().equals("annotation")) {
XmlSchemaAnnotation annotation = handleAnnotation(el);
sequence.setAnnotation(annotation);
}
}
return sequence;
}
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 XmlSchemaSimpleContentExtension handleSimpleContentExtension(XmlSchema schema, Element extEl,
Element schemaEl) {
XmlSchemaSimpleContentExtension ext = new XmlSchemaSimpleContentExtension();
if (extEl.hasAttribute("base")) {
String name = extEl.getAttribute("base");
ext.setBaseTypeName(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.getAttributes().add(attr);
} else if (el.getLocalName().equals("attributeGroup")) {
XmlSchemaAttributeGroupRef attrGroup = handleAttributeGroupRef(schema, el);
ext.getAttributes().add(attrGroup);
} else if (el.getLocalName().equals("anyAttribute")) {
ext.setAnyAttribute(handleAnyAttribute(schema, el, schemaEl));
} else if (el.getLocalName().equals("annotation")) {
XmlSchemaAnnotation ann = handleAnnotation(el);
ext.setAnnotation(ann);
}
}
return ext;
}
private XmlSchemaSimpleContentRestriction handleSimpleContentRestriction(XmlSchema schema,
Element restrictionEl,
Element schemaEl) {
XmlSchemaSimpleContentRestriction restriction = new XmlSchemaSimpleContentRestriction();
if (restrictionEl.hasAttribute("base")) {
String name = restrictionEl.getAttribute("base");
restriction.setBaseTypeName(getRefQName(name, restrictionEl));
}
if (restrictionEl.hasAttribute("id")) {
restriction.setId(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.getAttributes().add(attr);
} else if (el.getLocalName().equals("attributeGroup")) {
XmlSchemaAttributeGroupRef attrGroup = handleAttributeGroupRef(schema, el);
restriction.getAttributes().add(attrGroup);
} else if (el.getLocalName().equals("simpleType")) {
restriction.setBaseType(handleSimpleType(schema, el, schemaEl, false));
} 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);
Element annotation = XDOMUtil.getFirstChildElementNS(el, XmlSchema.SCHEMA_NS, "annotation");
if (annotation != null) {
XmlSchemaAnnotation facetAnnotation = handleAnnotation(annotation);
facet.setAnnotation(facetAnnotation);
}
restriction.getFacets().add(facet);
// process extra attributes and elements
processExtensibilityComponents(facet, el, true);
}
}
return restriction;
}
private void handleSimpleTypeFinal(Element simpleEl, XmlSchemaSimpleType simpleType) {
if (simpleEl.hasAttribute("final")) {
String finalstr = simpleEl.getAttribute("final");
simpleType.setFinal(XmlSchemaDerivationMethod.schemaValueOf(finalstr));
}
}
private void handleSimpleTypeList(XmlSchema schema, Element schemaEl, XmlSchemaSimpleType simpleType,
Element listEl) {
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;
Element listAnnotationEl;
inlineListType = XDOMUtil.getFirstChildElementNS(listEl, XmlSchema.SCHEMA_NS, "simpleType");
if (listEl.hasAttribute("itemType")) {
String name = listEl.getAttribute("itemType");
list.itemTypeName = getRefQName(name, listEl);
} else if (inlineListType != null) {
list.itemType = handleSimpleType(schema, inlineListType, schemaEl, false);
}
listAnnotationEl = XDOMUtil.getFirstChildElementNS(listEl, XmlSchema.SCHEMA_NS, "annotation");
if (listAnnotationEl != null) {
XmlSchemaAnnotation listAnnotation = handleAnnotation(listAnnotationEl);
list.setAnnotation(listAnnotation);
}
simpleType.content = list;
}
private void handleSimpleTypeRestriction(XmlSchema schema, Element schemaEl,
XmlSchemaSimpleType simpleType, Element restrictionEl) {
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(
* restriction 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.setBaseTypeName(getRefQName(restrictionEl.getAttribute("base"), ctx));
} else if (inlineSimpleType != null) {
restriction.setBaseType(handleSimpleType(schema, inlineSimpleType, schemaEl, false));
}
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);
}
// process extra attributes and elements
processExtensibilityComponents(facet, el, true);
restriction.getFacets().add(facet);
}
}
simpleType.content = restriction;
}
private void handleSimpleTypeUnion(XmlSchema schema, Element schemaEl, XmlSchemaSimpleType simpleType,
Element unionEl) {
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.setMemberTypesSource(memberTypes);
Vector<QName> v = new Vector<QName>();
StringTokenizer tokenizer = new StringTokenizer(memberTypes, " ");
while (tokenizer.hasMoreTokens()) {
String member = tokenizer.nextToken();
v.add(getRefQName(member, unionEl));
}
union.setMemberTypesQNames(new QName[v.size()]);
v.copyInto(union.getMemberTypesQNames());
}
Element inlineUnionType = XDOMUtil.getFirstChildElementNS(unionEl, XmlSchema.SCHEMA_NS, "simpleType");
while (inlineUnionType != null) {
XmlSchemaSimpleType unionSimpleType = handleSimpleType(schema, inlineUnionType, schemaEl, false);
union.getBaseTypes().add(unionSimpleType);
if (!unionSimpleType.isAnonymous()) {
union.setMemberTypesSource(union.getMemberTypesSource() + " " + unionSimpleType.getName());
}
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;
}
private TargetNamespaceValidator newIncludeValidator(final XmlSchema schema) {
return new TargetNamespaceValidator() {
public void validate(XmlSchema pSchema) {
if (isEmpty(pSchema.getSyntacticalTargetNamespace())) {
pSchema.setLogicalTargetNamespace(schema.getLogicalTargetNamespace());
} else {
if (!pSchema.getSyntacticalTargetNamespace().equals(schema.getLogicalTargetNamespace())) {
String msg = "An included schema was announced to have the default target namespace";
if (!isEmpty(schema.getLogicalTargetNamespace())) {
msg += " or the target namespace " + schema.getLogicalTargetNamespace();
}
throw new XmlSchemaException(msg + ", but has the target namespace "
+ pSchema.getLogicalTargetNamespace());
}
}
}
private boolean isEmpty(String pValue) {
return pValue == null || Constants.NULL_NS_URI.equals(pValue);
}
};
}
/**
* 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,
boolean namespaces) {
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
// ignore namespaces
&& (namespaces || !namespaceURI.startsWith(Constants.XMLNS_ATTRIBUTE_NS_URI))
// does not belong to the schema namespace by any chance!
&& !Constants.URI_2001_SCHEMA_XSD.equals(namespaceURI)) {
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();
}
}
}
/**
* Add an XmlSchema to the cache if the current thread has the cache enabled. The first three parameters
* are used to construct a key
*
* @param targetNamespace
* @param schemaLocation
* @param baseUri This parameter is the value put under the key (if the cache is enabled)
* @param readSchema
*/
private void putCachedSchema(String targetNamespace, String schemaLocation, String baseUri,
XmlSchema readSchema) {
if (resolvedSchemas != null) {
Map<String, SoftReference<XmlSchema>> threadResolvedSchemas = resolvedSchemas.get();
if (threadResolvedSchemas != null) {
String schemaKey = targetNamespace + schemaLocation + baseUri;
threadResolvedSchemas.put(schemaKey, new SoftReference<XmlSchema>(readSchema));
}
}
}
}