KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > ws > jaxme > xs > impl > XSLogicalParser


1 /*
2  * Copyright 2003, 2004 The Apache Software Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15
16  */

17 package org.apache.ws.jaxme.xs.impl;
18
19 import java.io.File JavaDoc;
20 import java.io.IOException JavaDoc;
21 import java.net.MalformedURLException JavaDoc;
22 import java.net.URL JavaDoc;
23 import java.util.ArrayList JavaDoc;
24 import java.util.HashMap JavaDoc;
25 import java.util.HashSet JavaDoc;
26 import java.util.Iterator JavaDoc;
27 import java.util.List JavaDoc;
28 import java.util.Map JavaDoc;
29 import java.util.Set JavaDoc;
30
31 import javax.xml.parsers.ParserConfigurationException JavaDoc;
32
33 import org.apache.ws.jaxme.xs.XSContentHandler;
34 import org.apache.ws.jaxme.xs.XSElement;
35 import org.apache.ws.jaxme.xs.XSObjectFactory;
36 import org.apache.ws.jaxme.xs.XSParser;
37 import org.apache.ws.jaxme.xs.XSSchema;
38 import org.apache.ws.jaxme.xs.parser.XSContext;
39 import org.apache.ws.jaxme.xs.parser.XsSAXParser;
40 import org.apache.ws.jaxme.xs.parser.impl.LocSAXException;
41 import org.apache.ws.jaxme.xs.xml.XsAnyURI;
42 import org.apache.ws.jaxme.xs.xml.XsEAnnotation;
43 import org.apache.ws.jaxme.xs.xml.XsEImport;
44 import org.apache.ws.jaxme.xs.xml.XsEInclude;
45 import org.apache.ws.jaxme.xs.xml.XsENotation;
46 import org.apache.ws.jaxme.xs.xml.XsERedefine;
47 import org.apache.ws.jaxme.xs.xml.XsESchema;
48 import org.apache.ws.jaxme.xs.xml.XsETopLevelSimpleType;
49 import org.apache.ws.jaxme.xs.xml.XsNCName;
50 import org.apache.ws.jaxme.xs.xml.XsObject;
51 import org.apache.ws.jaxme.xs.xml.XsObjectFactory;
52 import org.apache.ws.jaxme.xs.xml.XsQName;
53 import org.apache.ws.jaxme.xs.xml.XsRedefinable;
54 import org.apache.ws.jaxme.xs.xml.XsTAttribute;
55 import org.apache.ws.jaxme.xs.xml.XsTAttributeGroup;
56 import org.apache.ws.jaxme.xs.xml.XsTComplexType;
57 import org.apache.ws.jaxme.xs.xml.XsTLocalElement;
58 import org.apache.ws.jaxme.xs.xml.XsTNamedGroup;
59 import org.apache.ws.jaxme.xs.xml.XsTSimpleExplicitGroup;
60 import org.apache.ws.jaxme.xs.xml.XsTTopLevelElement;
61 import org.w3c.dom.Node JavaDoc;
62 import org.xml.sax.EntityResolver JavaDoc;
63 import org.xml.sax.InputSource JavaDoc;
64 import org.xml.sax.Locator JavaDoc;
65 import org.xml.sax.SAXException JavaDoc;
66 import org.xml.sax.XMLReader JavaDoc;
67
68
69 /** <p>Implementation of a logical parser.</p>
70  *
71  * @author <a HREF="mailto:joe@ispsoft.de">Jochen Wiedmann</a>
72  */

