1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36 package org.exolab.castor.xml.schema.reader;
37
38
39 import org.exolab.castor.xml.AttributeSet;
40 import org.exolab.castor.xml.Namespaces;
41 import org.exolab.castor.xml.XMLException;
42 import org.exolab.castor.xml.schema.Annotation;
43 import org.exolab.castor.xml.schema.ElementDecl;
44 import org.exolab.castor.xml.schema.Form;
45 import org.exolab.castor.xml.schema.IdentityConstraint;
46 import org.exolab.castor.xml.schema.Schema;
47 import org.exolab.castor.xml.schema.SchemaContext;
48 import org.exolab.castor.xml.schema.SchemaException;
49 import org.exolab.castor.xml.schema.SchemaNames;
50 import org.exolab.castor.xml.schema.XMLType;
51
52
53
54
55
56
57
58
59 public class ElementUnmarshaller extends ComponentReader {
60
61
62
63
64 private static final String MAX_OCCURS_WILDCARD = "unbounded";
65
66
67
68
69
70
71
72
73 private ComponentReader unmarshaller;
74
75
76
77
78 private int depth = 0;
79
80
81
82
83 private ElementDecl _element = null;
84
85
86 private CharacterUnmarshaller charUnmarshaller = null;
87
88 private Schema _schema = null;
89
90 private boolean foundAnnotation = false;
91 private boolean foundIdentityConstraint = false;
92 private boolean foundSimpleType = false;
93 private boolean foundComplexType = false;
94 private boolean foundTypeReference = false;
95
96
97
98
99
100
101
102
103
104
105
106
107 public ElementUnmarshaller(final SchemaContext schemaContext, final Schema schema,
108 final AttributeSet atts) throws XMLException {
109 super(schemaContext);
110
111 this._schema = schema;
112
113 _element = new ElementDecl(schema);
114
115 String attValue = null;
116
117
118 attValue = atts.getValue(SchemaNames.REF_ATTR);
119 if (attValue != null) {
120 _element.setReferenceName(attValue);
121
122 if (atts.getValue(SchemaNames.NAME_ATTR) != null) {
123 error("The attributes 'ref' and 'name' appearing on "
124 + "element declarations are mutually exclusive.");
125 }
126 validateRefAtts(atts);
127 }
128
129 else {
130 _element.setName(atts.getValue(SchemaNames.NAME_ATTR));
131 }
132
133
134 attValue = atts.getValue(SchemaNames.ABSTRACT);
135 if (attValue != null) {
136 _element.setAbstract(Boolean.parseBoolean(attValue));
137 }
138
139
140 _element.setBlock(atts.getValue(SchemaNames.BLOCK_ATTR));
141
142
143 attValue = atts.getValue(SchemaNames.DEFAULT_ATTR);
144 if (attValue != null) {
145 if (_element.getFixedValue() != null)
146 error("'default' and 'fixed' must not both be present.");
147 _element.setDefaultValue(attValue);
148 }
149
150
151 _element.setFinal(atts.getValue(SchemaNames.FINAL_ATTR));
152
153
154 final boolean isAbstract = Boolean.parseBoolean(atts.getValue(SchemaNames.ABSTRACT));
155 if (isAbstract) {
156 _element.setAbstract(isAbstract);
157 }
158
159
160 attValue = atts.getValue(SchemaNames.FIXED_ATTR);
161 if (attValue != null) {
162 if (_element.getDefaultValue() != null)
163 throw new IllegalArgumentException("'default' and 'fixed' must not both be present.");
164 _element.setFixedValue(attValue);
165 }
166
167
168 attValue = atts.getValue(SchemaNames.FORM);
169 if (attValue != null) {
170 _element.setForm(Form.valueOf(attValue));
171 }
172
173
174 _element.setId(atts.getValue(SchemaNames.ID_ATTR));
175
176
177 attValue = atts.getValue(SchemaNames.SUBSTITUTION_GROUP_ATTR);
178 if (attValue != null) {
179 _element.setSubstitutionGroup(attValue);
180 }
181
182
183 attValue = atts.getValue(SchemaNames.TYPE_ATTR);
184 if (attValue != null) {
185 foundTypeReference = true;
186 _element.setTypeReference(attValue);
187 }
188
189
190
191 attValue = atts.getValue(SchemaNames.NILLABLE_ATTR);
192 if (attValue != null) {
193 if (attValue.equals("true") || attValue.equals("1")) {
194 _element.setNillable(true);
195 } else if (!attValue.equals("false") && !attValue.equals("0")) {
196 String err =
197 "Invalid value for the 'nillable' attribute of " + "an element definition: " + attValue;
198 throw new IllegalArgumentException(err);
199 }
200 }
201
202
203
204
205
206 attValue = atts.getValue(SchemaNames.MIN_OCCURS_ATTR);
207 int minOccurs = 1;
208 if (attValue != null) {
209 minOccurs = toInt(attValue);
210 _element.setMinOccurs(minOccurs);
211 }
212
213
214
215
216
217 attValue = atts.getValue(SchemaNames.MAX_OCCURS_ATTR);
218 if (attValue != null) {
219 if (MAX_OCCURS_WILDCARD.equals(attValue))
220 attValue = "-1";
221 int maxOccurs = toInt(attValue);
222 _element.setMaxOccurs(maxOccurs);
223 } else if (minOccurs > 1)
224 _element.setMaxOccurs(minOccurs);
225
226 charUnmarshaller = new CharacterUnmarshaller(getSchemaContext());
227 }
228
229
230
231
232
233
234
235
236
237
238 public String elementName() {
239 return SchemaNames.ELEMENT;
240 }
241
242
243
244
245 public ElementDecl getElement() {
246 return _element;
247 }
248
249
250
251
252
253
254 public Object getObject() {
255 return _element;
256 }
257
258
259
260
261
262
263
264
265
266
267
268 public void startElement(String name, String namespace, AttributeSet atts, Namespaces nsDecls)
269 throws XMLException {
270
271
272 if (unmarshaller != null) {
273 unmarshaller.startElement(name, namespace, atts, nsDecls);
274 ++depth;
275 return;
276 }
277
278 if (SchemaNames.ANNOTATION.equals(name)) {
279 if (foundSimpleType || foundIdentityConstraint || foundComplexType)
280 error("An annotation may only appear as the first child " + "of an element definition.");
281
282
283 if (foundAnnotation)
284 error("Only one (1) 'annotation' is allowed as a child of " + "element definitions.");
285
286 foundAnnotation = true;
287 unmarshaller = new AnnotationUnmarshaller(getSchemaContext(), atts);
288 } else if (SchemaNames.COMPLEX_TYPE.equals(name)) {
289
290 if (foundComplexType)
291 error("Only one (1) 'complexType' may appear in an " + "element definition.");
292 if (foundSimpleType)
293 error("Both 'simpleType' and 'complexType' cannot appear "
294 + "in the same element definition.");
295 if (foundTypeReference)
296 error("Both 'type' attribute and 'complexType' element "
297 + "cannot appear in the same element definition.");
298
299
300 if (foundIdentityConstraint)
301 error("A 'complexType' must appear before 'key', " + "'keyref' and 'unique' elements.");
302
303 foundComplexType = true;
304 unmarshaller = new ComplexTypeUnmarshaller(getSchemaContext(), _schema, atts);
305 } else if (SchemaNames.SIMPLE_TYPE.equals(name)) {
306
307 if (foundSimpleType)
308 error("Only one (1) 'simpleType' may appear in an " + "element definition.");
309 if (foundComplexType)
310 error("Both 'simpleType' and 'complexType' cannot appear "
311 + "in the same element definition.");
312 if (foundTypeReference)
313 error("Both 'type' attribute and 'simpleType' element "
314 + "cannot appear in the same element definition.");
315
316 if (foundIdentityConstraint)
317 error("A 'simpleType' must appear before 'key', " + "'keyref' and 'unique' elements.");
318
319 foundSimpleType = true;
320 unmarshaller = new SimpleTypeUnmarshaller(getSchemaContext(), _schema, atts);
321 } else if (SchemaNames.KEY.equals(name) || SchemaNames.KEYREF.equals(name)
322 || SchemaNames.UNIQUE.equals(name)) {
323 foundIdentityConstraint = true;
324 unmarshaller = new IdentityConstraintUnmarshaller(getSchemaContext(), name, atts);
325 } else
326 illegalElement(name);
327
328 }
329
330
331
332
333
334
335
336
337 public void endElement(String name, String namespace) throws XMLException {
338
339
340 if ((unmarshaller != null) && (depth > 0)) {
341 unmarshaller.endElement(name, namespace);
342 --depth;
343 return;
344 }
345
346
347 if ((unmarshaller != null) && (charUnmarshaller != unmarshaller)) {
348 if (!name.equals(unmarshaller.elementName())) {
349 String err = "missing end element for ";
350 err += unmarshaller.elementName();
351 throw new SchemaException(err);
352 }
353 }
354
355
356 unmarshaller.finish();
357
358 if (SchemaNames.ANNOTATION.equals(name)) {
359 Annotation ann = (Annotation) unmarshaller.getObject();
360 _element.addAnnotation(ann);
361 } else if (SchemaNames.COMPLEX_TYPE.equals(name)) {
362
363 XMLType xmlType = ((ComplexTypeUnmarshaller) unmarshaller).getComplexType();
364
365 _element.setType(xmlType);
366
367 } else if (SchemaNames.SIMPLE_TYPE.equals(name)) {
368 XMLType xmlType = ((SimpleTypeUnmarshaller) unmarshaller).getSimpleType();
369 _element.setType(xmlType);
370 } else if (SchemaNames.KEY.equals(name) || SchemaNames.KEYREF.equals(name)
371 || SchemaNames.UNIQUE.equals(name)) {
372 IdentityConstraint constraint = (IdentityConstraint) unmarshaller.getObject();
373 _element.addIdentityConstraint(constraint);
374 }
375
376 unmarshaller = null;
377
378 }
379
380 public void characters(char[] ch, int start, int length) throws XMLException {
381
382 if (unmarshaller != null) {
383 unmarshaller.characters(ch, start, length);
384 }
385 }
386
387
388
389
390
391
392 private static void validateRefAtts(AttributeSet atts) throws XMLException {
393
394 StringBuffer errors = null;
395
396 for (int i = 0; i < atts.getSize(); i++) {
397 String name = atts.getName(i);
398 if (SchemaNames.REF_ATTR.equals(name))
399 continue;
400 else if (SchemaNames.MAX_OCCURS_ATTR.equals(name))
401 continue;
402 else if (SchemaNames.MIN_OCCURS_ATTR.equals(name))
403 continue;
404 else if (SchemaNames.ID_ATTR.equals(name))
405 continue;
406 else {
407
408 String namespace = atts.getNamespace(i);
409
410
411
412 if ((namespace == null) || (namespace.length() == 0)
413 || namespace.equals(SchemaUnmarshaller.XSD_NAMESPACE)) {
414
415 String error = "The attribute '" + name + "' must not appear on an element reference.";
416 if (errors == null)
417 errors = new StringBuffer(error);
418 else
419 errors.append(error);
420
421 errors.append(System.getProperty("line.separator"));
422
423
424 }
425
426
427 }
428 }
429
430 if (errors != null)
431 throw new XMLException(errors.toString());
432
433 }
434
435 }