KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > ws > jaxme > xs > util > DTDParser


1 /*
2  * Copyright 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 package org.apache.ws.jaxme.xs.util;
17
18 import java.io.IOException JavaDoc;
19 import java.io.Reader JavaDoc;
20 import java.io.StringReader JavaDoc;
21 import java.util.ArrayList JavaDoc;
22 import java.util.HashMap JavaDoc;
23 import java.util.Iterator JavaDoc;
24 import java.util.List JavaDoc;
25 import java.util.Map JavaDoc;
26 import java.util.StringTokenizer JavaDoc;
27
28 import javax.xml.parsers.ParserConfigurationException JavaDoc;
29 import javax.xml.parsers.SAXParserFactory JavaDoc;
30
31 import org.apache.ws.jaxme.xs.XSSchema;
32 import org.apache.ws.jaxme.xs.impl.XSLogicalParser;
33 import org.apache.ws.jaxme.xs.parser.XSContext;
34 import org.apache.ws.jaxme.xs.parser.impl.XSContextImpl;
35 import org.apache.ws.jaxme.xs.types.XSAnyType;
36 import org.apache.ws.jaxme.xs.types.XSEntities;
37 import org.apache.ws.jaxme.xs.types.XSEntity;
38 import org.apache.ws.jaxme.xs.types.XSID;
39 import org.apache.ws.jaxme.xs.types.XSIDREF;
40 import org.apache.ws.jaxme.xs.types.XSIDREFs;
41 import org.apache.ws.jaxme.xs.types.XSNMToken;
42 import org.apache.ws.jaxme.xs.types.XSNMTokens;
43 import org.apache.ws.jaxme.xs.types.XSNotation;
44 import org.apache.ws.jaxme.xs.types.XSString;
45 import org.apache.ws.jaxme.xs.xml.XsAGOccurs;
46 import org.apache.ws.jaxme.xs.xml.XsAnyURI;
47 import org.apache.ws.jaxme.xs.xml.XsEChoice;
48 import org.apache.ws.jaxme.xs.xml.XsEComplexContent;
49 import org.apache.ws.jaxme.xs.xml.XsEEnumeration;
50 import org.apache.ws.jaxme.xs.xml.XsERestriction;
51 import org.apache.ws.jaxme.xs.xml.XsESchema;
52 import org.apache.ws.jaxme.xs.xml.XsESimpleContent;
53 import org.apache.ws.jaxme.xs.xml.XsGAttrDecls;
54 import org.apache.ws.jaxme.xs.xml.XsNCName;
55 import org.apache.ws.jaxme.xs.xml.XsQName;
56 import org.apache.ws.jaxme.xs.xml.XsTAttribute;
57 import org.apache.ws.jaxme.xs.xml.XsTComplexType;
58 import org.apache.ws.jaxme.xs.xml.XsTExplicitGroup;
59 import org.apache.ws.jaxme.xs.xml.XsTExtensionType;
60 import org.apache.ws.jaxme.xs.xml.XsTLocalComplexType;
61 import org.apache.ws.jaxme.xs.xml.XsTLocalElement;
62 import org.apache.ws.jaxme.xs.xml.XsTLocalSimpleType;
63 import org.apache.ws.jaxme.xs.xml.XsTSimpleExtensionType;
64 import org.apache.ws.jaxme.xs.xml.XsTTopLevelElement;
65 import org.apache.ws.jaxme.xs.xml.impl.XsESchemaImpl;
66 import org.apache.ws.jaxme.xs.xml.impl.XsObjectFactoryImpl;
67 import org.xml.sax.EntityResolver JavaDoc;
68 import org.xml.sax.InputSource JavaDoc;
69 import org.xml.sax.Locator JavaDoc;
70 import org.xml.sax.SAXException JavaDoc;
71 import org.xml.sax.SAXParseException JavaDoc;
72 import org.xml.sax.XMLReader JavaDoc;
73 import org.xml.sax.ext.DeclHandler JavaDoc;
74 import org.xml.sax.helpers.DefaultHandler JavaDoc;
75 import org.xml.sax.helpers.LocatorImpl JavaDoc;
76
77
78 /** A SAX parser converting a DTD into an instance of XML Schema.
79  */

