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