/**
* Redistribution and use of this software and associated documentation
* ("Software"), with or without modification, are permitted provided
* that the following conditions are met:
*
* 1. Redistributions of source code must retain copyright
* statements and notices. Redistributions must also contain a
* copy of this document.
*
* 2. Redistributions in binary form must reproduce the
* above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. The name "Exolab" must not be used to endorse or promote
* products derived from this Software without prior written
* permission of Intalio, Inc. For written permission,
* please contact info@exolab.org.
*
* 4. Products derived from this Software may not be called "Exolab"
* nor may "Exolab" appear in their names without prior written
* permission of Intalio, Inc. Exolab is a registered
* trademark of Intalio, Inc.
*
* 5. Due credit should be given to the Exolab Project
* (http://www.exolab.org/).
*
* THIS SOFTWARE IS PROVIDED BY INTALIO, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
* NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* INTALIO, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Copyright 1999-2004 (C) Intalio Inc. All Rights Reserved.
*
* $Id$
*/
package org.exolab.castor.xml.schema.reader;
//-- imported classes and packages
import java.io.InputStream;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Properties;
import java.util.StringTokenizer;
import org.exolab.castor.net.URIResolver;
import org.exolab.castor.net.util.URIResolverImpl;
import org.exolab.castor.xml.AttributeSet;
import org.exolab.castor.xml.Namespaces;
import org.exolab.castor.xml.XMLException;
import org.exolab.castor.xml.schema.Annotation;
import org.exolab.castor.xml.schema.AttributeDecl;
import org.exolab.castor.xml.schema.AttributeGroupDecl;
import org.exolab.castor.xml.schema.ComplexType;
import org.exolab.castor.xml.schema.ElementDecl;
import org.exolab.castor.xml.schema.Form;
import org.exolab.castor.xml.schema.SchemaContext;
import org.exolab.castor.xml.schema.ModelGroup;
import org.exolab.castor.xml.schema.RedefineSchema;
import org.exolab.castor.xml.schema.Schema;
import org.exolab.castor.xml.schema.SchemaException;
import org.exolab.castor.xml.schema.SchemaNames;
import org.exolab.castor.xml.schema.ScopableResolver;
import org.exolab.castor.xml.schema.SimpleType;
import org.exolab.castor.xml.util.AttributeSetImpl;
/**
* @author <a href="mailto:kvisco@intalio.com">Keith Visco</a>
* @version $Revision$ $Date: 2006-04-13 06:47:36 -0600 (Thu, 13 Apr 2006) $
**/
public class SchemaUnmarshaller extends ComponentReader {
/**
* W3C XML schema namespace.
*/
public static final String XSD_NAMESPACE
= "http://www.w3.org/2001/XMLSchema";
/**
* Unsupported namespace definitions, pointing to older
* XML schema specifications.
*/
public static final String[] UNSUPPORTED_NAMESPACES = {
"http://www.w3.org/2000/10/XMLSchema",
"http://www.w3.org/1999/XMLSchema"
};
//--------------------/
//- Member Variables -/
//--------------------/
/**
* Indicates whether the {@link Schema} processed represents an
* included schema.
*/
private boolean _include = false;
/**
* The current {@link ComponentReader}.
**/
private ComponentReader _unmarshaller;
/**
* Flag to indicate that we are inside an annotation element.
**/
private int _annotationDepth = 0;
/**
* The current branch depth.
**/
private int _depth = 0;
boolean skipAll = false;
Schema _schema = null;
private boolean foundSchemaDef = false;
/**
* The default namespace URI to be used.
*/
private String _defaultNS = null;
/**
* The {@link SchemaUnmarshaller} state.
*/
private SchemaUnmarshallerState _state = null;
/**
* Remapped prefix mappings.
*/
private RemappedPrefixes _prefixMappings = null;
//----------------/
//- Constructors -/
//----------------/
/**
* Creates a {@link SchemaUnmarshaller} instance.
* @param schemaContext A {@link SchemaContext} to be used during schema unmarshalling.
* @throws XMLException Indicates that the XML schema cannnot be processed
*/
public SchemaUnmarshaller(final SchemaContext schemaContext)
throws XMLException {
this(schemaContext, null, null);
foundSchemaDef = false;
} //-- SchemaUnmarshaller
/**
* Creates a {@link SchemaUnmarshaller} instance.
* @param schemaContext A {@link SchemaContext} to be used during schema unmarshalling.
* @param state A {@link SchemaUnmarshallerState} to be used during unmarshalling.
* @throws XMLException Indicates that the XML schema cannnot be processed
*/
public SchemaUnmarshaller(
final SchemaContext schemaContext,
final SchemaUnmarshallerState state)
throws XMLException {
this(schemaContext, null, null);
_state = state;
foundSchemaDef = false;
} //-- SchemaUnmarshaller
/**
* Creates a {@link SchemaUnmarshaller} instance.
* @param schemaContext A {@link SchemaContext} to be used during schema unmarshalling.
* @param include Indicates whether the {@link Schema} to be processed ia an included schema.
* @param state A {@link SchemaUnmarshallerState} to be used during unmarshalling.
* @param uriResolver {@link URIResolver} to be used during processing.
* @throws XMLException Signals a problem in processing the XML schema.
*
* Called from IncludeUnmarshaller.
*
* @see {@link IncludeUnmarshaller}
*/
public SchemaUnmarshaller(
final SchemaContext schemaContext,
final boolean include,
final SchemaUnmarshallerState state,
final URIResolver uriResolver)
throws XMLException {
this(schemaContext, null, uriResolver);
_state = state;
_include = include;
foundSchemaDef = false;
}
/**
* Creates a {@link SchemaUnmarshaller} instance.
* Exists for backward compatibility
* @param schemaContext A {@link SchemaContext} to be used during schema unmarshalling.
* @param atts Attribute set to be processed.
* @throws XMLException Signals a problem in processing the XML schema.
*/
public SchemaUnmarshaller(
final SchemaContext schemaContext,
final AttributeSet atts) throws XMLException {
this(schemaContext, atts, null);
}
/**
* Creates a {@link SchemaUnmarshaller} instance.
* @param schemaContext A {@link SchemaContext} to be used during schema unmarshalling.
* @param atts Attribute set to be processed.
* @param uriResolver {@link URIResolver} to be used during processing.
* @throws XMLException Signals a problem in processing the XML schema.
*/
private SchemaUnmarshaller(
final SchemaContext schemaContext,
final AttributeSet atts,
final URIResolver uriResolver)
throws XMLException {
super(schemaContext);
_schema = new Schema();
//--initialize the schema to ensure that the default namespace
//--is not set
_schema.removeNamespace("");
if (getResolver() == null) {
setResolver(new ScopableResolver());
}
if (uriResolver == null) {
setURIResolver(new URIResolverImpl());
} else {
setURIResolver(uriResolver);
}
foundSchemaDef = true;
_state = new SchemaUnmarshallerState();
init(atts);
} //-- SchemaUnmarshaller
/**
* Returns the {@link Schema} instance representing the XML schema (file) just
* processed.
* @return the {@link Schema} instance obtained from processing an XML schema file.
*/
public Schema getSchema() {
return _schema;
}
/**
* Sets the {@link Schema} instance to be processed.
* @param schema {@link Schema} instancetp be processed.
*/
public void setSchema(final Schema schema) {
_schema = schema;
}
/**
* Returns the Object created by this ComponentReader.
* @return the Object created by this ComponentReader
**/
public Object getObject() {
return getSchema();
} //-- getObject
/**
* Returns the name of the element that this ComponentReader
* handles.
* @return the name of the element that this ComponentReader
* handles
**/
public String elementName() {
return SchemaNames.SCHEMA;
} //-- elementName
/**
* Initializes the Schema object with the given attribute list.
* @param atts the AttributeList for the schema
* @throws XMLException Signals a problem in initializing the {@link Schema}
* object instance
*/
private void init(final AttributeSet atts) throws XMLException {
if (atts == null) {
return;
}
String attValue = null;
String nsURI = atts.getValue(SchemaNames.TARGET_NS_ATTR);
if (nsURI != null && nsURI.length() == 0) {
throw new SchemaException("empty string is not a legal namespace.");
}
if ((nsURI != null) && (nsURI.length() > 0)) {
if (!_state.cacheIncludedSchemas) {
//if we are including a schema we must take care
//that the namespaces are the same
if ((_include) && (!_schema.getTargetNamespace().equals(nsURI))) {
throw new SchemaException("The target namespace of the included "
+ "components must be the same as the target namespace "
+ "of the including schema");
}
}
_schema.setTargetNamespace(nsURI);
}
_schema.setId(atts.getValue(SchemaNames.ID_ATTR));
_schema.setVersion(atts.getValue(SchemaNames.VERSION_ATTR));
//set the default locator of this schema
if (!_include || _state.cacheIncludedSchemas) {
_schema.setSchemaLocation(getDocumentLocator().getSystemId());
}
//-- attributeFormDefault
String form = atts.getValue(SchemaNames.ATTR_FORM_DEFAULT_ATTR);
if (form != null) {
_schema.setAttributeFormDefault(Form.valueOf(form));
}
//-- elementFormDefault
form = atts.getValue(SchemaNames.ELEM_FORM_DEFAULT_ATTR);
if (form != null) {
_schema.setElementFormDefault(Form.valueOf(form));
}
//-- @blockDefault
attValue = atts.getValue(SchemaNames.BLOCK_DEFAULT_ATTR);
if (attValue != null) {
_schema.setBlockDefault(attValue);
}
//-- @finalDefault
attValue = atts.getValue(SchemaNames.FINAL_DEFAULT_ATTR);
if (attValue != null) {
_schema.setFinalDefault(attValue);
}
//--@version
attValue = atts.getValue(SchemaNames.VERSION_ATTR);
if (attValue != null) {
_schema.setVersion(attValue);
}
} //-- init
/**
* Handles namespace attributes.
* @param namespaces The name space to handle.
* @throws XMLException If there's a problem related to namespace handling.
*/
private void handleNamespaces(final Namespaces namespaces)
throws XMLException {
if (namespaces == null) {
return;
}
Enumeration enumeration = namespaces.getLocalNamespaces();
while (enumeration.hasMoreElements()) {
String ns = (String) enumeration.nextElement();
String[] prefixes = namespaces.getNamespacePrefixes(ns, true);
if (prefixes.length == 0) {
//-- this should never happen, but report error just
//-- in case there is a bug in Namespaces class.
String error = "unexpected error processing the following "
+ "namespace: '" + ns + "'; the prefix could not be resolved.";
throw new XMLException(error);
}
boolean hasCollisions = false;
for (int pIdx = 0; pIdx < prefixes.length; pIdx++) {
String prefix = prefixes[pIdx];
//-- Since the Schema Object Model does not yet support
//-- namespace scoping, we need to checking for namespace
//-- prefix collisions...and remap the prefixes
String tmpURI = _schema.getNamespace(prefix);
if ((tmpURI != null) && (foundSchemaDef)) {
if (!tmpURI.equals(ns)) {
if (!hasCollisions) {
hasCollisions = true;
if (_prefixMappings == null) {
_prefixMappings = new RemappedPrefixes();
} else {
_prefixMappings = _prefixMappings.newRemappedPrefixes();
}
}
//-- create a new prefix
if (prefix.length() == 0) {
prefix = "ns";
}
int count = 1;
String newPrefix = prefix + count;
tmpURI = _schema.getNamespace(newPrefix);
while (tmpURI != null) {
if (tmpURI.equals(ns)) {
//-- no remapping necessary
break;
}
++count;
newPrefix = prefix + count;
tmpURI = _schema.getNamespace(newPrefix);
}
_prefixMappings.addMapping(prefix, newPrefix);
prefix = newPrefix;
} else {
//-- we may need to "reset" a currently mapped prefix
if (_prefixMappings != null) {
if (_prefixMappings.isRemappedPrefix(prefix)) {
//-- reset mapping in this scope
_prefixMappings.addMapping(prefix, prefix);
}
}
}
}
//-- end collision handling
if (prefix.length() == 0) {
_defaultNS = ns;
//register the default namespace with the empty string
_schema.addNamespace("", _defaultNS);
} else {
//-- check for old unsupported schema namespaces
for (int nsIdx = 0; nsIdx < UNSUPPORTED_NAMESPACES.length; nsIdx++) {
if (ns.equals(UNSUPPORTED_NAMESPACES[nsIdx])) {
error("The following namespace \"" + ns
+ "\" is no longer supported. Please update to "
+ " the W3C XML Schema Recommendation.");
}
}
_schema.addNamespace(prefix, ns);
}
}
}
} //-- handleNamespaces
/**
* Remaps any QName attributes for the given element and attributeSet.
* This method is a work around for the lack of namespace scoping
* support in the Schema Object Model
*
* @param name Name of the element handled.
* @param namespace Namepace of the element processed.
* @param atts The attributes of the element processed.
*/
private void handleRemapping(final String name, final String namespace,
final AttributeSetImpl atts) {
if (_prefixMappings == null) {
return;
}
//-- increase depth for scoping
_prefixMappings.depth++;
String[] remapAtts = (String[]) RemappedPrefixes.QNAME_TABLE.get(name);
if (remapAtts != null) {
for (int i = 0; i < remapAtts.length; i++) {
String value = atts.getValue(remapAtts[i]);
if (value != null) {
value = _prefixMappings.remapQName(value);
atts.setAttribute(remapAtts[i], value);
}
}
}
} //-- handleRemapping
/**
* Signals the start of an element with the given name.
*
* @param name the NCName of the element. It is an error
* if the name is a QName (ie. contains a prefix).
* @param namespace the namespace of the element. This may be null.
* Note: A null namespace is not the same as the default namespace unless
* the default namespace is also null.
* @param atts the AttributeSet containing the attributes associated
* with the element.
* @param nsDecls the namespace declarations being declared for this
* element. This may be null.
* @throws XMLException To indicate a problem in processing the current element.
**/
public void startElement(final String name,
String namespace, final AttributeSet atts,
final Namespaces nsDecls) throws XMLException {
if (skipAll) {
return;
}
//-- DEBUG
//System.out.println("#startElement: " + name + " {" + namespace + "}");
//-- /DEBUG
//-- process namespaces...unless we are inside an
//-- annotation
if (_annotationDepth == 0) {
handleNamespaces(nsDecls);
}
//-- backward compatibility, we'll need to
//-- remove this at some point
if ((!foundSchemaDef) && (namespace == null)) {
if (_defaultNS == null) {
_defaultNS = XSD_NAMESPACE;
namespace = XSD_NAMESPACE;
System.out.println("No namespace declaration has been " +
"found for " + name);
System.out.print(" * assuming default namespace of ");
System.out.println(XSD_NAMESPACE);
}
}
if (namespace == null) {
namespace = _defaultNS;
//-- end of backward compatibility
}
//-- keep track of annotations
if (name.equals(SchemaNames.ANNOTATION)) {
++_annotationDepth;
}
//-- check namespace
if (!XSD_NAMESPACE.equals(namespace)) {
if (_annotationDepth == 0) {
error("'" + name + "' has not been declared in the XML "
+ "Schema namespace.");
}
}
//-- handle namespace prefix remapping
if (_annotationDepth == 0) {
if (_prefixMappings != null) {
handleRemapping(name, namespace, (AttributeSetImpl) atts);
}
}
//-- Do delagation if necessary
if (_unmarshaller != null) {
try {
_unmarshaller.startElement(name, namespace, atts, nsDecls);
} catch (RuntimeException rtx) {
error(rtx);
}
++_depth;
return;
}
if (name.equals(SchemaNames.SCHEMA)) {
if (foundSchemaDef) {
illegalElement(name);
}
foundSchemaDef = true;
init(atts);
return;
}
//-- <annotation>
if (name.equals(SchemaNames.ANNOTATION)) {
_unmarshaller = new AnnotationUnmarshaller(getSchemaContext(), atts);
} else if (name.equals(SchemaNames.ATTRIBUTE)) {
//--<attribute>
_unmarshaller = new AttributeUnmarshaller(getSchemaContext(), _schema, atts);
} else if (name.equals(SchemaNames.ATTRIBUTE_GROUP)) {
//-- <attributeGroup>
_unmarshaller = new AttributeGroupUnmarshaller(getSchemaContext(), _schema, atts);
} else if (name.equals(SchemaNames.COMPLEX_TYPE)) {
//-- <complexType>
_unmarshaller
= new ComplexTypeUnmarshaller(getSchemaContext(), _schema, atts);
} else if (name.equals(SchemaNames.ELEMENT)) {
//-- <element>
_unmarshaller
= new ElementUnmarshaller(getSchemaContext(), _schema, atts);
} else if (name.equals(SchemaNames.SIMPLE_TYPE)) {
//-- <simpleType>
_unmarshaller = new SimpleTypeUnmarshaller(getSchemaContext(), _schema, atts);
} else if (name.equals(SchemaNames.GROUP)) {
//-- <group>
_unmarshaller = new ModelGroupUnmarshaller(getSchemaContext(), _schema, atts);
} else if (name.equals(SchemaNames.INCLUDE)) {
//-- <include>
_unmarshaller
= new IncludeUnmarshaller(getSchemaContext(), _schema, atts,
getURIResolver(), getDocumentLocator(), _state);
} else if (name.equals(SchemaNames.IMPORT)) {
//-- <import>
_unmarshaller
= new ImportUnmarshaller(getSchemaContext(), _schema, atts,
getURIResolver(), getDocumentLocator(), _state);
} else if (name.equals(SchemaNames.REDEFINE)) {
//-- <redefine>
_unmarshaller
= new RedefineUnmarshaller(getSchemaContext(), _schema, atts,
getURIResolver(), getDocumentLocator(), _state);
} else {
//-- we should throw a new Exception here
//-- but since we don't support everything
//-- yet, simply add an UnknownDef object
System.out.print('<');
System.out.print(name);
System.out.print("> elements are either currently unsupported ");
System.out.println("or non-valid schema elements.");
_unmarshaller = new UnknownUnmarshaller(getSchemaContext(), name);
}
// unmarshaller.setDocumentLocator(getDocumentLocator());
} //-- startElement
/**
* Signals to end of the element with the given name.
*
* @param name the NCName of the element. It is an error
* if the name is a QName (ie. contains a prefix).
* @param namespace the namespace of the element.
* @throws XMLException To indicate that the current element cannnot be processed successfully.
**/
public void endElement(String name, String namespace)
throws XMLException {
if (skipAll) {
return;
}
//-- DEBUG
//System.out.println("#endElement: " + name + " {" + namespace + "}");
//-- /DEBUG
//-- backward compatibility
if (namespace == null) {
namespace = _defaultNS;
}
//-- keep track of annotations
if (name.equals(SchemaNames.ANNOTATION)) {
--_annotationDepth;
}
//-- remove namespace remapping, if necessary
if (_prefixMappings != null) {
if (_prefixMappings.depth == 0) {
_prefixMappings = _prefixMappings.getParent();
} else {
--_prefixMappings.depth;
}
}
//-- Do delagation if necessary
if ((_unmarshaller != null) && (_depth > 0)) {
_unmarshaller.endElement(name, namespace);
--_depth;
return;
}
//-- use internal JVM String
name = name.intern();
if (name == SchemaNames.SCHEMA) {
return;
}
//-- check for name mismatches
if ((_unmarshaller != null)) {
if (!name.equals(_unmarshaller.elementName())) {
String err = "error: missing end element for ";
err += _unmarshaller.elementName();
throw new SchemaException(err);
}
} else {
String err = "error: missing start element for " + name;
throw new SchemaException(err);
}
//-- call unmarshaller.finish() to perform any necessary cleanup
_unmarshaller.finish();
//-- <annotation>
if (name.equals(SchemaNames.ANNOTATION)) {
_schema.addAnnotation((Annotation) _unmarshaller.getObject());
} else if (name.equals(SchemaNames.ATTRIBUTE)) {
//-- <attribute>
_schema.addAttribute((AttributeDecl) _unmarshaller.getObject());
} else if (name.equals(SchemaNames.ATTRIBUTE_GROUP)) {
//-- <attributeGroup>
Object obj = _unmarshaller.getObject();
try {
_schema.addAttributeGroup((AttributeGroupDecl) obj);
} catch (ClassCastException ex) {
String err = "Top-level AttributeGroups must be defining "
+ "AttributeGroups and not referring AttributeGroups.";
error(err);
}
} else if (name.equals(SchemaNames.COMPLEX_TYPE)) {
//-- <complexType>
ComplexType complexType = null;
complexType = ((ComplexTypeUnmarshaller) _unmarshaller).getComplexType();
_schema.addComplexType(complexType);
if (complexType.getName() != null) {
getResolver().addResolvable(complexType.getReferenceId(), complexType);
} else {
System.out.println("warning: top-level complexType with no name.");
}
} else if (name.equals(SchemaNames.SIMPLE_TYPE)) {
//-- <simpleType>
SimpleType simpleType = null;
simpleType = ((SimpleTypeUnmarshaller) _unmarshaller).getSimpleType();
_schema.addSimpleType(simpleType);
getResolver().addResolvable(simpleType.getReferenceId(), simpleType);
} else if (name.equals(SchemaNames.ELEMENT)) {
//--<element>
ElementDecl element = null;
element = ((ElementUnmarshaller) _unmarshaller).getElement();
_schema.addElementDecl(element);
} else if (name.equals(SchemaNames.GROUP)) {
//--<group>
ModelGroup group = null;
group = (((ModelGroupUnmarshaller) _unmarshaller).getGroup());
_schema.addModelGroup(group);
} else if (name.equals(SchemaNames.REDEFINE)) {
//--<redefine>
RedefineSchema redefine = null;
redefine = (RedefineSchema) (((RedefineUnmarshaller) _unmarshaller).getObject());
if ((redefine.getSchemaLocation() == null) && (redefine.hasRedefinition())) {
_schema.removeRedefineSchema(redefine);
String err = "A <redefine> structure with no 'schemaLocation' "
+ "attribute must contain only <annotation> elements";
error(err);
}
}
_unmarshaller = null;
} //-- endElement
/**
* {@inheritDoc}
*
* @see org.exolab.castor.xml.schema.reader.ComponentReader#characters(char[], int, int)
*/
public void characters(final char[] ch, final int start, final int length)
throws XMLException {
//-- Do delagation if necessary
if (_unmarshaller != null) {
_unmarshaller.characters(ch, start, length);
}
} //-- characters
/**
* This class handles remapping of namespace prefixes
* for attributes of type QName. This is needed to
* work around a limitation in Castor's Schema Object
* Model, which does not support proper namespace
* scoping yet.
*/
static class RemappedPrefixes {
public static final String RESOURCE_NAME
= "prefixremap.properties";
public static final String RESOURCE_LOCATION =
"/org/exolab/castor/xml/schema/reader/";
public static final HashMap QNAME_TABLE = new HashMap();
private static boolean initialized = false;
static {
synchronized (QNAME_TABLE) {
if (!initialized) {
initialized = true;
//-- built in mappings
//-- attribute
QNAME_TABLE.put(SchemaNames.ATTRIBUTE, new String [] {
SchemaNames.REF_ATTR, SchemaNames.TYPE_ATTR });
//-- attributeGroup
QNAME_TABLE.put(SchemaNames.ATTRIBUTE_GROUP, new String [] {
SchemaNames.REF_ATTR });
//-- element
QNAME_TABLE.put(SchemaNames.ELEMENT, new String [] {
SchemaNames.REF_ATTR, SchemaNames.TYPE_ATTR });
//-- extension
QNAME_TABLE.put(SchemaNames.EXTENSION, new String [] {
SchemaNames.BASE_ATTR });
//-- group
QNAME_TABLE.put(SchemaNames.GROUP, new String [] {
SchemaNames.REF_ATTR });
//-- restriction
QNAME_TABLE.put(SchemaNames.RESTRICTION, new String [] {
SchemaNames.BASE_ATTR });
//-- custom mappings
String filename = RESOURCE_LOCATION + RESOURCE_NAME;
InputStream is = SchemaUnmarshaller.class.getResourceAsStream(filename);
Properties props = new Properties();
if (is != null) {
try {
props.load(is);
} catch (java.io.IOException iox) {
//-- just use built-in mappings
}
}
Enumeration keys = props.propertyNames();
while (keys.hasMoreElements()) {
String name = (String) keys.nextElement();
StringTokenizer st = new StringTokenizer(props.getProperty(name), ",");
String[] atts = new String[st.countTokens()];
int index = 0;
while (st.hasMoreTokens()) {
atts[index++] = st.nextToken();
}
QNAME_TABLE.put(name, atts);
}
}
}
}
private HashMap _prefixes = null;
private RemappedPrefixes _parent = null;
int depth = 0;
public boolean isRemappedPrefix(String prefix) {
if (prefix == null) prefix = "";
if (_prefixes != null) {
if (_prefixes.get(prefix) != null) return true;
}
if (_parent != null) {
return _parent.isRemappedPrefix(prefix);
}
return false;
}
public RemappedPrefixes getParent() {
return _parent;
}
public String getPrefixMapping(final String oldPrefix) {
if (_prefixes != null) {
String newPrefix = (String)_prefixes.get(oldPrefix);
if (newPrefix != null)
return newPrefix;
}
if (_parent != null) {
return _parent.getPrefixMapping(oldPrefix);
}
return oldPrefix;
}
public RemappedPrefixes newRemappedPrefixes() {
RemappedPrefixes rp = new RemappedPrefixes();
rp._parent = this;
return rp;
}
public void addMapping(final String oldPrefix, final String newPrefix) {
if (_prefixes == null) {
_prefixes = new HashMap();
}
_prefixes.put(oldPrefix, newPrefix);
}
public String remapQName(String value) {
if (value == null) {
return null;
}
//-- non-default namespace
int idx = value.indexOf(':');
String prefix = "";
if (idx >= 0) {
prefix = value.substring(0, idx);
} else {
idx = -1;
}
String newPrefix = getPrefixMapping(prefix);
if (!prefix.equals(newPrefix)) {
if (newPrefix.length() == 0) {
value = value.substring(idx + 1);
} else {
value = newPrefix + ":" + value.substring(idx + 1);
}
}
return value;
} //-- remapValue
}
} //-- SchemaUnmarshaller