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