KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > ant > internal > ui > dtd > schema > SchemaFactory


1 /*******************************************************************************
2  * Copyright (c) 2002, 2005 Object Factory Inc.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * Object Factory Inc. - Initial implementation
10  * IBM Corporation - Fix for bug 40951
11  *******************************************************************************/

12 package org.eclipse.ant.internal.ui.dtd.schema;
13
14 import com.ibm.icu.text.MessageFormat;
15 import java.util.HashSet JavaDoc;
16 import java.util.LinkedList JavaDoc;
17
18 import org.eclipse.ant.internal.ui.dtd.IModel;
19 import org.eclipse.ant.internal.ui.dtd.ISchema;
20 import org.xml.sax.SAXException JavaDoc;
21 import org.xml.sax.ext.DeclHandler JavaDoc;
22
23 /**
24  * SchemaFactory is a SAX DeclHandler that converts DTD ELEMENT and ATTLIST
25  * declarations to schema form on the fly. The only two methods available to
26  * external users of SchemaFactory are its constructor and
27  * <code>getSchema()</code>. The latter returns the schema built by this process
28  * and should not be called until the XML parser to which this handler is
29  * attached has finished parsing.
30  * @author Bob Foster
31  */

32 public class SchemaFactory implements DeclHandler JavaDoc {
33     // used for parsing models
34
private char[] fBuf;
35     private int fLen;
36     private int fPos;
37     private Element fElement;
38     
39     private Schema fSchema;
40     private static HashSet JavaDoc fTypes = new HashSet JavaDoc();
41     private Exception JavaDoc fErrorException;
42     static {
43         fTypes.add("CDATA"); //$NON-NLS-1$
44
fTypes.add("ID"); //$NON-NLS-1$
45
fTypes.add("IDREF"); //$NON-NLS-1$
46
fTypes.add("IDREFS"); //$NON-NLS-1$
47
fTypes.add("NMTOKEN"); //$NON-NLS-1$
48
fTypes.add("NMTOKENS"); //$NON-NLS-1$
49
fTypes.add("ENTITY"); //$NON-NLS-1$
50
fTypes.add("ENTITIES"); //$NON-NLS-1$
51
}
52     
53     /**
54      * Constructor.
55      */

56     public SchemaFactory() {
57         fSchema = new Schema();
58     }
59     
60     /**
61      * @return ISchema produced from the DeclHandler. The schema is always
62      * correct, though it may be incomplete if the parse was interrupted due to
63      * validation or well-formed errors.
64      */

65     public ISchema getSchema() {
66         fSchema.setErrorException(fErrorException);
67         return fSchema;
68     }
69     
70     /**
71      * @see org.xml.sax.ext.DeclHandler#attributeDecl(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String)
72      */

73     public void attributeDecl(String JavaDoc eName, String JavaDoc aName, String JavaDoc type, String JavaDoc valueDefault, String JavaDoc value) {
74         Element element = getElement(eName);
75         Attribute attr = (Attribute) element.getAttributes().get(aName);
76         if (attr == null) {
77             attr = new Attribute(aName, element);
78             element.addAttribute(attr);
79             
80             String JavaDoc[] enumeration = null;
81             if (fTypes.contains(type))
82                 attr.setType(type);
83             else if (type.startsWith("NOTATION")) //$NON-NLS-1$
84
enumeration = parseValues(type.substring("NOTATION".length()+1), ','); //$NON-NLS-1$
85
else {
86                 type = stripSurroundingParentheses(type);
87                 enumeration = parseValues(type, '|');
88             }
89             attr.setEnum(enumeration);
90             
91             attr.setRequired(valueDefault == null || !valueDefault.equals("#IMPLIED")); //$NON-NLS-1$
92
attr.setFixed(valueDefault != null && valueDefault.equals("#FIXED")); //$NON-NLS-1$
93
attr.setDefault(value);
94         }
95     }
96     
97
98     /**
99      * Strips the surrounding parentheses from <code>aString</code>.
100      * <P>
101      * i.e.: (true|false) -> true|false
102      */

103     private String JavaDoc stripSurroundingParentheses(String JavaDoc aString) {
104         if(aString.startsWith("(")) { //$NON-NLS-1$
105
aString = aString.substring(1);
106         }
107         if(aString.endsWith(")")) { //$NON-NLS-1$
108
aString = aString.substring(0, aString.length()-1);
109         }
110         return aString;
111     }
112     
113     
114     /**
115      * @param eName Element name
116      * @return Element from schema or new element. Either way
117      * the element is in the schema upon return.
118      */

119     private Element getElement(String JavaDoc eName) {
120         Element element = (Element) fSchema.getElement(eName);
121         if (element == null) {
122             element = new Element(eName);
123             fSchema.addElement(element);
124         }
125         return element;
126     }
127
128     private String JavaDoc[] parseValues(String JavaDoc type, char separator) {
129         int start = 0, pos, len = type.length();
130         LinkedList JavaDoc values = new LinkedList JavaDoc();
131         while (start < len) {
132             pos = type.indexOf(separator, start);
133             if (pos < 0) pos = len;
134             String JavaDoc term = type.substring(start, pos);
135             start = pos + 1;
136             values.add(term);
137         }
138         return (String JavaDoc[]) values.toArray(new String JavaDoc[values.size()]);
139     }
140
141     /**
142      * @see org.xml.sax.ext.DeclHandler#elementDecl(java.lang.String, java.lang.String)
143      */

144     public void elementDecl(String JavaDoc name, String JavaDoc model) throws SAXException JavaDoc {
145         Element element = getElement(name);
146         if (!element.isUndefined()) {
147             // if the element has already been defined, this is an error
148
throw new SAXException JavaDoc(MessageFormat.format(AntDTDSchemaMessages.SchemaFactory_Doubly_defined, new String JavaDoc[]{name}));
149         }
150         
151         fElement = element;
152         if (model.equals("ANY")) { //$NON-NLS-1$
153
element.setAny(true);
154         } else if (model.equals("EMPTY")) { //$NON-NLS-1$
155
element.setEmpty(true);
156         } else if (model.equals("(#PCDATA)")) {//$NON-NLS-1$
157
element.setText(true);
158         } else {
159             element.setContentModel(parseModel(model));
160         }
161     }
162
163     /**
164      * Convert model string to IModel. The <code>fElement</code>
165      * variable is an implicit argument to this method, and it
166      * sets <code>fBuf</code>, <code>fPos</code> and <code>fLen</code> for use
167      * by other parser methods.
168      * @param model String from DTD, with parameter entities replaced.
169      * @return IModel
170      * @throws SAXException if syntax error detected in model. This is a
171      * validation error. Since the DTD is usually not read unless the parser is
172      * validating, we may not ever be handed a bad content model, but we need to
173      * check them, just the same.
174      */

175     private IModel parseModel(String JavaDoc model) throws SAXException JavaDoc {
176         fBuf = model.toCharArray();
177         fLen = fBuf.length;
178         if (fBuf[0] != '(') {
179             throw new SAXException JavaDoc(
180                 MessageFormat.format(AntDTDSchemaMessages.SchemaFactory_Start_with_left_parenthesis, new String JavaDoc[]{fElement.getName()}));
181         }
182
183         boolean ortext = model.startsWith("(#PCDATA|"); //$NON-NLS-1$
184
if (ortext) {
185             fPos = 8; //"(#PCDATA".length()
186
} else {
187             fPos = 0;
188         }
189         IModel emodel= scanExpr();
190         return emodel;
191     }
192
193     /**
194      * Scan a parenthesized expression starting
195      * from the left parenthesis or leftmost operator.
196      * @return IModel
197      */

198     private IModel scanExpr() throws SAXException JavaDoc {
199         // skip opening ( or |
200
fPos++;
201         return scanExpr(scanElement());
202     }
203     
204     /**
205      * Scan a parenthesized expression with the
206      * first term in hand.
207      * @param term The first operand in the expression, pre-scanned.
208      * @return IModel
209      * @throws SAXException if errors are detected in the model.
210      */

211     private IModel scanExpr(IModel term) throws SAXException JavaDoc {
212         checkLen();
213         if (fBuf[fPos] != ')') {
214             char op = fBuf[fPos];
215             if (op != '|' && op != ',') {
216                 throw new SAXException JavaDoc(
217                     MessageFormat.format(AntDTDSchemaMessages.SchemaFactory_Expecting_operator_or_right_parenthesis,
218                         new String JavaDoc[]{fElement.getName(),String.valueOf(fBuf)}));
219             }
220             Model model = new Model(op == '|' ? IModel.CHOICE : IModel.SEQUENCE);
221             model.addModel(term);
222             term = model;
223             
224             while (fBuf[fPos] == op) {
225                 fPos++;
226                 IModel next = scanElement();
227                 model.addModel(next);
228             }
229             if (fBuf[fPos] != ')') {
230                 throw new SAXException JavaDoc(
231                         MessageFormat.format(AntDTDSchemaMessages.SchemaFactory_Expecting_operator_or_right_parenthesis,
232                         new String JavaDoc[]{fElement.getName(), String.valueOf(fBuf)}));
233             }
234             fPos++;
235         }
236         return term;
237     }
238
239     /**
240      * Scan an element name or a parenthesized sub-expression.
241      * @return IModel
242      * @throws SAXException
243      */

244     private IModel scanElement() throws SAXException JavaDoc {
245         checkLen();
246         if (fBuf[fPos] == '(')
247             return scanExpr();
248         StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
249         while (fBuf[fPos] != '|' && fBuf[fPos] != ',' && fBuf[fPos] != ')'
250         && fBuf[fPos] != '*' && fBuf[fPos] != '+' && fBuf[fPos] != '?' ) {
251             sb.append(fBuf[fPos++]);
252             checkLen();
253         }
254         String JavaDoc name = sb.toString();
255         Element element = getElement(name);
256         Model model = new Model(IModel.LEAF);
257         model.setLeaf(element);
258         return model;
259     }
260
261     private void checkLen() throws SAXException JavaDoc {
262         if (fPos == fLen) {
263             throw new SAXException JavaDoc(
264                 MessageFormat.format(AntDTDSchemaMessages.SchemaFactory_Unexpected_end,
265                     new String JavaDoc[]{fElement.getName(),
266                         String.valueOf(fBuf)}));
267         }
268     }
269
270     /**
271      * @see org.xml.sax.ext.DeclHandler#externalEntityDecl(java.lang.String, java.lang.String, java.lang.String)
272      */

273     public void externalEntityDecl(String JavaDoc name, String JavaDoc publicId, String JavaDoc systemId) {
274     }
275
276     /**
277      * @see org.xml.sax.ext.DeclHandler#internalEntityDecl(java.lang.String, java.lang.String)
278      */

279     public void internalEntityDecl(String JavaDoc name, String JavaDoc value) {
280     }
281
282     public void setErrorException(Exception JavaDoc e) {
283         fErrorException = e;
284     }
285 }
286
Popular Tags