73 public class XSLogicalParser {
74     /** This class is used to ensure, that schemata aren't loaded
75      * twice. It can also be used for preloading schemata.
76      */

77     public static class AddedImport {
78         private final String JavaDoc targetNamespace, schemaLocation;
79         private final Node JavaDoc node;
80         /** Creates a new instance with the given target namespace and
81          * schema location.
82          * @param pTargetNamespace The schemas target namespace.
83          * @param pSchemaLocation The schemas location.
84          */

85         public AddedImport(XsAnyURI pTargetNamespace, String JavaDoc pSchemaLocation) {
86             this(pTargetNamespace == null ? "" : pTargetNamespace.toString(), pSchemaLocation);
87         }
88         /** Creates a new instance with the given target namespace and
89          * schema location.
90          * @param pTargetNamespace The schemas target namespace.
91          * @param pSchemaLocation The schemas location.
92          */

93         public AddedImport(String JavaDoc pTargetNamespace, String JavaDoc pSchemaLocation) {
94             this(pTargetNamespace, pSchemaLocation, null);
95         }
96         /** Creates a new instance with the given target namespace and
97          * schema location. The schema isn't parsed from the location.
98          * Instead, the supplied nodes contents should be used as a
99          * schema.
100          * @param pTargetNamespace The schemas target namespace.
101          * @param pSchemaLocation The schemas location.
102          * @param pNode The schemas contents as a DOM node.
103          */

104         public AddedImport(String JavaDoc pTargetNamespace, String JavaDoc pSchemaLocation, Node JavaDoc pNode) {
105             targetNamespace = pTargetNamespace == null ? "" : pTargetNamespace.toString();
106             if (pSchemaLocation == null) {
107                 throw new IllegalStateException JavaDoc("The schemaLocation must not be null.");
108             }
109             schemaLocation = pSchemaLocation;
110             node = pNode;
111         }
112         public boolean equals(Object JavaDoc pOther) {
113             if (pOther instanceof AddedImport) {
114                 AddedImport other = (AddedImport) pOther;
115                 return targetNamespace.equals(other.targetNamespace) &&
116                 schemaLocation.equals(other.schemaLocation);
117             } else {
118                 return false;
119             }
120         }
121         public int hashCode() {
122             return targetNamespace.hashCode() + schemaLocation.hashCode();
123         }
124         
125         /** Returns the imported schemas target namespace.
126          */

127         public String JavaDoc getNamespace() {
128             return targetNamespace;
129         }
130         
131         /** Returns the URL, from which the schema is being loaded.
132          * Returns null, if the schema is loaded from a DOM node.
133          */

134         public String JavaDoc getSchemaLocation() {
135             return schemaLocation;
136         }
137         
138         /** Returns the DOM node, from which the schema is being loaded.
139          * Returns null, if the schema is loaded from an URL.
140          */

141         public Node JavaDoc getNode() {
142             return node;
143         }
144     }
145     
146     private boolean notValidating;
147     private List JavaDoc syntaxSchemas = new ArrayList JavaDoc();
148     private XsESchema[] syntaxSchemaArray;
149     private XSSchema schema;
150     private Set JavaDoc parsedSchemas;
151     private List JavaDoc addedImports = new ArrayList JavaDoc();
152     
153     protected XSContext getData() {
154         return XSParser.getRunningInstance().getContext();
155     }
156     
157     /** <p>Sets whether the parser is validating.</p>
158      */

159     public void setValidating(boolean pValidating) {
160         notValidating = !pValidating;
161     }
162     
163     /** <p>Returns whether the parser is validating.</p>
164      */

165     public boolean isValidating() {
166         return !notValidating;
167     }
168     
169     /** <p>Adds a schema being imported by the parser. This feature
170      * is useful, if a schema silently assumes the presence of additional
171      * datatypes. For example, a WSDL definition will contain references
172      * to SOAP datatypes without explicit import.</p>
173      * <p>In practice, the declaration will silently create an
174      * "xs:import" node.</p>
175      * @param pNamespace Matches the "xs:import" nodes "namespace" attribute.
176      * In particular it may be null, in which case the imported schema may
177      * not have a targetNamespace.
178      * @param pSchemaLocation Matches the "xs:import" nodes "schemaLocation"
179      * attribute. In particular it may be null.
180      */

181     public void addImport(String JavaDoc pNamespace, String JavaDoc pSchemaLocation) {
182         addedImports.add(new AddedImport(pNamespace, pSchemaLocation));
183     }
184     
185     /** <p>Adds a schema being imported by the parser. The schema is
186      * provided as a DOM node. This feature is useful, if a schema
187      * silently assumes the presence of additional datatypes. For
188      * example, a WSDL definition will contain references to SOAP
189      * datatypes without explicit import.</p>
190      * @param pNamespace Matches the "xs:import" nodes "namespace"
191      * attribute. In particular it may be null, in which case the
192      * imported schema may not have a targetNamespace.
193      * @param pSchemaLocation System ID of the schema being imported,
194      * if known, or null. Knowing the system ID is important only,
195      * if you need to prevent recursive parsing of schemata.
196      * @param pSchema A DOM node with the schema being imported.
197      */

198     public void addImport(String JavaDoc pNamespace, String JavaDoc pSchemaLocation, Node JavaDoc pSchema) {
199         addedImports.add(new XSLogicalParser.AddedImport(pNamespace, pSchemaLocation, pSchema));
200     }
201     
202     /** <p>Returns the array of added imports, typically empty.</p>
203      */

204     public AddedImport[] getAddedImports() {
205         return (AddedImport[]) addedImports.toArray(new AddedImport[addedImports.size()]);
206     }
207     
208     /** <p>Returns the schema, which is currently being parsed.</p>
209      */

210     public XSSchema getSchema() { return schema; }
211     
212     /** <p>Sets the schema, which is currently being parsed.</p>
213      */

214     protected void setSchema(XSSchema pSchema) {
215         schema = pSchema;
216     }
217     
218     protected XsESchema parseSyntax(Node JavaDoc pNode) throws SAXException {
219         XSContext data = getData();
220         try {
221             XsObjectFactory factory = data.getXsObjectFactory();
222             XsESchema mySchema = factory.newXsESchema();
223             XsSAXParser xsSAXParser = factory.newXsSAXParser(mySchema);
224             addSyntaxSchema(mySchema);
225             try {
226                 data.setCurrentContentHandler(xsSAXParser);
227                 DOMSerializer ds = new DOMSerializer();
228                 ds.serialize(pNode, xsSAXParser);
229                 return (XsESchema) xsSAXParser.getBean();
230             } finally {
231                 removeSyntaxSchema();
232             }
233         } finally {
234             data.setCurrentContentHandler(null);
235         }
236     }
237     
238     /** <p>Converts the given URI into an instance of InputSource.</p>
239      */

240     protected InputSource JavaDoc getInputSource(String JavaDoc pReferencingSystemId, String JavaDoc pURI) throws SAXException {
241         URL JavaDoc url = null;
242         if (pReferencingSystemId != null) {
243             // Try to create the new URI based on the old URI; may be its relative?
244
try {
245                 url = new URL JavaDoc(new URL JavaDoc(pReferencingSystemId), pURI);
246             } catch (MalformedURLException JavaDoc e) {
247             }
248             
249             if (url == null) {
250                 try {
251                     url = new File JavaDoc(new File JavaDoc(pReferencingSystemId).getParentFile(), pURI).toURL();
252                 } catch (MalformedURLException JavaDoc e) {
253                 }
254             }
255         }
256         
257         if (url == null) {
258             try {
259                 url = new URL JavaDoc(pURI);
260             } catch (MalformedURLException JavaDoc e) {
261                 try {
262                     url = new File JavaDoc(pURI).toURL();
263                 } catch (MalformedURLException JavaDoc f) {
264                     throw new SAXException("Failed to parse the URI " + pURI);
265                 }
266             }
267         }
268         
269         try {
270             InputSource JavaDoc isource = new InputSource JavaDoc(url.openStream());
271             isource.setSystemId(url.toString());
272             return isource;
273         } catch (IOException JavaDoc e) {
274             throw new SAXException("Failed to open the URL " + url, e);
275         }
276     }
277     
278     
279     protected XsESchema parseSyntax(Locator JavaDoc pLocator, String JavaDoc pSchemaLocation)
280     throws SAXException, IOException JavaDoc, ParserConfigurationException JavaDoc {
281         XsESchema result = getData().getXsObjectFactory().newXsESchema();
282         parseSyntax(pLocator, pSchemaLocation, result);
283         return result;
284     }
285     
286     protected void parseSyntax(Locator JavaDoc pLocator, String JavaDoc pSchemaLocation,
287             XsESchema pSchema)
288     throws SAXException, IOException JavaDoc, ParserConfigurationException JavaDoc {
289         XSContext data = getData();
290         try {
291             XsObjectFactory factory = data.getXsObjectFactory();
292             XMLReader JavaDoc xr = factory.newXMLReader(isValidating());
293             EntityResolver JavaDoc entityResolver = xr.getEntityResolver();
294             InputSource JavaDoc schemaSource = null;
295             if (entityResolver != null) {
296                 schemaSource = entityResolver.resolveEntity(null, pSchemaLocation);
297             }
298             if (schemaSource == null) {
299                 schemaSource = getInputSource(pLocator == null ? null : pLocator.getSystemId(),
300                         pSchemaLocation);
301             }
302             
303             XsSAXParser xsSAXParser = factory.newXsSAXParser(pSchema);
304             addSyntaxSchema(pSchema);
305             try {
306                 data.setCurrentContentHandler(xsSAXParser);
307                 xr.setContentHandler(xsSAXParser);
308                 xr.parse(schemaSource);
309             } finally {
310                 removeSyntaxSchema();
311             }
312         } finally {
313             data.setCurrentContentHandler(null);
314         }
315     }
316     
317     /** <p>Redefines the given {@link XsRedefinable}.</p>
318      */

319     protected void redefine(XsESchema pSyntaxSchema,
320             XsERedefine pRedefine, XsRedefinable pChild) throws SAXException {
321         XSSchema mySchema = getSchema();
322         XSContext data = getData();
323         XSObjectFactory factory = data.getXSObjectFactory();
324         if (pChild instanceof XsTAttributeGroup) {
325             XsTAttributeGroup attributeGroup = (XsTAttributeGroup) pChild;
326             mySchema.redefine(factory.newXSAttributeGroup(mySchema, attributeGroup));
327         } else if (pChild instanceof XsTNamedGroup) {
328             XsTNamedGroup group = (XsTNamedGroup) pChild;
329             mySchema.redefine(factory.newXSGroup(mySchema, group));
330         } else if (pChild instanceof XsETopLevelSimpleType) {
331             XsETopLevelSimpleType type = (XsETopLevelSimpleType) pChild;
332             mySchema.redefine(factory.newXSType(mySchema, type));
333         } else if (pChild instanceof XsTComplexType) {
334             XsTComplexType type = (XsTComplexType) pChild;
335             mySchema.redefine(factory.newXSType(mySchema, type));
336         } else {
337             Locator JavaDoc locator = (pChild instanceof XsObject) ? ((XsObject) pChild).getLocator() : pRedefine.getLocator();
338             throw new LocSAXException("Unknown type for redefinition: " + pChild.getClass().getName() +
339                     ", perhaps you should handle this in a subclass?", locator);
340         }
341     }
342     
343     
344     
345     /** <p>Adds the given object to the schema.</p>
346      *
347      */

348     protected void add(XsESchema pSyntaxSchema, Object JavaDoc pChild) throws SAXException {
349         XSSchema mySchema = getSchema();
350         XSContext data = getData();
351         XSObjectFactory factory = data.getXSObjectFactory();
352         if (pChild instanceof XsEAnnotation) {
353             XsEAnnotation annotation = (XsEAnnotation) pChild;
354             mySchema.add(factory.newXSAnnotation(mySchema, annotation));
355         } else if (pChild instanceof XsETopLevelSimpleType) {
356             XsETopLevelSimpleType type = (XsETopLevelSimpleType) pChild;
357             mySchema.add(factory.newXSType(mySchema, type));
358         } else if (pChild instanceof XsTComplexType) {
359             XsTComplexType type = (XsTComplexType) pChild;
360             mySchema.add(factory.newXSType(mySchema, type));
361         } else if (pChild instanceof XsTNamedGroup) {
362             XsTNamedGroup group = (XsTNamedGroup) pChild;
363             mySchema.add(factory.newXSGroup(mySchema, group));
364         } else if (pChild instanceof XsTAttributeGroup) {
365             XsTAttributeGroup attributeGroup = (XsTAttributeGroup) pChild;
366             mySchema.add(factory.newXSAttributeGroup(mySchema, attributeGroup));
367         } else if (pChild instanceof XsTTopLevelElement) {
368             XsTTopLevelElement element = (XsTTopLevelElement) pChild;
369             mySchema.add(factory.newXSElement(mySchema, element));
370         } else if (pChild instanceof XsTAttribute) {
371             XsTAttribute attribute = (XsTAttribute) pChild;
372             mySchema.add(factory.newXSAttribute(mySchema, attribute));
373         } else if (pChild instanceof XsENotation) {
374             XsENotation notation = (XsENotation) pChild;
375             mySchema.add(factory.newXSNotation(mySchema, notation));
376         } else {
377             Locator JavaDoc locator = (pChild instanceof XsObject) ?
378                     ((XsObject) pChild).getLocator() : pSyntaxSchema.getLocator();
379                     throw new LocSAXException("Unknown child type: " + pChild.getClass().getName() +
380                             ", perhaps you should handle this in a subclass?", locator);
381         }
382     }
383     
384     /** <p>Handles xs:refefine.</p>
385      */

386     protected void redefineSchema(XsESchema pRedefiningSchema,
387             XsERedefine pRedefine)
388     throws SAXException, IOException JavaDoc, ParserConfigurationException JavaDoc {
389         // TODO: Implement redefine
390
throw new LocSAXException("Redefine isn't yet implemented.", pRedefine.getLocator());
391     }
392     
393     /** <p>Handles xs:include.</p>
394      */

395     protected void includeSchema(XsESchema pIncludingSchema,
396             XsEInclude pInclude)
397     throws SAXException, IOException JavaDoc, ParserConfigurationException JavaDoc {
398         final XsAnyURI schemaLocation = pInclude.getSchemaLocation();
399         if (schemaLocation == null) {
400             throw new LocSAXException("Invalid include: Missing 'schemaLocation' attribute.",
401                     pInclude.getLocator());
402         }
403         Locator JavaDoc locator = pInclude.getLocator();
404         XsESchema includedSchema = parseSyntax(locator, schemaLocation.toString());
405         XsAnyURI incNamespace = includedSchema.getTargetNamespace();
406         if (incNamespace == null) {
407             if (pIncludingSchema.getTargetNamespace() != null) {
408                 includedSchema.setTargetNamespace(pIncludingSchema.getTargetNamespace());
409             }
410         } else {
411             XsAnyURI myNamespace = includedSchema.getTargetNamespace();
412             if (!incNamespace.equals(myNamespace)) {
413                 throw new LocSAXException("Invalid include: The included schemas target namespace " +
414                         incNamespace + " and the including schemas target namespace " +
415                         myNamespace + " do not match.",
416                         pInclude.getLocator());
417             }
418         }
419         parse(includedSchema, schemaLocation.toString());
420     }
421     
422     private void checkValidImportSchema(XsESchema pImportingSchema, String JavaDoc pNamespace,
423             Locator JavaDoc pLocator)
424     throws SAXException {
425         if (pNamespace == null) {
426             if (pImportingSchema.getTargetNamespace() == null) {
427                 throw new LocSAXException("The importing schema has no 'targetNamespace' attribute and" +
428                         " the 'import' element has no 'namespace' attribute, which is" +
429                         " forbidden. Perhaps you want to use include?",
430                         pLocator);
431             }
432         } else {
433             if ("".equals(pNamespace)) {
434                 throw new LocSAXException("Invalid import: Empty 'namespace' attribute, which is forbidden." +
435                         " Perhaps you want to omit the attribute to indicate the absence of a namespace?",
436                         pLocator);
437             }
438             XsAnyURI targetNamespace = pImportingSchema.getTargetNamespace();
439             if (targetNamespace != null &&
440                     pNamespace.equals(targetNamespace.toString())) {
441                 throw new LocSAXException("The importing schema and the imported schema have the same namespace, which is forbidden. Perhaps you want to use include?",
442                         pLocator);
443             }
444         }
445     }
446     
447     private void importSchema(XsESchema pImportingSchema, String JavaDoc pNamespace,
448             XsESchema pImportedSchema, Locator JavaDoc pLocator,
449             String JavaDoc pSchemaLocation)
450     throws SAXException, ParserConfigurationException JavaDoc, IOException JavaDoc {
451         XsAnyURI impNamespace = pImportedSchema.getTargetNamespace();
452         if (pNamespace == null) {
453             if (impNamespace != null) {
454                 throw new LocSAXException("The 'import' element does not have a 'namespace' attribute, but the imported schema has target namespace " +
455                         impNamespace + ", it ought to match and have none.",
456                         pLocator);
457             }
458         } else {
459             if (impNamespace == null) {
460                 throw new LocSAXException("The 'import' element has a 'namespace' attribute (" + pNamespace +
461                         "), but the imported schema has no 'targetNamespace' attribute.",
462                         pLocator);
463             } else if (!pNamespace.equals(impNamespace.toString())) {
464                 throw new LocSAXException("The 'import' elements 'namespace' attribute (" + pNamespace +
465                         ") and the imported schemas 'targetNamespace' attribute (" +
466                         impNamespace + ") do not match.",
467                         pLocator);
468             }
469         }
470         parse(pImportedSchema, pSchemaLocation);
471     }
472     
473     /** <p>Handles xs:import.</p>
474      */

475     protected void importSchema(XsESchema pImportingSchema,
476             String JavaDoc pNamespace, String JavaDoc pSchemaLocation,
477             Locator JavaDoc pLocator)
478     throws SAXException, IOException JavaDoc, ParserConfigurationException JavaDoc {
479         if (pSchemaLocation == null) {
480             return;
481         }
482         checkValidImportSchema(pImportingSchema, pNamespace, pLocator);
483         
484         XsESchema importedSchema = parseSyntax(pLocator, pSchemaLocation);
485         importSchema(pImportingSchema, pNamespace, importedSchema, pLocator, pSchemaLocation);
486     }
487     
488     protected void importSchema(XsESchema pImportingSchema, String JavaDoc pNamespace, Node JavaDoc pNode,
489             String JavaDoc pSchemaLocation)
490     throws SAXException, IOException JavaDoc, ParserConfigurationException JavaDoc {
491         checkValidImportSchema(pImportingSchema, pNamespace, null);
492         XsESchema importedSchema = parseSyntax(pNode);
493         importSchema(pImportingSchema, pNamespace, importedSchema, null, pSchemaLocation);
494     }
495     
496     /** <p>Parses the given {@link InputSource} syntactically and
497      * converts the objects that it finds into logical objects.
498      * These logical objects are added to the given {@link XSSchema}.</p>
499      */

500     protected void parse(XsESchema pSyntaxSchema, String JavaDoc pSchemaLocation)
501             throws ParserConfigurationException JavaDoc, SAXException, IOException JavaDoc {
502         if (pSchemaLocation != null) {
503             AddedImport schema = new AddedImport(pSyntaxSchema.getTargetNamespace(),
504                                                  pSchemaLocation);
505             if (parsedSchemas == null) {
506                 parsedSchemas = new HashSet JavaDoc();
507             } else if (parsedSchemas.contains(schema)) {
508                 return; // Already imported/included, ignore it
509
}
510             parsedSchemas.add(schema);
511
512             for (int i = 0; i < addedImports.size(); i++) {
513                 AddedImport addedImport = (AddedImport) addedImports.get(i);
514                 if (schema.equals(addedImport)) {
515                     return;
516                 }
517             }
518         }
519         addSyntaxSchema(pSyntaxSchema);
520         try {
521             Object JavaDoc[] childs = pSyntaxSchema.getChilds();
522             
523             for (int i = 0; i < childs.length; i++) {
524                 Object JavaDoc o = childs[i];
525                 if (o instanceof XsEInclude) {
526                     includeSchema(pSyntaxSchema, (XsEInclude) o);
527                 } else if (o instanceof XsERedefine) {
528                     redefineSchema(pSyntaxSchema, (XsERedefine) o);
529                 } else if (o instanceof XsEImport) {
530                     XsEImport xsEImport = (XsEImport) o;
531                     XsAnyURI namespace = xsEImport.getNamespace();
532                     XsAnyURI schemaLocation = xsEImport.getSchemaLocation();
533                     importSchema(pSyntaxSchema, namespace == null ? null : namespace.toString(),
534                             schemaLocation == null ? null : schemaLocation.toString(),
535                                     xsEImport.getLocator());
536                 } else {
537                     add(pSyntaxSchema, childs[i]);
538                 }
539             }
540         } finally {
541             removeSyntaxSchema();
542         }
543     }
544     
545     
546     private static class SubstitutionGroup {
547         private final List JavaDoc members = new ArrayList JavaDoc();
548         private final XSElement head;
549         
550         public SubstitutionGroup(XSElement pHead) {
551             head = pHead;
552         }
553         public XSElement getHead() { return head; }
554         public XSElement[] getMembers() {
555             return (XSElement[]) members.toArray(new XSElement[members.size()]);
556         }
557         public void addMember(XSElement pElement) {
558             members.add(pElement);
559         }
560     }
561     
562     protected void createSubstitutionGroups(XSSchema pSchema) throws SAXException {
563         Object JavaDoc[] myChilds = pSchema.getChilds();
564         
565         // Build the Map of substitution groups.
566
Map JavaDoc substitutionGroups = new HashMap JavaDoc();
567         for (int i = 0; i < myChilds.length; i++) {
568             if (myChilds[i] instanceof XSElement) {
569                 XSElement element = (XSElement) myChilds[i];
570                 XsQName qName = element.getSubstitutionGroupName();
571                 if (qName != null) {
572                     SubstitutionGroup group = (SubstitutionGroup) substitutionGroups.get(qName);
573                     if (group == null) {
574                         XSElement head = pSchema.getElement(qName);
575                         if (head == null) {
576                             throw new LocSAXException("The substituted element " + qName + " is missing in the schema.",
577                                     element.getLocator());
578                         }
579                         if (head.isBlockedForSubstitution()) {
580                             throw new LocSAXException("The substituted element " + qName + " is blocked for substitution.",
581                                     element.getLocator());
582                         }
583                         group = new SubstitutionGroup(head);
584                         if (!head.isAbstract()) {
585                             group.addMember(head);
586                         }
587                         substitutionGroups.put(qName, group);
588                     }
589                     group.addMember(element);
590                 }
591             }
592         }
593         
594         // For any substitution group: Build an implicit choice group, which
595
// may be used to replace the substitution groups head, if required.
596
for (Iterator JavaDoc iter = substitutionGroups.values().iterator(); iter.hasNext(); ) {
597             SubstitutionGroup group = (SubstitutionGroup) iter.next();
598             XSElementImpl head = (XSElementImpl) group.getHead();
599             XsObject object = head.getXsObject();
600             XsESchema syntaxSchema = object.getXsESchema();
601             
602             // Find a name for the group
603
String JavaDoc namespace = syntaxSchema.getTargetNamespace().toString();
604             String JavaDoc localName = head.getName().getLocalName() + "Group";
605             XsQName suggestion = new XsQName(namespace, localName);
606             if (pSchema.getGroup(suggestion) != null) {
607                 for (int i = 0; ; i++) {
608                     suggestion = new XsQName(namespace, localName + i);
609                     if (pSchema.getGroup(suggestion) == null) {
610                         break;
611                     }
612                 }
613             }
614             
615             XsTNamedGroup namedGroup = object.getObjectFactory().newXsTNamedGroup(syntaxSchema);
616             namedGroup.setName(new XsNCName(suggestion.getLocalName()));
617             XsTSimpleExplicitGroup choice = namedGroup.createChoice();
618             XSElement[] members = group.getMembers();
619             for (int j = 0; j < members.length; j++) {
620                 XSElement member = members[j];
621                 XsTLocalElement memberElement = choice.createElement();
622                 memberElement.setRef(member.getName());
623             }
624             
625             XSGroupImpl xsGroup = (XSGroupImpl) getSchema().getXSObjectFactory().newXSGroup(pSchema, namedGroup);
626             pSchema.add(xsGroup);
627             head.setSubstitutionGroup(xsGroup);
628         }
629     }
630     
631     /** <p>This is the logical parsers frontend for parsing a stream
632      * of SAX events.</p>
633      * @param pSystemId System Id (schema location of the schema being parsed, if known.
634      * Null otherwise. Knowing the system id is important only, if you want
635      * to prevent recursive includes.
636      */

637     public XSContentHandler getXSContentHandler(String JavaDoc pSystemId) throws SAXException {
638         return new XSContentHandlerImpl(this, pSystemId);
639     }
640     
641     /** <p>This is the logical parsers frontend for parsing a DOM node.</p>
642      */

643     public XSSchema parse(Node JavaDoc pNode) throws SAXException {
644         XSContentHandler handler = getXSContentHandler(null);
645         DOMSerializer ds = new DOMSerializer();
646         ds.serialize(pNode, handler);
647         return handler.getXSSchema();
648     }
649     
650     /** <p>This is the logical parsers frontend for parsing the given
651      * {@link InputSource}. If the parsed schema includes or imports other
652      * schemas, they are also parsed and added to the parsers object
653      * tree.</p>
654      * @see #getXSContentHandler()
655      */

656     public XSSchema parse(InputSource JavaDoc pSource)
657     throws ParserConfigurationException JavaDoc, SAXException, IOException JavaDoc {
658         XSContentHandler contentHandler = getXSContentHandler(pSource.getSystemId());
659         XSContext data = getData();
660         XMLReader JavaDoc xr = data.getXsObjectFactory().newXMLReader(isValidating());
661         xr.setContentHandler(contentHandler);
662         xr.parse(pSource);
663         return getSchema();
664     }
665     
666     protected void clearSyntaxSchemas() {
667         syntaxSchemas.clear();
668         syntaxSchemaArray = null;
669     }
670     
671     protected void addSyntaxSchema(XsESchema pSyntaxSchema) {
672         syntaxSchemas.add(pSyntaxSchema);
673         syntaxSchemaArray = null;
674     }
675     
676     protected void removeSyntaxSchema() {
677         syntaxSchemas.remove(syntaxSchemas.size()-1);
678         syntaxSchemaArray = null;
679     }
680     
681     /** <p>Provides context information to the schema which is currently being parsed.
682      * The schema with index 0 is the outermost schema, on which the parser is actually
683      * invoked.</p>
684      */

685     public XsESchema[] getSyntaxSchemas() {
686         if (syntaxSchemaArray == null) {
687             syntaxSchemaArray = (XsESchema[]) syntaxSchemas.toArray(new XsESchema[syntaxSchemas.size()]);
688         }
689         return syntaxSchemaArray;
690     }
691     
692     /** <p>Returns the syntax schema, which is currently being parsed.</p>
693      */

694     public XsESchema getCurrentSyntaxSchema() {
695         if (syntaxSchemaArray == null || syntaxSchemaArray.length == 0) {
696             return null;
697         } else {
698             return syntaxSchemaArray[syntaxSchemaArray.length-1];
699         }
700     }
701 }
702
Popular Tags