80 public class DTDParser extends XSLogicalParser {
81     /** This class is used to collect the attributes in the
82      * DTD temporarily.
83      */

84     public class DTDAttribute {
85         private final String JavaDoc name, type, mode, value;
86         private final Locator JavaDoc loc;
87         /** Sets the attributes name.
88          */

89         public DTDAttribute(String JavaDoc pName, String JavaDoc pType, String JavaDoc pMode, String JavaDoc pValue) {
90             name = pName;
91             type = pType;
92             mode = pMode;
93             value = pValue;
94             Locator JavaDoc l = DTDParser.this.getLocator();
95             if (l == null) {
96                 loc = null;
97             } else {
98                 loc = new LocatorImpl JavaDoc(l);
99             }
100         }
101         /** Returns the attributes name.
102          */

103         public String JavaDoc getName() {
104             return name;
105         }
106         /** Returns the attributes type.
107          */

108         public String JavaDoc getType() {
109             return type;
110         }
111         /** Returns the attributes mode.
112          */

113         public String JavaDoc getMode() {
114             return mode;
115         }
116         /** Returns the attributes value.
117          */

118         public String JavaDoc getValue() {
119             return value;
120         }
121         /** Returns the attributes locator.
122          */

123         public Locator JavaDoc getLocator() {
124             return loc;
125         }
126     }
127
128     /** This class is used to collect the elements in the
129      * DTD temporarily.
130      */

131     public class DTDElement {
132         private final String JavaDoc name;
133         private Locator JavaDoc loc;
134         private String JavaDoc model;
135         private Map JavaDoc attributes = new HashMap JavaDoc();
136         /** Creates a new element declaration with the given name.
137          */

138         public DTDElement(String JavaDoc pName) {
139             name = pName;
140         }
141         /** Sets the elements content model.
142          */

143         public void setModel(String JavaDoc pModel) {
144             Locator JavaDoc l = DTDParser.this.getLocator();
145             if (l == null) {
146                 loc = null;
147             } else {
148                 loc = new LocatorImpl JavaDoc(l);
149             }
150             model = pModel;
151         }
152         /** Returns the elements content model.
153          */

154         public String JavaDoc getModel() {
155             return model;
156         }
157         /** Returns the elements name.
158          */

159         public String JavaDoc getName() {
160             return name;
161         }
162         /** Adds a new attribute to the element.
163          */

164         public void addAttribute(DTDAttribute pAttribute) throws SAXException JavaDoc {
165             if (attributes.put(pAttribute.getName(), pAttribute) != null) {
166                 throw new SAXParseException JavaDoc("Duplicate attribute " + pAttribute.getName()
167                                             + " in element " + getName(),
168                                             pAttribute.getLocator());
169             }
170         }
171         /** Returns the elements attributes.
172          */

173         public DTDAttribute[] getAttributes() {
174             return (DTDAttribute[]) attributes.values().toArray(new DTDAttribute[attributes.size()]);
175         }
176         /** Returns the elements locator.
177          */

178         public Locator JavaDoc getLocator() {
179             return loc;
180         }
181     }
182
183     protected static class ChildToken {
184         /** Type of a NAME token; see
185          * {@link DTDParser#parseChildren(XsTTopLevelElement, String, Locator)}
186          * for the definition of SEQUENCE.
187          */

188         public final static int SEQUENCE = 1;
189         /** Type of a NAME token; see
190          * {@link DTDParser#parseChildren(XsTTopLevelElement, String, Locator)}
191          * for the definition of CHOICE.
192          */

193         public final static int CHOICE = 2;
194         private final int type;
195         private final List JavaDoc tokens = new ArrayList JavaDoc();
196         private final String JavaDoc multiplicity;
197         protected ChildToken(int pType, String JavaDoc pMultiplicity) {
198             type = pType;
199             multiplicity = pMultiplicity;
200         }
201         /** Returns the token type; either of
202          * {@link #SEQUENCE}, or {@link #CHOICE}.
203          */

204         public int getType() { return type; }
205         /** Adds a token to the list of tokens.
206          */

207         public void add(ChildToken pToken) {
208             tokens.add(pToken);
209         }
210         /** Adds a name to the list of tokens.
211          */

212         public void add(String JavaDoc pName) {
213             tokens.add(pName);
214         }
215         /** Returns the tokens childs.
216          */

217         public Object JavaDoc[] getChilds() {
218             return tokens.toArray();
219         }
220         /** Returns the tokens multiplicity.
221          */

222         public String JavaDoc getMultiplicity() {
223             return multiplicity;
224         }
225     }
226     
227     /** This class is similar to a StringReader, except that
228      * it allows to extend the input dynamically.
229      */

230     public static class StringBufferReader extends Reader JavaDoc {
231         private final StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
232
233         /** Appends the given string to the input.
234          */

235         public void append(String JavaDoc pString) {
236             sb.append(pString);
237         }
238
239         /** Invoked, if the internal buffer is empty.
240          * Subclasses may override this to query for more
241          * input.
242          */

243         public String JavaDoc requestInput() {
244             return null;
245         }
246
247         public int read(char[] pBuffer, int pOffset, int pLen) throws IOException JavaDoc {
248             if (sb.length() == 0) {
249                 String JavaDoc s = requestInput();
250                 if (s != null && s.length() > 0) {
251                     append(s);
252                 }
253                 if (sb.length() == 0) {
254                     return -1;
255                 }
256             }
257             if (pLen >= sb.length()) {
258                 pLen = sb.length();
259             }
260             for (int i = 0; i < pLen; i++) {
261                 pBuffer[pOffset+i] = sb.charAt(i);
262             }
263             sb.delete(0, pLen);
264             return pLen;
265         }
266
267         public void close() throws IOException JavaDoc {
268         }
269     }
270
271     /** Implementation of a {@link DeclHandler} for reading
272      * the element and attribute declarations.
273      */

274     public class DtdDeclHandler extends DefaultHandler JavaDoc implements DeclHandler JavaDoc {
275         public void setDocumentLocator(Locator JavaDoc pLocator) {
276             setLocator(pLocator);
277         }
278
279         public void elementDecl(String JavaDoc pName, String JavaDoc pModel) throws SAXException JavaDoc {
280             DTDElement element = (DTDElement) elements.get(pName);
281             if (element == null) {
282                 element = new DTDElement(pName);
283                 elements.put(pName, element);
284             } else {
285                 if (element.getModel() != null) {
286                     throw new SAXParseException JavaDoc("Element " + pName
287                                                 + " declared twice", getLocator());
288                 }
289             }
290             element.setModel(pModel);
291         }
292
293         public void attributeDecl(String JavaDoc pElementName, String JavaDoc pAttributeName,
294                                   String JavaDoc pType, String JavaDoc pMode, String JavaDoc pValue) throws SAXException JavaDoc {
295             DTDElement element = (DTDElement) elements.get(pElementName);
296             if (element == null) {
297                 element = new DTDElement(pElementName);
298                 elements.put(pElementName, element);
299             }
300             DTDAttribute attr = new DTDAttribute(pAttributeName, pType, pMode, pValue);
301             element.addAttribute(attr);
302         }
303
304         public void internalEntityDecl(String JavaDoc pName, String JavaDoc pValue) throws SAXException JavaDoc {
305         }
306
307         public void externalEntityDecl(String JavaDoc pName, String JavaDoc publicId, String JavaDoc pSystemId) throws SAXException JavaDoc {
308         }
309     }
310
311     private Locator JavaDoc locator;
312     private final Map JavaDoc elements = new HashMap JavaDoc();
313     private String JavaDoc dummyElementName;
314     private XsAnyURI targetNamespace;
315     private XSContext context;
316
317     public XSContext getData() {
318         return context;
319     }
320
321     /** Returns the document locator.
322      */

323     public Locator JavaDoc getLocator() {
324         return locator;
325     }
326
327     /** Sets the document locator.
328      */

329     public void setLocator(Locator JavaDoc pLocator) {
330         locator = pLocator;
331         XSContext context = getData();
332         if (context != null) {
333             context.setLocator(pLocator);
334         }
335     }
336
337     protected String JavaDoc getDummyElementName() {
338         if (dummyElementName == null) {
339             for (int i = 0; ; i++) {
340                 String JavaDoc name = "dummyElement" + i;
341                 if (!elements.containsKey(name)) {
342                     dummyElementName = name;
343                     break;
344                 }
345             }
346         }
347         return dummyElementName;
348     }
349
350     /** Parses the given DTD, filling the parsers
351      * temporary map of elements.
352      */

353     protected void runXMLReader(final InputSource JavaDoc pSource)
354             throws ParserConfigurationException JavaDoc, IOException JavaDoc, SAXException JavaDoc {
355         /* We cannot parse the DTD directly. Instead, we create
356          * a dummy XML document, which references the DTD as
357          * an external entity, and parse the XML document.
358          */

359         String JavaDoc s = "<!DOCTYPE a SYSTEM 'uri:dtd'><a/>";
360         InputSource JavaDoc isource = new InputSource JavaDoc(new StringReader JavaDoc(s));
361         SAXParserFactory JavaDoc spf = SAXParserFactory.newInstance();
362         spf.setValidating(false);
363         XMLReader JavaDoc xr = spf.newSAXParser().getXMLReader();
364         xr.setEntityResolver(new EntityResolver JavaDoc(){
365             public InputSource JavaDoc resolveEntity(String JavaDoc publicId, String JavaDoc pSystemId) throws SAXException JavaDoc, IOException JavaDoc {
366                 return "uri:dtd".equals(pSystemId) ? pSource : null;
367             }
368         });
369         DtdDeclHandler handler = new DtdDeclHandler();
370         xr.setContentHandler(handler);
371         xr.setProperty("http://xml.org/sax/properties/declaration-handler", handler);
372         xr.parse(isource);
373     }
374
375     private ChildToken addToChildToken(ChildToken pToken, String JavaDoc pTokenValue,
376                                        String JavaDoc pMultiplicity, int pType,
377                                        Locator JavaDoc pLocator)
378             throws SAXException JavaDoc {
379         if ("".equals(pTokenValue)) {
380             throw new SAXParseException JavaDoc("Expected name, choice, or sequence, found empty string", pLocator);
381         }
382         if (pToken == null) {
383             pToken = new ChildToken(pType, pMultiplicity);
384         } else {
385             if (pType != pToken.getType()) {
386                 throw new SAXParseException JavaDoc("Mixed use of ',' and '|' in a choice or sequence", pLocator);
387             }
388         }
389         if (pTokenValue.startsWith("(")) {
390             pToken.add(parseChildren(pTokenValue, pLocator));
391         } else {
392             pToken.add(pTokenValue);
393         }
394         return pToken;
395     }
396
397     /** Returns a tokens multiplicity.
398      */

399     protected String JavaDoc getMultiplicity(String JavaDoc pToken) {
400         if (pToken.endsWith("*")) {
401             return "*";
402         } else if (pToken.endsWith("?")) {
403             return "?";
404         } else if (pToken.endsWith("+")) {
405             return "+";
406         } else {
407             return "";
408         }
409     }
410
411     /** Converts a list of children into its tokens.
412      */

413     protected ChildToken parseChildren(String JavaDoc pModel, Locator JavaDoc pLocator)
414             throws SAXException JavaDoc {
415         String JavaDoc model = pModel;
416         if (model.startsWith("(")) {
417             model = model.substring(1).trim();
418         } else {
419             throw new SAXParseException JavaDoc("A choice or sequence must start with '('",
420                                         pLocator);
421         }
422         String JavaDoc multiplicity = getMultiplicity(model);
423         model = model.substring(0, model.length() - multiplicity.length()).trim();
424         if (model.endsWith(")")) {
425             model = model.substring(0, model.length()-1);
426         } else {
427             throw new SAXParseException JavaDoc("A choice or sequence must end with ')', ')?', ')*', or ')+'",
428                                         pLocator);
429         }
430         ChildToken ct = null;
431         int level = 0;
432         int offset = 0;
433         for (int i = 0; i < model.length(); i++) {
434             char c = model.charAt(i);
435             switch (c) {
436                 case '(': ++level; break;
437                 case ')': --level; break;
438                 case '|':
439                 case ',':
440                     if (level == 0) {
441                         String JavaDoc t = model.substring(offset, i).trim();
442                         ct = addToChildToken(ct, t, multiplicity,
443                                              (c == '|' ? ChildToken.CHOICE : ChildToken.SEQUENCE),
444                                              pLocator);
445                         offset = i+1;
446                     }
447             }
448         }
449         String JavaDoc t = model.substring(offset).trim();
450         return addToChildToken(ct, t, multiplicity,
451                                ct == null ? ChildToken.SEQUENCE : ct.getType(),
452                                pLocator);
453     }
454
455     /** Sets the objects multiplicity.
456      */

457     protected void setMultiplicity(XsAGOccurs pOccurs, String JavaDoc pMultiplicity) {
458         if ("?".equals(pMultiplicity)) {
459             pOccurs.setMinOccurs(0);
460         } else if ("*".equals(pMultiplicity)) {
461             pOccurs.setMinOccurs(0);
462             pOccurs.setMaxOccurs("unbounded");
463         } else if ("+".equals(pMultiplicity)) {
464             pOccurs.setMaxOccurs("unbounded");
465         } else if (!"".equals(pMultiplicity)) {
466             throw new IllegalArgumentException JavaDoc("Invalid multiplicity: " + pMultiplicity);
467         }
468     }
469
470     /** Adds the childs to a group.
471      */

472     protected void addChildren(XsTTopLevelElement pElement,
473                                XsTExplicitGroup pGroup, ChildToken pToken,
474                                Locator JavaDoc pLocator)
475             throws SAXException JavaDoc {
476         setMultiplicity(pGroup, pToken.getMultiplicity());
477         Object JavaDoc[] tokens = pToken.getChilds();
478         for (int i = 0; i < tokens.length; i++) {
479             Object JavaDoc o = tokens[i];
480             if (o instanceof String JavaDoc) {
481                 String JavaDoc name = (String JavaDoc) o;
482                 String JavaDoc multiplicity = getMultiplicity(name);
483                 name = name.substring(0, name.length()-multiplicity.length()).trim();
484                 if (!elements.containsKey(name)) {
485                     throw new SAXParseException JavaDoc("Element " + pElement.getName()
486                                                 + " references an undeclared element " + name,
487                                                 pLocator);
488                 }
489                 XsTLocalElement e = pGroup.createElement();
490                 e.setRef(new XsQName(getTargetNamespace(), getLocalPart(name)));
491                 setMultiplicity(e, multiplicity);
492             } else if (o instanceof ChildToken) {
493                 ChildToken ct = (ChildToken) o;
494                 XsTExplicitGroup group;
495                 if (ct.type == ChildToken.SEQUENCE) {
496                     group = pGroup.createSequence();
497                 } else {
498                     group = pGroup.createChoice();
499                 }
500                 addChildren(pElement, group, ct, pLocator);
501             } else {
502                 throw new IllegalStateException JavaDoc("Unknown token type: " + tokens[i].getClass().getName());
503             }
504         }
505     }
506
507     /** Parses a content model with children. This content
508      * model is specified as follows:
509      * <pre>
510      * children ::= (choice | seq) ('?' | '*' | '+')?
511      * cp ::= (Name | choice | seq) ('?' | '*' | '+')?
512      * choice ::= '(' S? cp ( S? '|' S? cp )+ S? ')'
513      * seq ::= '(' S? cp ( S? ',' S? cp )* S? ')'
514      * </pre>
515      */

516     protected XsGAttrDecls parseChildren(XsTTopLevelElement pElement, String JavaDoc pModel,
517                                  Locator JavaDoc pLocator) throws SAXException JavaDoc {
518         ChildToken ct = parseChildren(pModel, pLocator);
519         XsTLocalComplexType complexType = pElement.createComplexType();
520         XsTExplicitGroup group;
521         if (ct.getType() == ChildToken.SEQUENCE) {
522             group = complexType.createSequence();
523         } else {
524             group = complexType.createChoice();
525         }
526         addChildren(pElement, group, ct, pLocator);
527         return complexType;
528     }
529
530     /** Parses a mixed content model. The mixed content model
531      * is specified as follows:
532      * <pre>
533      * Mixed ::= '(' S? '#PCDATA' (S? '|' S? Name)* S? ')*'
534      * | '(' S? '#PCDATA' S? ')'
535      * </pre>
536      */

537     protected XsGAttrDecls parseMixed(XsTTopLevelElement pElement, String JavaDoc pModel,
538                                       Locator JavaDoc pLocator, boolean pHasAttributes)
539             throws SAXException JavaDoc {
540         if (!pModel.startsWith("(")) {
541             throw new SAXParseException JavaDoc("Mixed content model must start with '(#PCDATA'",
542                                         pLocator);
543         }
544         pModel = pModel.substring(1).trim();
545         if (!pModel.startsWith("#PCDATA")) {
546             throw new SAXParseException JavaDoc("Mixed content model must start with '(#PCDATA'",
547                     pLocator);
548         }
549         pModel = pModel.substring("#PCDATA".length()).trim();
550         boolean unbounded;
551         if (pModel.endsWith("*")) {
552             pModel = pModel.substring(0, pModel.length()-1).trim();
553             unbounded = true;
554         } else {
555             unbounded = false;
556         }
557         if (!pModel.endsWith(")")) {
558             throw new SAXParseException JavaDoc("Mixed content model must end with ')' or ')*'",
559                                         pLocator);
560         }
561         pModel = pModel.substring(0, pModel.length()-1);
562         if ("".equals(pModel)) {
563             XsQName qName = XSString.getInstance().getName();
564             qName = new XsQName(qName.getNamespaceURI(), qName.getLocalName(), "xs");
565             if (pHasAttributes) {
566                 XsTLocalComplexType complexType = pElement.createComplexType();
567                 XsESimpleContent simpleContent = complexType.createSimpleContent();
568                 XsTSimpleExtensionType ext = simpleContent.createExtension();
569                 ext.setBase(qName);
570                 return ext;
571             } else {
572                 pElement.setType(qName);
573                 return null;
574             }
575         } else if (!unbounded) {
576             throw new SAXParseException JavaDoc("Mixed content must be either #PCDATA or have multiplicity '*'",
577                                         pLocator);
578         } else {
579             XsTLocalComplexType complexType = pElement.createComplexType();
580             complexType.setMixed(true);
581             XsEChoice choice = complexType.createChoice();
582             choice.setMinOccurs(0);
583             choice.setMaxOccurs("unbounded");
584             while (!"".equals(pModel)) {
585                 if (pModel.startsWith("|")) {
586                     pModel = pModel.substring(1).trim();
587                 } else {
588                     throw new SAXParseException JavaDoc("Expected '|' while parsing mixed content", pLocator);
589                 }
590                 int offset = pModel.indexOf('|');
591                 String JavaDoc name;
592                 if (offset == -1) {
593                     name = pModel.trim();
594                     pModel = "";
595                 } else {
596                     name = pModel.substring(0, offset).trim();
597                     pModel = pModel.substring(offset);
598                 }
599                 if (elements.containsKey(name)) {
600                     XsTLocalElement e = choice.createElement();
601                     e.setRef(new XsQName(getTargetNamespace(), getLocalPart(name)));
602                 } else {
603                     throw new SAXParseException JavaDoc("Element " + pElement.getName()
604                                                 + " references element " + name
605                                                 + ", which is not declared",
606                                                 pLocator);
607                 }
608             }
609             return complexType;
610         }
611     }
612
613     /** Creates a new attribute.
614      */

615     protected void createAttribute(XsGAttrDecls pAttrDecls, DTDAttribute pAttribute)
616             throws SAXException JavaDoc {
617         XsTAttribute attr = pAttrDecls.createAttribute();
618         attr.setName(new XsNCName(getLocalPart(pAttribute.getName())));
619         String JavaDoc type = pAttribute.getType();
620         XsQName qName;
621         if ("CDATA".equals(type)) {
622             qName = XSString.getInstance().getName();
623         } else if ("ID".equals(type)) {
624             qName = XSID.getInstance().getName();
625         } else if ("IDREF".equals(type)) {
626             qName = XSIDREF.getInstance().getName();
627         } else if ("IDREFS".equals(type)) {
628             qName = XSIDREFs.getInstance().getName();
629         } else if ("ENTITY".equals(type)) {
630             qName = XSEntity.getInstance().getName();
631         } else if ("ENTITIES".equals(type)) {
632             qName = XSEntities.getInstance().getName();
633         } else if ("NMTOKEN".equals(type)) {
634             qName = XSNMToken.getInstance().getName();
635         } else if ("NMTOKENS".equals(type)) {
636             qName = XSNMTokens.getInstance().getName();
637         } else {
638             if (type.startsWith("NOTATION") &&
639                 Character.isWhitespace(type.charAt("NOTATION".length()))) {
640                 qName = XSNotation.getInstance().getName();
641             } else {
642                 qName = XSNMToken.getInstance().getName();
643             }
644             XsTLocalSimpleType simpleType = attr.createSimpleType();
645             XsERestriction restriction = simpleType.createRestriction();
646             restriction.setBase(new XsQName(qName.getNamespaceURI(), qName.getLocalName(), "xs"));
647             if (type.startsWith("(")) {
648                 type = type.substring(1).trim();
649             } else {
650                 throw new SAXParseException JavaDoc("The enumeration in the type of attribute "
651                                             + pAttribute.getName()
652                                             + " must begin with an '('.",
653                                             pAttribute.getLocator());
654             }
655             if (type.endsWith(")")) {
656                 type = type.substring(0, type.length()-1).trim();
657             } else {
658                 throw new SAXParseException JavaDoc("The enumeration in the type of attribute "
659                                             + pAttribute.getName()
660                                             + " must begin with an '('.",
661                                             pAttribute.getLocator());
662             }
663             StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(type, "|");
664             if (!st.hasMoreTokens()) {
665                 throw new SAXParseException JavaDoc("The enumeration in the type of attribute "
666                                             + pAttribute.getName()
667                                             + " contains no tokens.",
668                                             pAttribute.getLocator());
669             }
670             while (st.hasMoreTokens()) {
671                 String JavaDoc token = st.nextToken().trim();
672                 if ("".equals(token)) {
673                     throw new SAXParseException JavaDoc("The enumeration in the type of attribute "
674                                                 + pAttribute.getName()
675                                                 + " contains an empty token.",
676                                                 pAttribute.getLocator());
677                 }
678                 XsEEnumeration enumeration = restriction.createEnumeration();
679                 enumeration.setValue(token);
680             }
681             qName = null;
682         }
683         if (qName != null) {
684             attr.setType(new XsQName(qName.getNamespaceURI(), qName.getLocalName(), "xs"));
685         }
686     }
687
688     private String JavaDoc getLocalPart(String JavaDoc pName) {
689         int offset = pName.indexOf(':');
690         if (offset >= 0) {
691             return pName.substring(offset+1);
692         } else {
693             return pName;
694         }
695     }
696
697     /** Creates an element named <code>pName</code> with the
698      * content model <code>pModel</code> and the attribute
699      * list <code>pAttrs</code> in the schema <code>pSchema</code>.
700      */

701     protected XsTTopLevelElement createElement(XsESchema pSchema, String JavaDoc pName,
702                                                String JavaDoc pModel,
703                                                DTDAttribute[] pAttributes,
704                                                Locator JavaDoc pLocator)
705             throws SAXException JavaDoc {
706         XsTTopLevelElement result = pSchema.createElement();
707         result.setName(new XsNCName(getLocalPart(pName)));
708         XsGAttrDecls attrDecls;
709         if ("EMPTY".equals(pModel)) {
710             attrDecls = result.createComplexType();
711         } else if ("ANY".equals(pModel)) {
712             XsQName qName = XSAnyType.getInstance().getName();
713             qName = new XsQName(qName.getNamespaceURI(), qName.getLocalName(), "xs");
714             if (pAttributes.length == 0) {
715                 result.setType(qName);
716                 attrDecls = null;
717             } else {
718                 XsTComplexType complexType = result.createComplexType();
719                 XsEComplexContent complexContent = complexType.createComplexContent();
720                 XsTExtensionType extensionType = complexContent.createExtension();
721                 extensionType.setBase(qName);
722                 attrDecls = extensionType;
723             }
724         } else if (pModel.startsWith("(")) {
725             String JavaDoc pcData = pModel.substring(1).trim();
726             if (pcData.startsWith("#PCDATA")) {
727                 attrDecls = parseMixed(result, pModel, pLocator, pAttributes.length == 0);
728             } else {
729                 attrDecls = parseChildren(result, pModel, pLocator);
730             }
731         } else {
732             throw new SAXParseException JavaDoc("Invalid content model in element " + pName
733                                         + ", expected EMPTY|ANY|(...",
734                                         pLocator);
735         }
736         for (int i = 0; i < pAttributes.length; i++) {
737             createAttribute(attrDecls, pAttributes[i]);
738         }
739         return result;
740     }
741
742     /** Parses the given {@link org.xml.sax.InputSource} and
743      * converts it into an instance of
744      * {@link org.apache.ws.jaxme.xs.xml.XsESchema}.
745      */

746     protected void parse(XsESchema pSchema, InputSource JavaDoc pSource)
747             throws ParserConfigurationException JavaDoc, IOException JavaDoc, SAXException JavaDoc {
748         runXMLReader(pSource);
749         for (Iterator JavaDoc iter = elements.values().iterator(); iter.hasNext(); ) {
750             DTDElement element = (DTDElement) iter.next();
751             String JavaDoc name = element.getName();
752             String JavaDoc model = element.getModel();
753             DTDAttribute[] attrs = element.getAttributes();
754             if (attrs.length > 0 && model == null) {
755                 throw new SAXParseException JavaDoc("The element " + name
756                                             + " is referred by attribute "
757                                             + attrs[0].getName()
758                                             + ", but never declared.",
759                                             attrs[0].getLocator());
760             }
761             createElement(pSchema, name, model, element.getAttributes(),
762                           element.getLocator());
763         }
764     }
765
766     public XSSchema parse(InputSource JavaDoc pInputSource)
767             throws ParserConfigurationException JavaDoc, IOException JavaDoc, SAXException JavaDoc {
768         XsObjectFactoryImpl xsObjectFactory = new XsObjectFactoryImpl(){
769             public XSContext getContext() {
770                 return getData();
771             }
772         };
773         context = new XSContextImpl();
774         context.setXSLogicalParser(this);
775         context.setXsObjectFactory(xsObjectFactory);
776         clearSyntaxSchemas();
777         XsESchema syntaxSchema = new XsESchemaImpl(context){
778         };
779         parse(syntaxSchema, pInputSource);
780         XSSchema schema = context.getXSObjectFactory().newXSSchema(context, syntaxSchema);
781         setSchema(schema);
782         parse(syntaxSchema, pInputSource.getSystemId());
783         schema.validate();
784         return schema;
785     }
786
787     /** Sets the created schemas target namespace.
788      */

789     public void setTargetNamespace(XsAnyURI pTargetNamespace) {
790         targetNamespace = pTargetNamespace;
791     }
792
793     /** Returns the created schemas target namespace.
794      */

795     public XsAnyURI getTargetNamespace() {
796         return targetNamespace;
797     }
798 }
Popular Tags