View Javadoc
1   /**
2    * Redistribution and use of this software and associated documentation ("Software"), with or
3    * without modification, are permitted provided that the following conditions are met:
4    *
5    * 1. Redistributions of source code must retain copyright statements and notices. Redistributions
6    * must also contain a copy of this document.
7    *
8    * 2. Redistributions in binary form must reproduce the above copyright notice, this list of
9    * conditions and the following disclaimer in the documentation and/or other materials provided with
10   * the distribution.
11   *
12   * 3. The name "Exolab" must not be used to endorse or promote products derived from this Software
13   * without prior written permission of Intalio, Inc. For written permission, please contact
14   * info@exolab.org.
15   *
16   * 4. Products derived from this Software may not be called "Exolab" nor may "Exolab" appear in
17   * their names without prior written permission of Intalio, Inc. Exolab is a registered trademark of
18   * Intalio, Inc.
19   *
20   * 5. Due credit should be given to the Exolab Project (http://www.exolab.org/).
21   *
22   * THIS SOFTWARE IS PROVIDED BY INTALIO, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESSED OR
23   * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
24   * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTALIO, INC. OR ITS
25   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28   * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
29   * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30   *
31   * Copyright 1999-2003 (C) Intalio, Inc. All Rights Reserved.
32   *
33   * $Id$
34   */
35  
36  package org.exolab.castor.xml.schema.writer;
37  
38  import java.io.IOException;
39  import java.io.Writer;
40  import java.util.Collection;
41  import java.util.Enumeration;
42  import java.util.Iterator;
43  
44  import org.apache.commons.logging.Log;
45  import org.apache.commons.logging.LogFactory;
46  import org.exolab.castor.types.AnyNode;
47  import org.exolab.castor.xml.Namespaces;
48  import org.exolab.castor.xml.Serializer;
49  import org.exolab.castor.xml.schema.Annotated;
50  import org.exolab.castor.xml.schema.Annotation;
51  import org.exolab.castor.xml.schema.AppInfo;
52  import org.exolab.castor.xml.schema.AttributeDecl;
53  import org.exolab.castor.xml.schema.AttributeGroup;
54  import org.exolab.castor.xml.schema.AttributeGroupDecl;
55  import org.exolab.castor.xml.schema.AttributeGroupReference;
56  import org.exolab.castor.xml.schema.BlockList;
57  import org.exolab.castor.xml.schema.ComplexType;
58  import org.exolab.castor.xml.schema.ContentModelGroup;
59  import org.exolab.castor.xml.schema.ContentType;
60  import org.exolab.castor.xml.schema.Documentation;
61  import org.exolab.castor.xml.schema.ElementDecl;
62  import org.exolab.castor.xml.schema.Facet;
63  import org.exolab.castor.xml.schema.FinalList;
64  import org.exolab.castor.xml.schema.Form;
65  import org.exolab.castor.xml.schema.Group;
66  import org.exolab.castor.xml.schema.IdentityConstraint;
67  import org.exolab.castor.xml.schema.IdentityField;
68  import org.exolab.castor.xml.schema.IdentitySelector;
69  import org.exolab.castor.xml.schema.KeyRef;
70  import org.exolab.castor.xml.schema.ModelGroup;
71  import org.exolab.castor.xml.schema.RedefineSchema;
72  import org.exolab.castor.xml.schema.Schema;
73  import org.exolab.castor.xml.schema.SchemaContext;
74  import org.exolab.castor.xml.schema.SchemaContextImpl;
75  import org.exolab.castor.xml.schema.SchemaNames;
76  import org.exolab.castor.xml.schema.SimpleContent;
77  import org.exolab.castor.xml.schema.SimpleType;
78  import org.exolab.castor.xml.schema.Structure;
79  import org.exolab.castor.xml.schema.Union;
80  import org.exolab.castor.xml.schema.Wildcard;
81  import org.exolab.castor.xml.schema.XMLType;
82  import org.exolab.castor.xml.schema.simpletypes.ListType;
83  import org.exolab.castor.xml.util.AnyNode2SAX;
84  import org.xml.sax.DocumentHandler;
85  import org.xml.sax.SAXException;
86  import org.xml.sax.helpers.AttributeListImpl;
87  
88  /**
89   * A class for serializing Schema models.
90   * 
91   * @author <a href="mailto:kvisco@intalio.com">Keith Visco</a>
92   * @version $Revision$ $Date: 2006-04-05 13:16:42 -0600 (Wed, 05 Apr 2006) $
93   **/
94  public class SchemaWriter {
95  
96    /**
97     * The {@link Log} instance to use.
98     */
99    private static final Log LOG = LogFactory.getLog(SchemaWriter.class);
100   // ------------------------/
101   // - Schema element names -/
102   // ------------------------/
103 
104   /**
105    * Annotation element name.
106    */
107   private static final String ANNOTATION = "annotation";
108 
109   /**
110    * AppInfo element name.
111    */
112   private static final String APPINFO = "appinfo";
113 
114   /**
115    * Attribute element name.
116    */
117   private static final String ATTRIBUTE = "attribute";
118 
119   /**
120    * AttributeGroup element name.
121    */
122   private static final String ATTRIBUTE_GROUP = "attributeGroup";
123 
124   /**
125    * ComplexType element name.
126    */
127   private static final String COMPLEX_TYPE = "complexType";
128 
129   /**
130    * Documentation element name.
131    */
132   private static final String DOCUMENTATION = "documentation";
133 
134   /**
135    * Element element name.
136    */
137   private static final String ELEMENT = "element";
138 
139   /**
140    * ModelGroup element name.
141    */
142   private static final String GROUP = "group";
143 
144   /**
145    * Restriction element name.
146    */
147   private static final String RESTRICTION = "restriction";
148 
149   /**
150    * Schema element name.
151    */
152   private static final String SCHEMA = "schema";
153 
154   /**
155    * SimpleType element name
156    */
157   private static final String SIMPLE_TYPE = "simpleType";
158 
159   // -------------------/
160   // - Attribute names -/
161   // -------------------/
162 
163   private static final String ATTR_NAME = "name";
164   private static final String ATTR_TYPE = "type";
165 
166   private static final String VALUE_TRUE = "true";
167 
168 
169   /**
170    * For use with SAX AttributeList
171    */
172   private static final String CDATA = "CDATA";
173   private static final String XMLNS_PREFIX = "xmlns:";
174   private static final String XMLNS_DEFAULT = "xmlns";
175   private static final String DEFAULT_PREFIX = "xsd";
176 
177   /**
178    * The DocumentHandler to send events to
179    */
180   private DocumentHandler _handler = null;
181 
182   /**
183    * The AttributeList to send events to
184    */
185   private AttributeListImpl _atts = new AttributeListImpl();
186 
187   /**
188    * This field is no longer used and only here for backward compatibility.
189    * 
190    * @deprecated
191    **/
192   public static boolean enable = false;
193 
194   /** Castor XML context - mother of all dwelling. */
195   private SchemaContext _schemaContext = null;
196 
197   /**
198    * Creates a new SchemaWriter for the given Writer.
199    *
200    * @param writer the Writer to serialize to
201    * @throws IOException in case taht wrapping the Writer fails
202    **/
203   public SchemaWriter(final Writer writer) throws IOException {
204     this();
205     Serializer serializer = _schemaContext.getSerializer();
206 
207     if (serializer == null) {
208       throw new IOException("Unable to obtain serailizer");
209     }
210 
211     serializer.setOutputCharStream(writer);
212 
213     DocumentHandler handler = serializer.asDocumentHandler();
214 
215     if (handler == null) {
216       String err = "The following serializer is not SAX capable: ";
217       err += serializer.getClass().getName();
218       err += "; cannot proceed.";
219       throw new IOException(err);
220     }
221 
222     _handler = handler;
223 
224   } // -- SchemaWriter
225 
226   /**
227    * Creates a new SchemaWriter for the given DocumentHandler.
228    *
229    * @param handler the DocumentHandler to send events to
230    **/
231   public SchemaWriter(final DocumentHandler handler) {
232     this();
233 
234     if (handler == null) {
235       throw new IllegalArgumentException("DocumentHandler must not be null.");
236     }
237 
238     _handler = handler;
239   } // -- SchemaWriter
240 
241   /**
242    * A constructor to create an empty uninitialized SchemaWriter via XMLContext.
243    */
244   public SchemaWriter() {
245     super();
246     _schemaContext = new SchemaContextImpl();
247   }
248 
249   /**
250    * To set the {@link SchemaContext} to be used for the {@link SchemaWriter}.
251    * 
252    * @param schemaContext the {@link SchemaContext} to be used
253    */
254   public void setSchemaContext(final SchemaContext schemaContext) {
255     _schemaContext = schemaContext;
256   }
257 
258   /**
259    * To set the DocumentHandler to a Writer - which is wrapped by a serializer.
260    * 
261    * @param writer the Writer to use for output
262    * @throws IOException in case the Writer cannot be used for DocumentHandler
263    */
264   public void setDocumentHandler(final Writer writer) throws IOException {
265     Serializer serializer = _schemaContext.getSerializer();
266 
267     if (serializer == null) {
268       String message = "Unable to obtain serailizer";
269       LOG.warn(message);
270       throw new IOException(message);
271     }
272 
273     serializer.setOutputCharStream(writer);
274 
275     DocumentHandler handler = serializer.asDocumentHandler();
276 
277     if (handler == null) {
278       String err = "The following serializer is not SAX capable: ";
279       err += serializer.getClass().getName();
280       err += "; cannot proceed.";
281       LOG.warn(err);
282       throw new IOException(err);
283     }
284 
285     _handler = handler;
286   }
287 
288   /**
289    * To directly set a DocumentHandler.
290    * 
291    * @param documentHandler set the DocumentHandler
292    */
293   public void setDocumentHandler(final DocumentHandler documentHandler) {
294     if (documentHandler == null) {
295       String message = "DocumentHandler must not be null.";
296       LOG.warn(message);
297       throw new IllegalArgumentException(message);
298     }
299     _handler = documentHandler;
300   }
301 
302   public void write(final Schema schema) throws SAXException {
303     if (schema == null)
304       throw new IllegalArgumentException("Schema must not be null.");
305 
306     processSchema(schema);
307 
308   } // -- write
309 
310 
311   /**
312    * Processes the given annotated structure into events
313    *
314    * @param annotated the annotated structure to process into events
315    **/
316   private void processAnnotated(Annotated annotated, String schemaPrefix) throws SAXException {
317     Enumeration enumeration = annotated.getAnnotations();
318     while (enumeration.hasMoreElements())
319       processAnnotation((Annotation) enumeration.nextElement(), schemaPrefix);
320 
321   } // -- processAnnotated
322 
323   /**
324    * Processes the given annotation into events
325    *
326    * @param annotation the annotation to process into events
327    * @param schemaPrefix the namespace prefix to use for schema elements
328    **/
329   private void processAnnotation(Annotation annotation, String schemaPrefix) throws SAXException {
330 
331     _atts.clear();
332 
333     String ELEM_ANNOTATION = schemaPrefix + ANNOTATION;
334 
335     _handler.startElement(ELEM_ANNOTATION, _atts);
336 
337 
338     // --process appinfo elements
339     Enumeration enumeration = annotation.getAppInfo();
340     String ELEM_APPINFO = schemaPrefix + APPINFO;
341     while (enumeration.hasMoreElements()) {
342       AppInfo app = (AppInfo) enumeration.nextElement();
343 
344       String source = app.getSource();
345       String sourceName = _atts.getName(0);
346       boolean isSourceIsNull = (sourceName == null);
347       boolean isSourceExists = false;
348 
349       if (!isSourceIsNull) {
350         isSourceExists = sourceName.equals(SchemaNames.SOURCE_ATTR);
351       }
352       if (source != null && !isSourceExists)
353         _atts.addAttribute(SchemaNames.SOURCE_ATTR, CDATA, source);
354 
355       _handler.startElement(ELEM_APPINFO, _atts);
356       Enumeration anyNodes = app.getObjects();
357       while (anyNodes.hasMoreElements()) {
358         Object obj = anyNodes.nextElement();
359         if (obj instanceof AnyNode) {
360           AnyNode2SAX anyNode2SAX = new AnyNode2SAX((AnyNode) obj);
361           anyNode2SAX.setDocumentHandler(_handler);
362           anyNode2SAX.start();
363         } else {
364           char[] chars = obj.toString().toCharArray();
365           _handler.characters(chars, 0, chars.length);
366 
367         }
368       }
369       _handler.endElement(ELEM_APPINFO);
370     }
371 
372     // -- process documentation elements
373     enumeration = annotation.getDocumentation();
374     String ELEM_DOCUMENTATION = schemaPrefix + DOCUMENTATION;
375     while (enumeration.hasMoreElements()) {
376       _atts.clear();
377       Documentation doc = (Documentation) enumeration.nextElement();
378       String source = doc.getSource();
379       String sourceName = _atts.getName(0);
380       boolean isSourceIsNull = (sourceName == null);
381       boolean isSourceExists = false;
382 
383       if (!isSourceIsNull) {
384         isSourceExists = sourceName.equals(SchemaNames.SOURCE_ATTR);
385       }
386       if (source != null && !isSourceExists) {
387         _atts.addAttribute(SchemaNames.SOURCE_ATTR, CDATA, source);
388       }
389 
390       _handler.startElement(ELEM_DOCUMENTATION, _atts);
391       Enumeration anyNodes = doc.getObjects();
392       while (anyNodes.hasMoreElements()) {
393         Object obj = anyNodes.nextElement();
394         if (obj instanceof AnyNode) {
395           AnyNode2SAX anyNode2SAX = new AnyNode2SAX((AnyNode) obj);
396           anyNode2SAX.setDocumentHandler(_handler);
397           anyNode2SAX.start();
398         } else {
399           char[] chars = obj.toString().toCharArray();
400           _handler.characters(chars, 0, chars.length);
401 
402         }
403       }
404       _handler.endElement(ELEM_DOCUMENTATION);
405     }
406 
407 
408     _handler.endElement(ELEM_ANNOTATION);
409 
410   } // -- processAnnotations
411 
412   /**
413    * Processes the given attribute declaration
414    *
415    * @param attribute the attribute declaration to process into events
416    * @param schemaPrefix the namespace prefix to use for schema elements
417    **/
418   private void processAttribute(AttributeDecl attribute, String schemaPrefix) throws SAXException {
419     String ELEM_ATTRIBUTE = schemaPrefix + ATTRIBUTE;
420 
421     _atts.clear();
422 
423     boolean isReference = attribute.isReference();
424 
425     // -- name
426     if (!isReference) {
427       _atts.addAttribute(SchemaNames.NAME_ATTR, CDATA, attribute.getName());
428     } else {
429       _atts.addAttribute(SchemaNames.REF_ATTR, CDATA, attribute.getReferenceName());
430     }
431 
432 
433     // -- type attribute
434     boolean hasAnonymousType = false;
435     SimpleType type = attribute.getSimpleType();
436     if ((!isReference) && (type != null)) {
437 
438       if (type.getName() != null) {
439 
440         String typeName = type.getName();
441 
442         // -- add prefix if necessary
443         if (typeName.indexOf(':') < 0) {
444           if (type.isBuiltInType()) {
445             typeName = schemaPrefix + typeName; // xsd prefix
446           } else {
447             // resolve prefix
448             String namespace = type.getSchema().getTargetNamespace();
449             if (namespace == null)
450               namespace = "";
451             String prefix = getNSPrefix(attribute.getSchema(), namespace);
452             if ((prefix != null) && (prefix.length() > 0))
453               typeName = prefix + ":" + typeName;
454           }
455         }
456         _atts.addAttribute(ATTR_TYPE, CDATA, typeName);
457       } else
458         hasAnonymousType = true;
459     }
460 
461     // default or fixed values?
462     // -- @default
463     if (attribute.isDefault()) {
464       _atts.addAttribute(SchemaNames.DEFAULT_ATTR, CDATA, attribute.getDefaultValue());
465     }
466     // -- @fixed
467     else if (attribute.isFixed()) {
468       _atts.addAttribute(SchemaNames.FIXED_ATTR, CDATA, attribute.getFixedValue());
469     }
470 
471     // -- @form
472     if (attribute.getForm() != null) {
473       _atts.addAttribute(SchemaNames.FORM, CDATA, attribute.getForm().toString());
474     }
475 
476     // -- @id (optional)
477     if (attribute.getId() != null) {
478       _atts.addAttribute(SchemaNames.ID_ATTR, CDATA, attribute.getId());
479     }
480 
481     // -- use : required
482     if (attribute.isRequired()) {
483       _atts.addAttribute(SchemaNames.USE_ATTR, CDATA, AttributeDecl.USE_REQUIRED);
484     }
485     // -- use : prohibited
486     else if (attribute.isProhibited()) {
487       _atts.addAttribute(SchemaNames.USE_ATTR, CDATA, AttributeDecl.USE_PROHIBITED);
488     }
489 
490     _handler.startElement(ELEM_ATTRIBUTE, _atts);
491 
492     // -- process annotations
493     processAnnotated(attribute, schemaPrefix);
494 
495     // -- process anonymous type if necessary
496     if (hasAnonymousType) {
497       processSimpleType(type, schemaPrefix);
498     }
499 
500     _handler.endElement(ELEM_ATTRIBUTE);
501 
502 
503   } // -- processAttribute
504 
505   /**
506    * Processes the given attributeGroup declaration
507    *
508    * @param attGroup the attributeGroup declaration to process into events
509    * @param schemaPrefix the namespace prefix to use for schema elements
510    **/
511   private void processAttributeGroup(AttributeGroup attGroup, String schemaPrefix)
512       throws SAXException {
513     String ELEM_ATTRIBUTE_GROUP = schemaPrefix + ATTRIBUTE_GROUP;
514 
515     _atts.clear();
516 
517     boolean isReference = (attGroup instanceof AttributeGroupReference);
518 
519     // -- name
520     if (!isReference) {
521       _atts.addAttribute(SchemaNames.NAME_ATTR, CDATA, ((AttributeGroupDecl) attGroup).getName());
522     } else {
523       _atts.addAttribute(SchemaNames.REF_ATTR, CDATA,
524           ((AttributeGroupReference) attGroup).getReference());
525     }
526 
527     // -- @id (optional)
528     if (attGroup.getId() != null) {
529       _atts.addAttribute(SchemaNames.ID_ATTR, CDATA, attGroup.getId());
530     }
531 
532     _handler.startElement(ELEM_ATTRIBUTE_GROUP, _atts);
533 
534     // -- process annotations
535     processAnnotated(attGroup, schemaPrefix);
536 
537     if (!isReference) {
538       AttributeGroupDecl group = (AttributeGroupDecl) attGroup;
539       Enumeration enumeration = group.getLocalAttributes();
540       while (enumeration.hasMoreElements()) {
541         processAttribute((AttributeDecl) enumeration.nextElement(), schemaPrefix);
542       }
543       enumeration = group.getLocalAttributeGroupReferences();
544       while (enumeration.hasMoreElements()) {
545         processAttributeGroup((AttributeGroup) enumeration.nextElement(), schemaPrefix);
546       }
547 
548       if (group.getAnyAttribute() != null) {
549         processWildcard(group.getAnyAttribute(), schemaPrefix);
550       }
551     }
552 
553     _handler.endElement(ELEM_ATTRIBUTE_GROUP);
554 
555 
556   } // -- processAttributeGroup
557 
558   /**
559    * Processes the given complex type definition
560    *
561    * @param complexType the complex type definition to process into events
562    * @param schemaPrefix the namespace prefix to use for schema elements
563    **/
564   private void processComplexType(ComplexType complexType, String schemaPrefix)
565       throws SAXException {
566     String ELEMENT_NAME = schemaPrefix + COMPLEX_TYPE;
567 
568     _atts.clear();
569 
570     // -- handle top-level only attributes
571     if (complexType.isTopLevel()) {
572 
573       // -- @name
574       _atts.addAttribute(SchemaNames.NAME_ATTR, CDATA, complexType.getName());
575 
576       // -- @abstract
577       if (complexType.isAbstract()) {
578         _atts.addAttribute(SchemaNames.ABSTRACT, CDATA, VALUE_TRUE);
579       }
580 
581       // -- @block
582       if (complexType.getBlock() != null) {
583         _atts.addAttribute(SchemaNames.BLOCK_ATTR, CDATA, complexType.getBlock().toString());
584       }
585 
586       // -- @final
587       if (complexType.getFinal() != null) {
588         _atts.addAttribute(SchemaNames.FINAL_ATTR, CDATA, complexType.getFinal().toString());
589       }
590     } // -- isTopLevel
591 
592     // -- @id
593     if (complexType.getId() != null) {
594       _atts.addAttribute(SchemaNames.ID_ATTR, CDATA, complexType.getId());
595     }
596 
597     // -- @mixed
598     if (complexType.getContentType() == ContentType.mixed) {
599       _atts.addAttribute(SchemaNames.MIXED, CDATA, VALUE_TRUE);
600     }
601 
602     _handler.startElement(ELEMENT_NAME, _atts);
603 
604     // -- process annotations
605     processAnnotated(complexType, schemaPrefix);
606 
607 
608     // -- handle simpleContent/complexContent if we have a baseType.
609     String ELEM_CONTENT = null;
610     String ELEM_DERIVATION = null;
611     XMLType baseType = complexType.getBaseType();
612     if (baseType != null) {
613       if (complexType.isSimpleContent())
614         ELEM_CONTENT = schemaPrefix + SchemaNames.SIMPLE_CONTENT;
615       else
616         ELEM_CONTENT = schemaPrefix + SchemaNames.COMPLEX_CONTENT;
617 
618       _atts.clear();
619       if (complexType.isComplexContent()) {
620         if (complexType.getContentType() == ContentType.mixed) {
621           _atts.addAttribute(SchemaNames.MIXED, CDATA, VALUE_TRUE);
622         }
623 
624       }
625       _handler.startElement(ELEM_CONTENT, _atts);
626 
627       ELEM_DERIVATION = schemaPrefix + complexType.getDerivationMethod();
628 
629       String baseTypeName = baseType.getName();
630 
631       // -- add "xsd" prefix if necessary
632       if (complexType.isSimpleContent()) {
633         // the base type can be a complexType in extension
634         if (baseType.isSimpleType()) {
635           SimpleType simpleType = (SimpleType) baseType;
636           if (baseTypeName.indexOf(':') < 0) {
637             if (simpleType.isBuiltInType()) {
638               baseTypeName = schemaPrefix + baseTypeName;
639             } else {
640               String targetNamespace = simpleType.getSchema().getTargetNamespace();
641               String prefix = getNSPrefix(complexType.getSchema(), targetNamespace);
642               if ((prefix != null) && (prefix.length() > 0)) {
643                 baseTypeName = prefix + ":" + baseTypeName;
644               }
645             }
646           }
647         }
648       } else if (complexType.isComplexContent()) {
649         // --complexType: add 'xsd' only for anyType
650         if (baseType.isAnyType()) {
651           if (baseTypeName.indexOf(':') < 0) {
652             baseTypeName = schemaPrefix + baseTypeName;
653           }
654 
655         }
656       } // --end of 'xsd' appending
657       // add the targetNamespace prefix if necessary
658       if (baseType.isComplexType()) {
659         String targetNamespace = baseType.getSchema().getTargetNamespace();
660         // -- targetNamespace is null
661         if (targetNamespace == null) {
662           if (complexType.isRedefined()) {
663             targetNamespace = complexType.getSchema().getTargetNamespace();
664           }
665         }
666 
667         else {
668           String nsPrefix = getNSPrefix(complexType.getSchema(), targetNamespace);
669           if ((nsPrefix != null) && (nsPrefix.length() != 0))
670             baseTypeName = nsPrefix + ':' + baseTypeName;
671           targetNamespace = null;
672           nsPrefix = null;
673         }
674 
675       }
676       _atts.clear();
677       _atts.addAttribute(SchemaNames.BASE_ATTR, CDATA, baseTypeName);
678       _handler.startElement(ELEM_DERIVATION, _atts);
679       // --Any Facets to process?
680       // --only relevant for the simpleContent with restriction
681       if (complexType.isSimpleContent() && complexType.isRestricted()) {
682         if (complexType.getContentType().getType() == ContentType.SIMPLE) {
683           SimpleContent simpleContent = (SimpleContent) complexType.getContentType();
684           SimpleType simpleType = simpleContent.getSimpleType();
685           // -- process facets
686           Enumeration enumeration = simpleType.getLocalFacets();
687           while (enumeration.hasMoreElements()) {
688             Facet facet = (Facet) enumeration.nextElement();
689             _atts.clear();
690             _atts.addAttribute(SchemaNames.VALUE_ATTR, CDATA, facet.getValue());
691             String facetName = schemaPrefix + facet.getName();
692             _handler.startElement(facetName, _atts);
693             Enumeration annotations = facet.getAnnotations();
694             while (annotations.hasMoreElements()) {
695               Annotation annotation = (Annotation) annotations.nextElement();
696               processAnnotation(annotation, schemaPrefix);
697             }
698             _handler.endElement(facetName);
699           } // --facets
700           enumeration = null;
701           simpleType = null;
702         }
703       } // --<simpleContent><restriction>
704 
705     }
706 
707     // -- process content model group
708     processContentModelGroup(complexType, schemaPrefix);
709 
710     // -- process Attributes, must appear last in a complex type
711     Enumeration enumeration = complexType.getLocalAttributeDecls();
712     while (enumeration.hasMoreElements()) {
713       processAttribute((AttributeDecl) enumeration.nextElement(), schemaPrefix);
714     }
715     enumeration = complexType.getAttributeGroupReferences();
716     while (enumeration.hasMoreElements()) {
717       processAttributeGroup((AttributeGroup) enumeration.nextElement(), schemaPrefix);
718     }
719 
720     if (baseType != null) {
721       _handler.endElement(ELEM_DERIVATION);
722       _handler.endElement(ELEM_CONTENT);
723     }
724 
725     if (complexType.getAnyAttribute() != null) {
726       processWildcard(complexType.getAnyAttribute(), schemaPrefix);
727     }
728 
729     _handler.endElement(ELEMENT_NAME);
730 
731   } // -- processComplexType
732 
733   /**
734    * Processes the given ContentModelGroup
735    *
736    * @param contentModel the content model group to process into events
737    * @param schemaPrefix the namespace prefix to use for schema elements
738    **/
739   private void processContentModelGroup(ContentModelGroup contentModel, String schemaPrefix)
740       throws SAXException {
741     Enumeration enumeration = contentModel.enumerate();
742     while (enumeration.hasMoreElements()) {
743       Structure structure = (Structure) enumeration.nextElement();
744       switch (structure.getStructureType()) {
745         case Structure.ELEMENT:
746           processElement((ElementDecl) structure, schemaPrefix);
747           break;
748         case Structure.MODELGROUP:
749         case Structure.GROUP:
750           processGroup((Group) structure, schemaPrefix);
751           break;
752         case Structure.WILDCARD:
753           processWildcard((Wildcard) structure, schemaPrefix);
754           break;
755         default:
756           break;
757       }
758     }
759   } // -- contentModel
760 
761   /**
762    * Processes the given element declaration
763    *
764    * @param element the element declaration to process into events
765    **/
766   private void processElement(ElementDecl element, String schemaPrefix) throws SAXException {
767     String ELEMENT_NAME = schemaPrefix + ELEMENT;
768 
769     _atts.clear();
770 
771 
772     // -- name or reference
773     String value = element.getName();
774     if (value != null) {
775       if (element.isReference()) {
776         String targetNamespace = element.getReference().getSchema().getTargetNamespace();
777         String nsPrefix = getNSPrefix(element.getSchema(), targetNamespace);
778         if ((nsPrefix != null) && (nsPrefix.length() != 0))
779           value = nsPrefix + ':' + value;
780         targetNamespace = null;
781         nsPrefix = null;
782         _atts.addAttribute(SchemaNames.REF_ATTR, CDATA, value);
783 
784       } else
785         _atts.addAttribute(ATTR_NAME, CDATA, value);
786     }
787 
788     // -- minOccurs/maxOccurs
789     int max = element.getMaxOccurs();
790     int min = element.getMinOccurs();
791 
792     if (min != 1) {
793       _atts.addAttribute(SchemaNames.MIN_OCCURS_ATTR, CDATA, Integer.toString(min));
794     }
795 
796     if (max < 0) {
797       _atts.addAttribute(SchemaNames.MAX_OCCURS_ATTR, CDATA, "unbounded");
798     } else if (max != 1) {
799       _atts.addAttribute(SchemaNames.MAX_OCCURS_ATTR, CDATA, Integer.toString(max));
800     }
801 
802     // -- type attribute
803     boolean hasAnonymousType = false;
804     if (!element.isReference()) {
805       XMLType type = element.getType();
806 
807       // -- no type?
808       if (type == null) {
809         // -- do nothing
810       }
811       // -- anonymous (in-lined) type
812       else if (type.getName() == null) {
813         hasAnonymousType = true;
814       }
815       // -- built-in simpleType
816       else if (type.isSimpleType() && ((SimpleType) type).isBuiltInType()) {
817         _atts.addAttribute(ATTR_TYPE, CDATA, schemaPrefix + type.getName());
818       } else if (type.getStructureType() == Structure.ANYTYPE) {
819         _atts.addAttribute(ATTR_TYPE, CDATA, schemaPrefix + type.getName());
820       }
821       // -- type imported from another schema
822       else if (isImportedType(type, element)) {
823         String namespace = type.getSchema().getTargetNamespace();
824         String prefix = getNSPrefix(element.getSchema(), namespace);
825         if (prefix == null) {
826           // -- declare a temporary prefix
827           prefix = schemaPrefix + '2';
828           _atts.addAttribute("xmlns:" + prefix, CDATA, namespace);
829         }
830         _atts.addAttribute(ATTR_TYPE, CDATA, prefix + ':' + type.getName());
831         // -- otherwise...user defined type.
832       } else {
833         String typeName = type.getName();
834         // add the targetNamespace prefix if necessary
835         String targetNamespace = element.getSchema().getTargetNamespace();
836         if (targetNamespace != null) {
837           String nsPrefix = getNSPrefix(element.getSchema(), targetNamespace);
838           if ((nsPrefix != null) && (nsPrefix.length() != 0))
839             typeName = nsPrefix + ':' + typeName;
840           targetNamespace = null;
841           nsPrefix = null;
842         }
843 
844         _atts.addAttribute(ATTR_TYPE, CDATA, typeName);
845       }
846     }
847 
848     // add various attributes if we are looking at a local element definition; iow,
849     // for an element reference, this values should be specified on the
850     // referenced (global) element definition only.
851     if (!element.isReference()) {
852 
853       // -- @abstract
854       if (element.isAbstract()) {
855         _atts.addAttribute(SchemaNames.ABSTRACT, CDATA, VALUE_TRUE);
856       }
857 
858       // -- @block
859       if (element.getBlock() != null) {
860         _atts.addAttribute(SchemaNames.BLOCK_ATTR, CDATA, element.getBlock().toString());
861       }
862 
863       // -- @default
864       String defaultValue = element.getDefaultValue();
865       if (defaultValue != null) {
866         _atts.addAttribute(SchemaNames.DEFAULT_ATTR, CDATA, defaultValue);
867       }
868 
869       // -- @fixed
870       String fixedValue = element.getFixedValue();
871       if (fixedValue != null) {
872         _atts.addAttribute(SchemaNames.FIXED_ATTR, CDATA, fixedValue);
873       }
874 
875       // -- @final
876       FinalList finalValue = element.getFinal();
877       if (finalValue != null) {
878         _atts.addAttribute(SchemaNames.FINAL_ATTR, CDATA, finalValue.toString());
879       }
880 
881       // -- @substitutionGroup
882       String substitutionGroup = element.getSubstitutionGroup();
883       if (substitutionGroup != null) {
884         _atts.addAttribute(SchemaNames.SUBSTITUTION_GROUP_ATTR, CDATA, substitutionGroup);
885       }
886     }
887 
888     // -- @form
889     Form form = element.getForm();
890     if (form != null) {
891       _atts.addAttribute(SchemaNames.FORM, CDATA, form.toString());
892     }
893 
894     // -- @id
895     String id = element.getId();
896     if (id != null) {
897       _atts.addAttribute(SchemaNames.ID_ATTR, CDATA, id);
898     }
899 
900     // -- @nillable
901     if (element.isNillable()) {
902       _atts.addAttribute(SchemaNames.NILLABLE_ATTR, CDATA, VALUE_TRUE);
903     }
904 
905 
906     _handler.startElement(ELEMENT_NAME, _atts);
907 
908     // -- process annotations
909     processAnnotated(element, schemaPrefix);
910 
911     // -- process anonymous type if necessary
912     if (hasAnonymousType) {
913       XMLType type = element.getType();
914       if (type.isComplexType())
915         processComplexType((ComplexType) type, schemaPrefix);
916       else if (type.isSimpleType())
917         processSimpleType((SimpleType) type, schemaPrefix);
918     }
919 
920     // -- process any identity-constraints
921     Enumeration enumeration = element.getIdentityConstraints();
922     while (enumeration.hasMoreElements()) {
923       processIdentityConstraint((IdentityConstraint) enumeration.nextElement(), schemaPrefix);
924     }
925 
926     _handler.endElement(ELEMENT_NAME);
927 
928   } // -- processElement
929 
930   /**
931    * Processes the given group definition into SAX events
932    *
933    * @param group the group definition to process into SAX events
934    * @param schemaPrefix the namespace prefix to use for schema elements
935    **/
936   private void processGroup(Group group, String schemaPrefix) throws SAXException {
937     String ELEMENT_NAME = schemaPrefix;
938 
939     // -- ModelGroup
940     String reference = null;
941     if (group instanceof ModelGroup) {
942       ELEMENT_NAME += GROUP;
943       ModelGroup mGroup = (ModelGroup) group;
944       if (mGroup.hasReference()) {
945         ModelGroup refGroup = mGroup.getReference();
946         if (refGroup != null) {
947           reference = refGroup.getName();
948           // -- prefix
949           String namespace = refGroup.getSchema().getTargetNamespace();
950           if (namespace == null)
951             namespace = "";
952           String prefix = getNSPrefix(mGroup.getSchema(), namespace);
953           if ((prefix != null) && (prefix.length() > 0))
954             reference = prefix + ':' + reference;
955 
956         }
957       }
958     }
959     // -- Group
960     else {
961       ELEMENT_NAME += group.getOrder().toString();
962     }
963 
964     _atts.clear();
965 
966     // -- @id
967     if (group.getId() != null) {
968       _atts.addAttribute(SchemaNames.ID_ATTR, CDATA, group.getId());
969     }
970 
971     // -- reference
972     if (reference != null) {
973       _atts.addAttribute("ref", CDATA, reference);
974     } else if (group.getName() != null) {
975       _atts.addAttribute(ATTR_NAME, CDATA, group.getName());
976     }
977 
978     // -- minOccurs/maxOccurs
979     int max = group.getMaxOccurs();
980     int min = group.getMinOccurs();
981 
982     if (min != 1) {
983       _atts.addAttribute(SchemaNames.MIN_OCCURS_ATTR, CDATA, Integer.toString(min));
984     }
985 
986     if (max < 0) {
987       _atts.addAttribute(SchemaNames.MAX_OCCURS_ATTR, CDATA, "unbounded");
988     } else if (max != 1) {
989       _atts.addAttribute(SchemaNames.MAX_OCCURS_ATTR, CDATA, Integer.toString(max));
990     }
991 
992 
993     _handler.startElement(ELEMENT_NAME, _atts);
994 
995     // -- process annotations
996     processAnnotated(group, schemaPrefix);
997 
998     // -- process content model
999     if (reference == null) {
1000       processContentModelGroup(group, schemaPrefix);
1001     }
1002 
1003     _handler.endElement(ELEMENT_NAME);
1004 
1005   } // -- processGroup
1006 
1007   /**
1008    * Processes the given IdentityConstraint
1009    *
1010    * @param constraint the IdentityConstraint to process
1011    **/
1012   private void processIdentityConstraint(IdentityConstraint constraint, String schemaPrefix)
1013       throws SAXException {
1014 
1015     if (constraint == null)
1016       return;
1017 
1018     String ELEMENT_NAME = schemaPrefix;
1019 
1020     String id = null;
1021     String refer = null;
1022 
1023     switch (constraint.getStructureType()) {
1024       case Structure.KEYREF:
1025         ELEMENT_NAME += SchemaNames.KEYREF;
1026         refer = ((KeyRef) constraint).getRefer();
1027         break;
1028       case Structure.UNIQUE:
1029         ELEMENT_NAME += SchemaNames.UNIQUE;
1030         break;
1031       default:
1032         ELEMENT_NAME += SchemaNames.KEY;
1033         break;
1034     }
1035 
1036     id = constraint.getId();
1037 
1038     _atts.clear();
1039 
1040     // -- name
1041     _atts.addAttribute(SchemaNames.NAME_ATTR, CDATA, constraint.getName());
1042 
1043     // -- id
1044     if (id != null) {
1045       _atts.addAttribute(SchemaNames.ID_ATTR, CDATA, id);
1046     }
1047 
1048     // -- refer
1049     if (refer != null) {
1050       _atts.addAttribute(SchemaNames.REFER_ATTR, CDATA, refer);
1051     }
1052 
1053     _handler.startElement(ELEMENT_NAME, _atts);
1054 
1055     // -- process annotations
1056     processAnnotated(constraint, schemaPrefix);
1057 
1058     // -- process selector
1059     String ELEM_SELECTOR = schemaPrefix + SchemaNames.SELECTOR;
1060     String xpath = null;
1061 
1062     IdentitySelector selector = constraint.getSelector();
1063     xpath = selector.getXPath();
1064     id = selector.getId();
1065     _atts.clear();
1066     _atts.addAttribute(SchemaNames.XPATH_ATTR, CDATA, xpath);
1067     if (id != null) {
1068       _atts.addAttribute(SchemaNames.ID_ATTR, CDATA, id);
1069     }
1070     _handler.startElement(ELEM_SELECTOR, _atts);
1071     processAnnotated(selector, schemaPrefix);
1072     _handler.endElement(ELEM_SELECTOR);
1073 
1074     // -- process field(s)
1075     String ELEM_FIELD = schemaPrefix + SchemaNames.FIELD;
1076     Enumeration enumeration = constraint.getFields();
1077     while (enumeration.hasMoreElements()) {
1078       IdentityField field = (IdentityField) enumeration.nextElement();
1079       _atts.clear();
1080       id = field.getId();
1081       xpath = field.getXPath();
1082       _atts.addAttribute(SchemaNames.XPATH_ATTR, CDATA, xpath);
1083       if (id != null) {
1084         _atts.addAttribute(SchemaNames.ID_ATTR, CDATA, id);
1085       }
1086       _handler.startElement(ELEM_FIELD, _atts);
1087       processAnnotated(field, schemaPrefix);
1088       _handler.endElement(ELEM_FIELD);
1089     }
1090     _handler.endElement(ELEMENT_NAME);
1091 
1092   } // -- processIdentityConstraint
1093 
1094   private void processSchema(Schema schema) throws SAXException {
1095     // -- calculate schema prefix
1096     String schemaPrefix = getNSPrefix(schema, schema.getSchemaNamespace());
1097     if (schemaPrefix == null) {
1098       schemaPrefix = DEFAULT_PREFIX;
1099     }
1100 
1101     // -- namespace declaration for xsd
1102     _atts.clear();
1103     if (schemaPrefix.length() == 0) {
1104       // -- declared as default namespace
1105       _atts.addAttribute(XMLNS_DEFAULT, CDATA, schema.getSchemaNamespace());
1106     } else {
1107       // -- declare namespace + prefix
1108       _atts.addAttribute(XMLNS_PREFIX + schemaPrefix, CDATA, schema.getSchemaNamespace());
1109     }
1110 
1111 
1112 
1113     // -- namespace declarations
1114     Namespaces namespaces = schema.getNamespaces();
1115     Enumeration keys = namespaces.getLocalNamespacePrefixes();
1116     while (keys.hasMoreElements()) {
1117       String nsPrefix = (String) keys.nextElement();
1118       if (!nsPrefix.equals(schemaPrefix)) {
1119         String ns = namespaces.getNamespaceURI(nsPrefix);
1120         if (nsPrefix.length() > 0) {
1121           _atts.addAttribute(XMLNS_PREFIX + nsPrefix, CDATA, ns);
1122         } else {
1123           _atts.addAttribute(XMLNS_DEFAULT, CDATA, ns);
1124         }
1125       }
1126     }
1127 
1128     // -- targetNS
1129     String value = schema.getTargetNamespace();
1130     if (value != null)
1131       _atts.addAttribute(SchemaNames.TARGET_NS_ATTR, CDATA, value);
1132 
1133     // -- attributeFormDefault
1134     Form form = schema.getAttributeFormDefault();
1135     if (form != null) {
1136       _atts.addAttribute(SchemaNames.ATTR_FORM_DEFAULT_ATTR, CDATA, form.toString());
1137     }
1138     // -- elementFormDefault
1139     form = schema.getElementFormDefault();
1140     if (form != null) {
1141       _atts.addAttribute(SchemaNames.ELEM_FORM_DEFAULT_ATTR, CDATA, form.toString());
1142     }
1143 
1144     // -- blockDefault
1145     BlockList blockList = schema.getBlockDefault();
1146     if (blockList != null) {
1147       _atts.addAttribute(SchemaNames.BLOCK_DEFAULT_ATTR, CDATA, blockList.toString());
1148     }
1149 
1150     // -- finalDefault
1151     FinalList finalList = schema.getFinalDefault();
1152     if (finalList != null) {
1153       _atts.addAttribute(SchemaNames.FINAL_DEFAULT_ATTR, CDATA, finalList.toString());
1154     }
1155 
1156     // --@version
1157     if (schema.getVersion() != null) {
1158       _atts.addAttribute(SchemaNames.VERSION_ATTR, CDATA, schema.getVersion());
1159     }
1160 
1161 
1162     // -- modify schemaPrefix to include ':'
1163     if (schemaPrefix.length() > 0) {
1164       schemaPrefix += ':';
1165     }
1166 
1167     _handler.startDocument();
1168 
1169     String ELEM_SCHEMA = schemaPrefix + SCHEMA;
1170 
1171     _handler.startElement(ELEM_SCHEMA, _atts);
1172 
1173     // -- process annotations
1174     processAnnotated(schema, schemaPrefix);
1175 
1176     // -- process all imported schemas
1177     Collection<Schema> importedSchemas = schema.getImportedSchema();
1178     for (Schema importedSchema : importedSchemas) {
1179       processImport(importedSchema, schemaPrefix);
1180     }
1181 
1182     // -- process all cached included schemas
1183     Collection<Schema> enumeration = schema.getCachedIncludedSchemas();
1184     for (Schema includedSchema : enumeration) {
1185       processIncludedSchema(includedSchema, schemaPrefix);
1186     }
1187 
1188     // -- process all redefinitions
1189     Collection<RedefineSchema> redefinedSchemas = schema.getRedefineSchema();
1190     for (RedefineSchema redefinedSchema : redefinedSchemas) {
1191       processRedefinition(redefinedSchema, schema, schemaPrefix);
1192     }
1193 
1194     // -- process all top level attributeGroup declarations
1195     Iterator<AttributeGroup> attributeGroups = schema.getAttributeGroups().iterator();
1196     while (attributeGroups.hasNext()) {
1197       boolean found = false;
1198       AttributeGroup temp = (AttributeGroup) attributeGroups.next();
1199       // -- check if this attributeGroup is not
1200       // -- part of a redefinition
1201       if (temp instanceof AttributeGroupDecl) {
1202         if (((AttributeGroupDecl) temp).isRedefined()) {
1203           found = true;
1204         }
1205       }
1206 
1207       // --check if this attributeGroup is not already included
1208       Collection<Schema> includedSchemas = schema.getCachedIncludedSchemas();
1209       for (Schema includedSchema : includedSchemas) {
1210         if (temp instanceof AttributeGroupDecl) {
1211           String name = ((AttributeGroupDecl) temp).getName();
1212           found = (includedSchema.getAttributeGroup(name) != null);
1213         }
1214       }
1215 
1216       if (!found) {
1217         processAttributeGroup(temp, schemaPrefix);
1218       }
1219     }
1220 
1221     // -- process all top level attribute declarations
1222     Collection<AttributeDecl> attributeDeclarations = schema.getAttributes();
1223     for (AttributeDecl attribute : attributeDeclarations) {
1224       boolean alreadyIncluded = false;
1225       // --check if this attribute is not already included
1226       Iterator<Schema> includedSchemas = schema.getCachedIncludedSchemas().iterator();
1227       while (includedSchemas.hasNext()) {
1228         Schema tempSchema = includedSchemas.next();
1229         // TODO[Java 5.0]: check whether algorithm is wrong !!!
1230         alreadyIncluded = (tempSchema.getAttribute(attribute.getName()) != null);
1231       }
1232 
1233       if (!alreadyIncluded) {
1234         processAttribute(attribute, schemaPrefix);
1235       }
1236     }
1237 
1238     // -- process all top level element declarations
1239     Collection<ElementDecl> elementDeclarations = schema.getElementDecls();
1240     for (ElementDecl element : elementDeclarations) {
1241       boolean alreadyIncluded = false;
1242       // --check if this element is not already included
1243       Iterator<Schema> includedSchemas = schema.getCachedIncludedSchemas().iterator();
1244       while (includedSchemas.hasNext()) {
1245         Schema tempSchema = includedSchemas.next();
1246         // TODO[Java 5.0]: check whether algorithm is wrong !!!
1247         alreadyIncluded = (tempSchema.getElementDecl(element.getName()) != null);
1248       }
1249 
1250       if (!alreadyIncluded) {
1251         processElement(element, schemaPrefix);
1252       }
1253     }
1254 
1255     // -- process all top level complex types
1256     Collection<ComplexType> complexTypes = schema.getComplexTypes();
1257     for (ComplexType complexType : complexTypes) {
1258       boolean alreadyIncluded = false;
1259       // --check if this complex type is not already included
1260       Iterator<Schema> includedSchemas = schema.getCachedIncludedSchemas().iterator();
1261       while (includedSchemas.hasNext()) {
1262         Schema tempSchema = includedSchemas.next();
1263         // TODO[Java 5.0]: check whether algorithm is wrong !!!
1264         alreadyIncluded = (tempSchema.getComplexType(complexType.getName()) != null);
1265       }
1266       if (!complexType.isRedefined() && !alreadyIncluded) {
1267         processComplexType(complexType, schemaPrefix);
1268       }
1269     }
1270 
1271     // -- process all top level groups
1272     Collection<ModelGroup> modelGroups = schema.getModelGroups();
1273     for (ModelGroup modelGroup : modelGroups) {
1274       boolean alreadyIncluded = false;
1275       // --check if this Group is not already included
1276       Iterator<Schema> includedSchemas = schema.getCachedIncludedSchemas().iterator();
1277       while (includedSchemas.hasNext()) {
1278         Schema tempSchema = includedSchemas.next();
1279         // TODO[Java 5.0]: check whether algorithm is wrong !!!
1280         alreadyIncluded = (tempSchema.getModelGroup(modelGroup.getName()) != null);
1281       }
1282 
1283       if (!modelGroup.isRedefined() && !alreadyIncluded) {
1284         processGroup(modelGroup, schemaPrefix);
1285       }
1286     }
1287 
1288     // -- process all top level simple types
1289     Collection<SimpleType> simpleTypes = schema.getSimpleTypes();
1290     for (SimpleType simpleType : simpleTypes) {
1291       boolean found = false;
1292       // --check if this attributeGroup is not
1293       // -- included
1294       Iterator<Schema> includedSchemas = schema.getCachedIncludedSchemas().iterator();
1295       while (includedSchemas.hasNext()) {
1296         Schema tempSchema = includedSchemas.next();
1297         found = (tempSchema.getSimpleType(simpleType.getName()) != null);
1298       }
1299       if (!simpleType.isRedefined() && !found) {
1300         processSimpleType(simpleType, schemaPrefix);
1301       }
1302     }
1303 
1304     _handler.endElement(ELEM_SCHEMA);
1305 
1306     _handler.endDocument();
1307 
1308   } // -- processSchema
1309 
1310   /**
1311    * Process a Wildcard (xsd:any) component
1312    *
1313    * @param wildcard the Wildcard to process
1314    * @param schemaPrefix the namespace prefix to use for schema elements
1315    */
1316   private void processWildcard(Wildcard wildcard, String schemaPrefix) throws SAXException {
1317 
1318     String ELEMENT_NAME = null;
1319     if (wildcard.isAttributeWildcard())
1320       ELEMENT_NAME = schemaPrefix + SchemaNames.ANY_ATTRIBUTE;
1321     else
1322       ELEMENT_NAME = schemaPrefix + SchemaNames.ANY;
1323 
1324     _atts.clear();
1325 
1326     // -- @namespace
1327     StringBuffer namespace = new StringBuffer();
1328     Enumeration enumeration = wildcard.getNamespaces();
1329     while (enumeration.hasMoreElements()) {
1330       if (namespace.length() > 0)
1331         namespace.append(' ');
1332       namespace.append(enumeration.nextElement().toString());
1333     }
1334     if (namespace.length() > 0) {
1335       _atts.addAttribute(SchemaNames.NAMESPACE, CDATA, namespace.toString());
1336     }
1337 
1338     // -- minOccurs/maxOccurs
1339     int max = wildcard.getMaxOccurs();
1340     int min = wildcard.getMinOccurs();
1341 
1342     if (min != 1) {
1343       _atts.addAttribute(SchemaNames.MIN_OCCURS_ATTR, CDATA, Integer.toString(min));
1344     }
1345 
1346     if (max < 0) {
1347       _atts.addAttribute(SchemaNames.MAX_OCCURS_ATTR, CDATA, "unbounded");
1348     } else if (max != 1) {
1349       _atts.addAttribute(SchemaNames.MAX_OCCURS_ATTR, CDATA, Integer.toString(max));
1350     }
1351 
1352     // -- @processContents
1353     String value = wildcard.getProcessContent();
1354     if (value != null) {
1355       _atts.addAttribute(SchemaNames.PROCESS_CONTENTS, CDATA, value);
1356     }
1357     _handler.startElement(ELEMENT_NAME, _atts);
1358     processAnnotated(wildcard, schemaPrefix);
1359     _handler.endElement(ELEMENT_NAME);
1360 
1361   } // -- processWildcard
1362 
1363   /**
1364    * Process an imported schema
1365    *
1366    * @param schema the imported Schema to process
1367    * @param schemaPrefix the namespace prefix to use for schema elements
1368    **/
1369   private void processImport(Schema schema, String schemaPrefix) throws SAXException {
1370     String ELEMENT_NAME = schemaPrefix + SchemaNames.IMPORT;
1371     _atts.clear();
1372 
1373     String namespace = schema.getTargetNamespace();
1374     String schemaLoc = schema.getSchemaLocation();
1375 
1376     _atts.addAttribute("namespace", null, namespace);
1377     _atts.addAttribute("schemaLocation", null, schemaLoc);
1378     _handler.startElement(ELEMENT_NAME, _atts);
1379     _handler.endElement(ELEMENT_NAME);
1380   } // -- processImport
1381 
1382   /**
1383    * Process an included schema
1384    *
1385    * @param schema the imported Schema to process
1386    * @param schemaPrefix the namespace prefix to use for schema elements
1387    **/
1388   private void processIncludedSchema(Schema schema, String schemaPrefix) throws SAXException {
1389     String ELEMENT_NAME = schemaPrefix + SchemaNames.INCLUDE;
1390     _atts.clear();
1391 
1392     String schemaLoc = schema.getSchemaLocation();
1393 
1394     _atts.addAttribute("schemaLocation", null, schemaLoc);
1395     _handler.startElement(ELEMENT_NAME, _atts);
1396     _handler.endElement(ELEMENT_NAME);
1397   } // -- processImport
1398 
1399   /**
1400    * Process a set of redefinitions
1401    *
1402    * @param schema the redefined Schema to process
1403    * @param schemaPrefix the namespace prefix to use for schema elements
1404    **/
1405   private void processRedefinition(RedefineSchema schema, Schema parentSchema, String schemaPrefix)
1406       throws SAXException {
1407     String ELEMENT_NAME = schemaPrefix + SchemaNames.REDEFINE;
1408     _atts.clear();
1409 
1410     String schemaLoc = schema.getSchemaLocation();
1411     if (schemaLoc != "") {
1412       _atts.addAttribute("schemaLocation", null, schemaLoc);
1413     }
1414 
1415     _handler.startElement(ELEMENT_NAME, _atts);
1416 
1417     // -- process annotations
1418     processAnnotated(schema, schemaPrefix);
1419 
1420     if (schemaLoc != "") {
1421       // --process complexTypes
1422       for (ComplexType complexType : schema.enumerateComplexTypes()) {
1423         processComplexType(complexType, schemaPrefix);
1424       }
1425       // --process simpleTypes
1426       for (SimpleType simpleType : schema.enumerateSimpleTypes()) {
1427         processSimpleType(simpleType, schemaPrefix);
1428       }
1429       // --process groups
1430       for (ModelGroup modelGroup : schema.enumerateGroups()) {
1431         processGroup(modelGroup, schemaPrefix);
1432       }
1433       // --process AttributeGroups
1434       for (AttributeGroup attributeGroup : schema.enumerateAttributeGroups()) {
1435         processAttributeGroup(attributeGroup, schemaPrefix);
1436       }
1437     }
1438     _handler.endElement(ELEMENT_NAME);
1439   } // -- processImport
1440 
1441   /**
1442    * Processes the given simple type definition
1443    *
1444    * @param simpleType the simple type definition to process into events
1445    * @param schemaPrefix the namespace prefix to use for schema elements
1446    **/
1447   private void processSimpleType(SimpleType simpleType, String schemaPrefix) throws SAXException {
1448 
1449     if (simpleType.isBuiltInType())
1450       return;
1451 
1452     String ELEMENT_NAME = schemaPrefix + SIMPLE_TYPE;
1453 
1454     _atts.clear();
1455 
1456     String name = simpleType.getName();
1457 
1458     // -- top-level simple type
1459     if (name != null) {
1460       _atts.addAttribute(SchemaNames.NAME_ATTR, CDATA, name);
1461     }
1462 
1463     // -- @final
1464     if (simpleType.getFinal() != null) {
1465       _atts.addAttribute(SchemaNames.FINAL_ATTR, CDATA, simpleType.getFinal());
1466     }
1467 
1468     // -- @id
1469     if (simpleType.getId() != null) {
1470       _atts.addAttribute(SchemaNames.ID_ATTR, CDATA, simpleType.getId());
1471     }
1472 
1473     _handler.startElement(ELEMENT_NAME, _atts);
1474 
1475     // -- process annotations
1476     processAnnotated(simpleType, schemaPrefix);
1477 
1478     // -- handle restriction
1479     SimpleType base = (SimpleType) simpleType.getBaseType();
1480 
1481     /*
1482      * In case we don't have a direct reference on the base type, check whether its definition can
1483      * be obtained from one of the imported schemas.
1484      */
1485     String typeName = simpleType.getBaseTypeName();
1486     if (base == null && typeName != null) {
1487       Schema schema = simpleType.getSchema();
1488       base = getSimpleTypeFromSchema(schema, typeName);
1489     }
1490 
1491     boolean isRestriction = false;
1492     if (base != null) {
1493       if (simpleType instanceof ListType) {
1494         isRestriction = (base instanceof ListType);
1495       } else
1496         isRestriction = true;
1497     }
1498 
1499     if (isRestriction) {
1500 
1501       String ELEM_RESTRICTION = schemaPrefix + RESTRICTION;
1502 
1503       _atts.clear();
1504 
1505       typeName = base.getName();
1506       // -- add "xsd" prefix if necessary
1507       if (typeName.indexOf(':') < 0) {
1508         if (base.isBuiltInType()) {
1509           typeName = schemaPrefix + typeName;
1510         } else {
1511           String targetNamespace = base.getSchema().getTargetNamespace();
1512           String prefix = getNSPrefix(simpleType.getSchema(), targetNamespace);
1513           if ((prefix != null) && (prefix.length() > 0)) {
1514             typeName = prefix + ":" + typeName;
1515           }
1516         }
1517       }
1518       _atts.addAttribute(SchemaNames.BASE_ATTR, CDATA, typeName);
1519 
1520       _handler.startElement(ELEM_RESTRICTION, _atts);
1521 
1522       // -- process facets
1523       Enumeration enumeration = simpleType.getLocalFacets();
1524       while (enumeration.hasMoreElements()) {
1525         Facet facet = (Facet) enumeration.nextElement();
1526         _atts.clear();
1527         _atts.addAttribute(SchemaNames.VALUE_ATTR, CDATA, facet.getValue());
1528         String facetName = schemaPrefix + facet.getName();
1529         _handler.startElement(facetName, _atts);
1530         Enumeration annotations = facet.getAnnotations();
1531         while (annotations.hasMoreElements()) {
1532           Annotation annotation = (Annotation) annotations.nextElement();
1533           processAnnotation(annotation, schemaPrefix);
1534         }
1535         _handler.endElement(facetName);
1536       }
1537 
1538       _handler.endElement(ELEM_RESTRICTION);
1539     } else if (simpleType instanceof Union) {
1540       processUnion((Union) simpleType, schemaPrefix);
1541     }
1542     // -- handle List
1543     else {
1544 
1545       String ELEM_LIST = schemaPrefix + SchemaNames.LIST;
1546 
1547       _atts.clear();
1548 
1549       SimpleType itemType = ((ListType) simpleType).getItemType();
1550 
1551       boolean topLevel = (itemType.getParent() == itemType.getSchema());
1552       if (itemType.isBuiltInType() || topLevel) {
1553         typeName = itemType.getName();
1554         // -- add "xsd" prefix if necessary
1555         if ((typeName.indexOf(':') < 0) && itemType.isBuiltInType()) {
1556           typeName = schemaPrefix + typeName;
1557         }
1558         _atts.addAttribute("itemType", CDATA, typeName);
1559       }
1560       _handler.startElement(ELEM_LIST, _atts);
1561 
1562       // -- processAnnotations
1563       Annotation ann = ((ListType) simpleType).getLocalAnnotation();
1564       if (ann != null) {
1565         processAnnotation(ann, schemaPrefix);
1566       }
1567       // -- process simpleType if necessary
1568       if ((!topLevel) && (!itemType.isBuiltInType())) {
1569         processSimpleType(itemType, schemaPrefix);
1570       }
1571       _handler.endElement(ELEM_LIST);
1572     }
1573 
1574     _handler.endElement(ELEMENT_NAME);
1575 
1576   } // -- processSimpleType
1577 
1578   /**
1579    * Processes the given simpleType Union definition
1580    *
1581    * @param union the simpleType Union definition to process into events
1582    * @param schemaPrefix the namespace prefix to use for schema elements
1583    * @throws SAXException Indicates a problem in SAX processing.
1584    **/
1585   private void processUnion(final Union union, final String schemaPrefix) throws SAXException {
1586 
1587     String elementName = schemaPrefix + SchemaNames.UNION;
1588 
1589     _atts.clear();
1590 
1591     if (union.getId() != null) {
1592       _atts.addAttribute(SchemaNames.ID_ATTR, CDATA, union.getId());
1593     }
1594 
1595     // -- process local simpleType references
1596     StringBuffer memberTypesBuffer = new StringBuffer();
1597     Enumeration memberTypes = union.getMemberTypes();
1598     while (memberTypes.hasMoreElements()) {
1599       SimpleType simpleType = (SimpleType) memberTypes.nextElement();
1600       // -- ignore local simpleTypes;
1601       if (!simpleType.isBuiltInType() && simpleType.getParent() != union.getSchema()) {
1602         continue;
1603       }
1604       // -- process top-level references
1605       if (memberTypesBuffer.length() > 0) {
1606         memberTypesBuffer.append(' ');
1607       }
1608       if (simpleType.isBuiltInType()) {
1609         memberTypesBuffer.append(schemaPrefix);
1610       } else {
1611         String targetNamespace = simpleType.getSchema().getTargetNamespace();
1612         String prefix = getNSPrefix(simpleType.getSchema(), targetNamespace);
1613         if ((prefix != null) && (prefix.length() > 0)) {
1614           memberTypesBuffer.append(prefix + ":");
1615         }
1616       }
1617       memberTypesBuffer.append(simpleType.getName());
1618     }
1619     if (memberTypesBuffer.length() > 0) {
1620       _atts.addAttribute(SchemaNames.MEMBER_TYPES_ATTR, CDATA, memberTypesBuffer.toString());
1621     }
1622 
1623     _handler.startElement(elementName, _atts);
1624 
1625     // -- process local annotation
1626     Annotation annotation = union.getLocalAnnotation();
1627     if (annotation != null) {
1628       processAnnotation(annotation, schemaPrefix);
1629     }
1630 
1631     // -- process local simpleType definitions
1632     Enumeration localMemberTypeDefinitions = union.getMemberTypes();
1633     while (localMemberTypeDefinitions.hasMoreElements()) {
1634       SimpleType localMemberTypeDefinition = (SimpleType) localMemberTypeDefinitions.nextElement();
1635       // -- ignore top-level simpleTypes;
1636       if (localMemberTypeDefinition.getParent() == union.getSchema()) {
1637         continue;
1638       }
1639       processSimpleType(localMemberTypeDefinition, schemaPrefix);
1640     }
1641 
1642     _handler.endElement(elementName);
1643 
1644   } // -- processUnion
1645 
1646   /**
1647    * Determines if a given XMLType is imported by the schema containing the element that refers to
1648    * it.
1649    *
1650    * @param type the type to be checked to see if it is imported
1651    * @param element the schema element that references the type
1652    **/
1653   private boolean isImportedType(XMLType type, ElementDecl element) {
1654     String targetNS = type.getSchema().getTargetNamespace();
1655     if (targetNS != null) {
1656       return (element.getSchema().getImportedSchema(targetNS) != null);
1657     }
1658     return false;
1659   } // -- isImportedType
1660 
1661   /**
1662    * Determines the proper namespace prefix for a namespace by scanning all declared namespaces for
1663    * the schema.
1664    *
1665    * @param schema the schema in which the namespace is declared
1666    * @param namespace the namespace for which a prefix will be returned
1667    **/
1668   private String getNSPrefix(Schema schema, String namespace) {
1669     if (namespace == null)
1670       namespace = "";
1671     return schema.getNamespaces().getNamespacePrefix(namespace);
1672   } // -- getNSPrefix
1673 
1674 
1675   /**
1676    * Walks over provided schema and its hierarchy looking for the named type.
1677    * 
1678    * @param schema Schema instance where to start searching from.
1679    * @param typeName Name of the type we search.
1680    * 
1681    * @return Definition of the simple type is found, null otherwise.
1682    */
1683   private SimpleType getSimpleTypeFromSchema(Schema schema, String typeName) {
1684     SimpleType base = schema.getSimpleType(typeName);
1685     if (base == null) {
1686       Iterator<Schema> imports = schema.getImportedSchema().iterator();
1687       while (imports.hasNext() && base == null) {
1688         Schema importedSchema = imports.next();
1689         base = getSimpleTypeFromSchema(importedSchema, typeName);
1690       }
1691     }
1692     return base;
1693   }
1694 } // -- SchemaWriter