001: /**
002: * Redistribution and use of this software and associated documentation
003: * ("Software"), with or without modification, are permitted provided
004: * that the following conditions are met:
005: *
006: * 1. Redistributions of source code must retain copyright
007: * statements and notices. Redistributions must also contain a
008: * copy of this document.
009: *
010: * 2. Redistributions in binary form must reproduce the
011: * above copyright notice, this list of conditions and the
012: * following disclaimer in the documentation and/or other
013: * materials provided with the distribution.
014: *
015: * 3. The name "Exolab" must not be used to endorse or promote
016: * products derived from this Software without prior written
017: * permission of Intalio, Inc. For written permission,
018: * please contact info@exolab.org.
019: *
020: * 4. Products derived from this Software may not be called "Exolab"
021: * nor may "Exolab" appear in their names without prior written
022: * permission of Intalio, Inc. Exolab is a registered
023: * trademark of Intalio, Inc.
024: *
025: * 5. Due credit should be given to the Exolab Project
026: * (http://www.exolab.org/).
027: *
028: * THIS SOFTWARE IS PROVIDED BY INTALIO, INC. AND CONTRIBUTORS
029: * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
030: * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
031: * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
032: * INTALIO, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
033: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
034: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
035: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
036: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
037: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
038: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
039: * OF THE POSSIBILITY OF SUCH DAMAGE.
040: *
041: * Copyright 1999-2004 (C) Intalio Inc. All Rights Reserved.
042: *
043: * $Id: SchemaUnmarshaller.java 5951 2006-05-30 22:18:48Z bsnyder $
044: */package org.exolab.castor.xml.schema.reader;
045:
046: //-- imported classes and packages
047: import org.exolab.castor.xml.*;
048: import org.exolab.castor.xml.util.AttributeSetImpl;
049: import org.exolab.castor.xml.schema.*;
050: import org.exolab.castor.net.URIResolver;
051: import org.exolab.castor.net.util.URIResolverImpl;
052:
053: import java.util.Enumeration;
054: import java.util.HashMap;
055: import java.util.Properties;
056: import java.util.StringTokenizer;
057:
058: import java.io.InputStream;
059:
060: /**
061: * @author <a href="mailto:kvisco@intalio.com">Keith Visco</a>
062: * @version $Revision: 5951 $ $Date: 2006-04-13 06:47:36 -0600 (Thu, 13 Apr 2006) $
063: **/
064: public class SchemaUnmarshaller extends ComponentReader {
065:
066: public static final String XSD_NAMESPACE = "http://www.w3.org/2001/XMLSchema";
067:
068: public static final String[] UNSUPPORTED_NAMESPACES = {
069: "http://www.w3.org/2000/10/XMLSchema",
070: "http://www.w3.org/1999/XMLSchema" };
071:
072: //--------------------/
073: //- Member Variables -/
074: //--------------------/
075:
076: /**
077: * is this an included schema?
078: */
079: private boolean _include = false;
080: /**
081: * The current ComponentReader
082: **/
083: private ComponentReader unmarshaller;
084:
085: /**
086: * Flag to indicate we are inside an annotation element
087: **/
088: private int _annotationDepth = 0;
089:
090: /**
091: * The current branch depth
092: **/
093: private int depth = 0;
094:
095: boolean skipAll = false;
096:
097: /**
098: * The ID Resolver
099: **/
100: Resolver _resolver = null;
101:
102: Schema _schema = null;
103:
104: private boolean foundSchemaDef = false;
105:
106: private String defaultNS = null;
107:
108: /**
109: * The SchemaUnmarsahller state
110: */
111: private SchemaUnmarshallerState _state = null;
112:
113: private RemappedPrefixes _prefixMappings = null;
114:
115: //----------------/
116: //- Constructors -/
117: //----------------/
118:
119: public SchemaUnmarshaller() throws XMLException {
120: this (null, null, null);
121: foundSchemaDef = false;
122: } //-- SchemaUnmarshaller
123:
124: public SchemaUnmarshaller(SchemaUnmarshallerState state)
125: throws XMLException {
126: this (null, null, null);
127: _state = state;
128: foundSchemaDef = false;
129: } //-- SchemaUnmarshaller
130:
131: public SchemaUnmarshaller(boolean include,
132: SchemaUnmarshallerState state, URIResolver uriResolver)
133: throws XMLException {
134: this (null, null, uriResolver);
135: _state = state;
136: _include = include;
137: foundSchemaDef = false;
138: }
139:
140: //--backward compatibility
141: public SchemaUnmarshaller(AttributeSet atts, Resolver resolver)
142: throws XMLException {
143: this (atts, resolver, null);
144: }
145:
146: public SchemaUnmarshaller(AttributeSet atts, Resolver resolver,
147: URIResolver uriResolver) throws XMLException {
148: super ();
149: _schema = new Schema();
150: //--initialize the schema to ensure that the default namespace
151: //--is not set
152: _schema.removeNamespace("");
153: setResolver(resolver);
154: if (uriResolver == null)
155: uriResolver = new URIResolverImpl();
156: setURIResolver(uriResolver);
157: foundSchemaDef = true;
158: _state = new SchemaUnmarshallerState();
159: init(atts);
160: } //-- SchemaUnmarshaller
161:
162: public Schema getSchema() {
163: return _schema;
164: }
165:
166: public void setSchema(Schema schema) {
167: _schema = schema;
168: }
169:
170: /**
171: * Returns the Object created by this ComponentReader
172: * @return the Object created by this ComponentReader
173: **/
174: public Object getObject() {
175: return getSchema();
176: } //-- getObject
177:
178: /**
179: * Returns the name of the element that this ComponentReader
180: * handles
181: * @return the name of the element that this ComponentReader
182: * handles
183: **/
184: public String elementName() {
185: return SchemaNames.SCHEMA;
186: } //-- elementName
187:
188: /**
189: * initializes the Schema object with the given attribute list
190: * @param atts the AttributeList for the schema
191: **/
192: private void init(AttributeSet atts) throws XMLException {
193: if (atts == null)
194: return;
195:
196: String attValue = null;
197:
198: String nsURI = atts.getValue(SchemaNames.TARGET_NS_ATTR);
199: if (nsURI != null && nsURI.length() == 0)
200: throw new SchemaException(
201: "empty string is not a legal namespace.");
202: if ((nsURI != null) && (nsURI.length() > 0)) {
203: if (!_state.cacheIncludedSchemas) {
204: //if we are including a schema we must take care
205: //that the namespaces are the same
206: if ((_include)
207: && (!_schema.getTargetNamespace().equals(nsURI))) {
208: throw new SchemaException(
209: "The target namespace of the included components must be the same as the target namespace of the including schema");
210: }
211: }
212: _schema.setTargetNamespace(nsURI);
213: }
214:
215: _schema.setId(atts.getValue(SchemaNames.ID_ATTR));
216: _schema.setVersion(atts.getValue(SchemaNames.VERSION_ATTR));
217:
218: //set the default locator of this schema
219: if (!_include || _state.cacheIncludedSchemas) {
220: _schema.setSchemaLocation(getDocumentLocator()
221: .getSystemId());
222: }
223:
224: //-- attributeFormDefault
225: String form = atts.getValue(SchemaNames.ATTR_FORM_DEFAULT_ATTR);
226: if (form != null) {
227: _schema.setAttributeFormDefault(Form.valueOf(form));
228: }
229:
230: //-- elementFormDefault
231: form = atts.getValue(SchemaNames.ELEM_FORM_DEFAULT_ATTR);
232: if (form != null) {
233: _schema.setElementFormDefault(Form.valueOf(form));
234: }
235:
236: //-- @blockDefault
237: attValue = atts.getValue(SchemaNames.BLOCK_DEFAULT_ATTR);
238: if (attValue != null) {
239: _schema.setBlockDefault(attValue);
240: }
241:
242: //-- @finalDefault
243: attValue = atts.getValue(SchemaNames.FINAL_DEFAULT_ATTR);
244: if (attValue != null) {
245: _schema.setFinalDefault(attValue);
246: }
247:
248: //--@version
249: attValue = atts.getValue(SchemaNames.VERSION_ATTR);
250: if (attValue != null) {
251: _schema.setVersion(attValue);
252: }
253:
254: } //-- init
255:
256: /**
257: * Handles namespace attributes
258: **/
259: private void handleNamespaces(Namespaces namespaces)
260: throws XMLException {
261:
262: if (namespaces == null)
263: return;
264:
265: Enumeration enumeration = namespaces.getLocalNamespaces();
266:
267: while (enumeration.hasMoreElements()) {
268:
269: String ns = (String) enumeration.nextElement();
270: String[] prefixes = namespaces.getNamespacePrefixes(ns,
271: true);
272:
273: if (prefixes.length == 0) {
274: //-- this should never happen, but report error just
275: //-- in case there is a bug in Namespaces class.
276: String error = "unexpected error processing the following "
277: + "namespace: '"
278: + ns
279: + "'; the prefix could not be resolved.";
280: throw new XMLException(error);
281: }
282:
283: boolean hasCollisions = false;
284: for (int pIdx = 0; pIdx < prefixes.length; pIdx++) {
285: String prefix = prefixes[pIdx];
286:
287: //-- Since the Schema Object Model does not yet support
288: //-- namespace scoping, we need to checking for namespace
289: //-- prefix collisions...and remap the prefixes
290: String tmpURI = _schema.getNamespace(prefix);
291: if ((tmpURI != null) && (foundSchemaDef)) {
292: if (!tmpURI.equals(ns)) {
293: if (!hasCollisions) {
294: hasCollisions = true;
295: if (_prefixMappings == null)
296: _prefixMappings = new RemappedPrefixes();
297: else
298: _prefixMappings = _prefixMappings
299: .newRemappedPrefixes();
300: }
301:
302: //-- create a new prefix
303: if (prefix.length() == 0)
304: prefix = "ns";
305:
306: int count = 1;
307: String newPrefix = prefix + count;
308: tmpURI = _schema.getNamespace(newPrefix);
309: while (tmpURI != null) {
310: if (tmpURI.equals(ns)) {
311: //-- no remapping necessary
312: break;
313: }
314: ++count;
315: newPrefix = prefix + count;
316: tmpURI = _schema.getNamespace(newPrefix);
317: }
318: _prefixMappings.addMapping(prefix, newPrefix);
319: prefix = newPrefix;
320: }
321: //-- we may need to "reset" a currently mapped prefix
322: else {
323: if (_prefixMappings != null) {
324: if (_prefixMappings
325: .isRemappedPrefix(prefix)) {
326: //-- reset mapping in this scope
327: _prefixMappings.addMapping(prefix,
328: prefix);
329: }
330: }
331: }
332: }
333: //-- end collision handling
334:
335: if (prefix.length() == 0) {
336: defaultNS = ns;
337: //register the default namespace with the empty string
338: _schema.addNamespace("", defaultNS);
339: } else {
340: //-- check for old unsupported schema namespaces
341: for (int nsIdx = 0; nsIdx < UNSUPPORTED_NAMESPACES.length; nsIdx++) {
342: if (ns.equals(UNSUPPORTED_NAMESPACES[nsIdx]))
343: error("The following namespace \""
344: + ns
345: + "\" is no longer supported. Please update to "
346: + " the W3C XML Schema Recommendation.");
347: }
348: _schema.addNamespace(prefix, ns);
349: }
350: }
351: }
352:
353: } //-- handleNamespaces
354:
355: /**
356: * Remaps any QName attributes for the given element and attributeSet.
357: * This method is a work around for the lack of namespace scoping
358: * support in the Schema Object Model
359: */
360: private void handleRemapping(String name, String namespace,
361: AttributeSetImpl atts) {
362:
363: if (_prefixMappings == null)
364: return;
365:
366: //-- increase depth for scoping
367: _prefixMappings.depth++;
368:
369: String[] remapAtts = (String[]) RemappedPrefixes.QNAME_TABLE
370: .get(name);
371:
372: if (remapAtts != null) {
373: for (int i = 0; i < remapAtts.length; i++) {
374: String value = atts.getValue(remapAtts[i]);
375: if (value != null) {
376: value = _prefixMappings.remapQName(value);
377: atts.setAttribute(remapAtts[i], value);
378: }
379: }
380: }
381:
382: } //-- handleRemapping
383:
384: public void setResolver(Resolver resolver) {
385: if (resolver == null)
386: resolver = new ScopableResolver();
387: super .setResolver(resolver);
388: _resolver = resolver;
389: } //-- setResolver
390:
391: /**
392: * Signals the start of an element with the given name.
393: *
394: * @param name the NCName of the element. It is an error
395: * if the name is a QName (ie. contains a prefix).
396: * @param namespace the namespace of the element. This may be null.
397: * Note: A null namespace is not the same as the default namespace unless
398: * the default namespace is also null.
399: * @param atts the AttributeSet containing the attributes associated
400: * with the element.
401: * @param nsDecls the namespace declarations being declared for this
402: * element. This may be null.
403: **/
404: public void startElement(String name, String namespace,
405: AttributeSet atts, Namespaces nsDecls) throws XMLException {
406:
407: if (skipAll)
408: return;
409:
410: //-- DEBUG
411: //System.out.println("#startElement: " + name + " {" + namespace + "}");
412: //-- /DEBUG
413:
414: //-- process namespaces...unless we are inside an
415: //-- annotation
416: if (_annotationDepth == 0)
417: handleNamespaces(nsDecls);
418:
419: //-- backward compatibility, we'll need to
420: //-- remove this at some point
421: if ((!foundSchemaDef) && (namespace == null)) {
422: if (defaultNS == null) {
423: defaultNS = XSD_NAMESPACE;
424: namespace = XSD_NAMESPACE;
425: System.out.println("No namespace declaration has been "
426: + "found for " + name);
427: System.out.print(" * assuming default namespace of ");
428: System.out.println(XSD_NAMESPACE);
429: }
430: }
431: if (namespace == null)
432: namespace = defaultNS;
433: //-- end of backward compatibility
434:
435: //-- keep track of annotations
436: if (name.equals(SchemaNames.ANNOTATION)) {
437: ++_annotationDepth;
438: }
439:
440: //-- check namespace
441: if (!XSD_NAMESPACE.equals(namespace)) {
442: if (_annotationDepth == 0) {
443: error("'" + name
444: + "' has not been declared in the XML "
445: + "Schema namespace.");
446: }
447: }
448:
449: //-- handle namespace prefix remapping
450: if (_annotationDepth == 0) {
451: if (_prefixMappings != null) {
452: handleRemapping(name, namespace,
453: (AttributeSetImpl) atts);
454: }
455: }
456:
457: //-- Do delagation if necessary
458: if (unmarshaller != null) {
459: try {
460: unmarshaller.startElement(name, namespace, atts,
461: nsDecls);
462: } catch (RuntimeException rtx) {
463: error(rtx);
464: }
465: ++depth;
466: return;
467: }
468:
469: if (name.equals(SchemaNames.SCHEMA)) {
470:
471: if (foundSchemaDef)
472: illegalElement(name);
473:
474: foundSchemaDef = true;
475: init(atts);
476: return;
477: }
478:
479: //-- <annotation>
480: if (name.equals(SchemaNames.ANNOTATION)) {
481: unmarshaller = new AnnotationUnmarshaller(atts);
482: }
483: //--<attribute>
484: else if (name.equals(SchemaNames.ATTRIBUTE)) {
485: unmarshaller = new AttributeUnmarshaller(_schema, atts,
486: getResolver());
487: }
488: //-- <attributeGroup>
489: else if (name.equals(SchemaNames.ATTRIBUTE_GROUP)) {
490: unmarshaller = new AttributeGroupUnmarshaller(_schema, atts);
491: }
492: //-- <complexType>
493: else if (name.equals(SchemaNames.COMPLEX_TYPE)) {
494: unmarshaller = new ComplexTypeUnmarshaller(_schema, atts,
495: _resolver);
496: }
497: //-- <element>
498: else if (name.equals(SchemaNames.ELEMENT)) {
499: unmarshaller = new ElementUnmarshaller(_schema, atts,
500: _resolver);
501: }
502: //-- <simpleType>
503: else if (name.equals(SchemaNames.SIMPLE_TYPE)) {
504: unmarshaller = new SimpleTypeUnmarshaller(_schema, atts);
505: }
506: //-- <group>
507: else if (name.equals(SchemaNames.GROUP)) {
508: unmarshaller = new ModelGroupUnmarshaller(_schema, atts,
509: _resolver);
510: }
511: //-- <include>
512: else if (name.equals(SchemaNames.INCLUDE)) {
513: unmarshaller = new IncludeUnmarshaller(_schema, atts,
514: _resolver, getURIResolver(), getDocumentLocator(),
515: _state);
516: }
517: //-- <import>
518: else if (name.equals(SchemaNames.IMPORT)) {
519: unmarshaller = new ImportUnmarshaller(_schema, atts,
520: _resolver, getURIResolver(), getDocumentLocator(),
521: _state);
522: }
523: //-- <redefine>
524: else if (name.equals(SchemaNames.REDEFINE)) {
525: unmarshaller = new RedefineUnmarshaller(_schema, atts,
526: _resolver, getURIResolver(), getDocumentLocator(),
527: _state);
528: } else {
529: //-- we should throw a new Exception here
530: //-- but since we don't support everything
531: //-- yet, simply add an UnknownDef object
532: System.out.print('<');
533: System.out.print(name);
534: System.out
535: .print("> elements are either currently unsupported ");
536: System.out.println("or non-valid schema elements.");
537: unmarshaller = new UnknownUnmarshaller(name);
538: }
539:
540: unmarshaller.setDocumentLocator(getDocumentLocator());
541:
542: } //-- startElement
543:
544: /**
545: * Signals to end of the element with the given name.
546: *
547: * @param name the NCName of the element. It is an error
548: * if the name is a QName (ie. contains a prefix).
549: * @param namespace the namespace of the element.
550: **/
551: public void endElement(String name, String namespace)
552: throws XMLException {
553: if (skipAll)
554: return;
555:
556: //-- DEBUG
557: //System.out.println("#endElement: " + name + " {" + namespace + "}");
558: //-- /DEBUG
559:
560: //-- backward compatibility
561: if (namespace == null)
562: namespace = defaultNS;
563:
564: //-- keep track of annotations
565: if (name.equals(SchemaNames.ANNOTATION)) {
566: --_annotationDepth;
567: }
568:
569: //-- remove namespace remapping, if necessary
570: if (_prefixMappings != null) {
571: if (_prefixMappings.depth == 0) {
572: _prefixMappings = _prefixMappings.getParent();
573: } else
574: --_prefixMappings.depth;
575: }
576:
577: //-- Do delagation if necessary
578: if ((unmarshaller != null) && (depth > 0)) {
579: unmarshaller.endElement(name, namespace);
580: --depth;
581: return;
582: }
583:
584: //-- use internal JVM String
585: name = name.intern();
586:
587: if (name == SchemaNames.SCHEMA)
588: return;
589:
590: //-- check for name mismatches
591: if ((unmarshaller != null)) {
592: if (!name.equals(unmarshaller.elementName())) {
593: String err = "error: missing end element for ";
594: err += unmarshaller.elementName();
595: throw new SchemaException(err);
596: }
597: } else {
598: String err = "error: missing start element for " + name;
599: throw new SchemaException(err);
600: }
601:
602: //-- call unmarshaller.finish() to perform any necessary cleanup
603: unmarshaller.finish();
604:
605: //-- <annotation>
606: if (name.equals(SchemaNames.ANNOTATION)) {
607: _schema
608: .addAnnotation((Annotation) unmarshaller
609: .getObject());
610: }
611: //-- <attribute>
612: else if (name.equals(SchemaNames.ATTRIBUTE)) {
613: _schema.addAttribute((AttributeDecl) unmarshaller
614: .getObject());
615: }
616: //-- <attributeGroup>
617: else if (name.equals(SchemaNames.ATTRIBUTE_GROUP)) {
618: Object obj = unmarshaller.getObject();
619: try {
620: _schema.addAttributeGroup((AttributeGroupDecl) obj);
621: } catch (ClassCastException ex) {
622: String err = "Top-level AttributeGroups must be defining "
623: + "AttributeGroups and not referring AttributeGroups.";
624: error(err);
625: }
626: }
627: //-- <complexType>
628: else if (name.equals(SchemaNames.COMPLEX_TYPE)) {
629: ComplexType complexType = null;
630: complexType = ((ComplexTypeUnmarshaller) unmarshaller)
631: .getComplexType();
632: _schema.addComplexType(complexType);
633: if (complexType.getName() != null) {
634: _resolver.addResolvable(complexType.getReferenceId(),
635: complexType);
636: } else {
637: System.out
638: .println("warning: top-level complexType with no name.");
639: }
640: }
641: //-- <simpleType>
642: else if (name.equals(SchemaNames.SIMPLE_TYPE)) {
643: SimpleType simpleType = null;
644: simpleType = ((SimpleTypeUnmarshaller) unmarshaller)
645: .getSimpleType();
646: _schema.addSimpleType(simpleType);
647: _resolver.addResolvable(simpleType.getReferenceId(),
648: simpleType);
649: }
650: //--<element>
651: else if (name.equals(SchemaNames.ELEMENT)) {
652: ElementDecl element = null;
653: element = ((ElementUnmarshaller) unmarshaller).getElement();
654: _schema.addElementDecl(element);
655: }
656: //--<group>
657: else if (name.equals(SchemaNames.GROUP)) {
658: ModelGroup group = null;
659: group = (((ModelGroupUnmarshaller) unmarshaller).getGroup());
660: _schema.addModelGroup(group);
661: }
662: //--<redefine>
663: else if (name.equals(SchemaNames.REDEFINE)) {
664: RedefineSchema redefine = null;
665: redefine = (RedefineSchema) (((RedefineUnmarshaller) unmarshaller)
666: .getObject());
667: if ((redefine.getSchemaLocation() == null)
668: && (redefine.hasRedefinition())) {
669: _schema.removeRedefineSchema(redefine);
670: String err = "A <redefine> structure with no 'schemaLocation' attribute must contain only <annotation> elements";
671: error(err);
672: }
673: }
674:
675: unmarshaller = null;
676: } //-- endElement
677:
678: public void characters(char[] ch, int start, int length)
679: throws XMLException {
680: //-- Do delagation if necessary
681: if (unmarshaller != null) {
682: unmarshaller.characters(ch, start, length);
683: }
684: } //-- characters
685:
686: /**
687: * This class handles remapping of namespace prefixes
688: * for attributes of type QName. This is needed to
689: * work around a limitation in Castor's Schema Object
690: * Model, which does not support proper namespace
691: * scoping yet.
692: */
693: static class RemappedPrefixes {
694:
695: public static final String RESOURCE_NAME = "prefixremap.properties";
696:
697: public static final String RESOURCE_LOCATION = "/org/exolab/castor/xml/schema/reader/";
698:
699: public static final HashMap QNAME_TABLE = new HashMap();
700: private static boolean initialized = false;
701:
702: static {
703:
704: synchronized (QNAME_TABLE) {
705:
706: if (!initialized) {
707:
708: initialized = true;
709:
710: //-- built in mappings
711:
712: //-- attribute
713: QNAME_TABLE.put(SchemaNames.ATTRIBUTE,
714: new String[] { SchemaNames.REF_ATTR,
715: SchemaNames.TYPE_ATTR });
716:
717: //-- attributeGroup
718: QNAME_TABLE.put(SchemaNames.ATTRIBUTE_GROUP,
719: new String[] { SchemaNames.REF_ATTR });
720:
721: //-- element
722: QNAME_TABLE.put(SchemaNames.ELEMENT,
723: new String[] { SchemaNames.REF_ATTR,
724: SchemaNames.TYPE_ATTR });
725:
726: //-- extension
727: QNAME_TABLE.put(SchemaNames.EXTENSION,
728: new String[] { SchemaNames.BASE_ATTR });
729:
730: //-- group
731: QNAME_TABLE.put(SchemaNames.GROUP,
732: new String[] { SchemaNames.REF_ATTR });
733:
734: //-- restriction
735: QNAME_TABLE.put(SchemaNames.RESTRICTION,
736: new String[] { SchemaNames.BASE_ATTR });
737:
738: //-- custom mappings
739: String filename = RESOURCE_LOCATION + RESOURCE_NAME;
740: InputStream is = SchemaUnmarshaller.class
741: .getResourceAsStream(filename);
742: Properties props = new Properties();
743: if (is != null) {
744: try {
745: props.load(is);
746: } catch (java.io.IOException iox) {
747: //-- just use built-in mappings
748: }
749: }
750:
751: Enumeration keys = props.propertyNames();
752: while (keys.hasMoreElements()) {
753: String name = (String) keys.nextElement();
754: StringTokenizer st = new StringTokenizer(props
755: .getProperty(name), ",");
756: String[] atts = new String[st.countTokens()];
757: int index = 0;
758: while (st.hasMoreTokens()) {
759: atts[index++] = st.nextToken();
760: }
761: QNAME_TABLE.put(name, atts);
762: }
763:
764: }
765: }
766: }
767:
768: private HashMap _prefixes = null;
769:
770: private RemappedPrefixes _parent = null;
771:
772: int depth = 0;
773:
774: public boolean isRemappedPrefix(String prefix) {
775:
776: if (prefix == null)
777: prefix = "";
778:
779: if (_prefixes != null) {
780: if (_prefixes.get(prefix) != null)
781: return true;
782: }
783:
784: if (_parent != null) {
785: return _parent.isRemappedPrefix(prefix);
786: }
787: return false;
788: }
789:
790: public RemappedPrefixes getParent() {
791: return _parent;
792: }
793:
794: public String getPrefixMapping(String oldPrefix) {
795:
796: if (_prefixes != null) {
797: String newPrefix = (String) _prefixes.get(oldPrefix);
798: if (newPrefix != null)
799: return newPrefix;
800: }
801:
802: if (_parent != null) {
803: return _parent.getPrefixMapping(oldPrefix);
804: }
805:
806: return oldPrefix;
807: }
808:
809: public RemappedPrefixes newRemappedPrefixes() {
810: RemappedPrefixes rp = new RemappedPrefixes();
811: rp._parent = this ;
812: return rp;
813: }
814:
815: public void addMapping(String oldPrefix, String newPrefix) {
816: if (_prefixes == null) {
817: _prefixes = new HashMap();
818: }
819: _prefixes.put(oldPrefix, newPrefix);
820: }
821:
822: public String remapQName(String value) {
823: if (value == null)
824: return null;
825:
826: //-- non-default namespace
827: int idx = value.indexOf(':');
828: String prefix = "";
829: if (idx >= 0) {
830: prefix = value.substring(0, idx);
831: } else
832: idx = -1;
833: String newPrefix = getPrefixMapping(prefix);
834: if (!prefix.equals(newPrefix)) {
835: if (newPrefix.length() == 0)
836: value = value.substring(idx + 1);
837: else
838: value = newPrefix + ":" + value.substring(idx + 1);
839: }
840:
841: return value;
842: } //-- remapValue
843:
844: }
845:
846: } //-- SchemaUnmarshaller
|