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.util;
47
48 import java.util.Enumeration;
49 import java.util.Stack;
50 import java.util.Vector;
51
52 import org.exolab.castor.xml.Namespaces;
53 import org.exolab.castor.xml.schema.AttributeDecl;
54 import org.exolab.castor.xml.schema.ComplexType;
55 import org.exolab.castor.xml.schema.ContentType;
56 import org.exolab.castor.xml.schema.ElementDecl;
57 import org.exolab.castor.xml.schema.Group;
58 import org.exolab.castor.xml.schema.Order;
59 import org.exolab.castor.xml.schema.Particle;
60 import org.exolab.castor.xml.schema.Schema;
61 import org.exolab.castor.xml.schema.SchemaException;
62 import org.exolab.castor.xml.schema.Structure;
63 import org.exolab.castor.xml.schema.XMLType;
64 import org.xml.sax.AttributeList;
65 import org.xml.sax.DocumentHandler;
66 import org.xml.sax.Locator;
67 import org.xml.sax.SAXException;
68 import org.xml.sax.SAXParseException;
69
70
71
72
73
74
75
76
77
78
79 public final class XMLInstance2SchemaHandler
80 implements DocumentHandler, org.xml.sax.ErrorHandler
81 {
82
83
84 private static final String XMLNS = "xmlns";
85 private static final String DEFAULT_PREFIX = "xsd";
86
87
88
89
90
91
92
93 private Schema _schema = null;
94
95
96
97
98 private Stack _siStack = null;
99
100 private String _nsPrefix = null;
101
102 private Order _defaultGroupOrder = Order.sequence;
103
104
105
106
107
108
109
110
111
112 public XMLInstance2SchemaHandler() {
113 this(null);
114 }
115
116
117
118
119
120 public XMLInstance2SchemaHandler(Schema schema) {
121 super();
122
123 _siStack = new Stack();
124
125 _schema = schema;
126
127 if (_schema == null) {
128 _schema = new Schema();
129 _schema.addNamespace(DEFAULT_PREFIX, Schema.DEFAULT_SCHEMA_NS);
130 _nsPrefix = DEFAULT_PREFIX;
131 }
132
133 else {
134 _nsPrefix = null;
135 Namespaces namespaces = _schema.getNamespaces();
136 Enumeration enumeration = namespaces.getLocalNamespacePrefixes();
137 while (enumeration.hasMoreElements()) {
138 String key = (String) enumeration.nextElement();
139 if (namespaces.getNamespaceURI(key).equals(Schema.DEFAULT_SCHEMA_NS)) {
140 _nsPrefix = key;
141 break;
142 }
143 }
144 if (_nsPrefix == null) {
145 _schema.addNamespace(DEFAULT_PREFIX, Schema.DEFAULT_SCHEMA_NS);
146 _nsPrefix = DEFAULT_PREFIX;
147 }
148 }
149 }
150
151
152
153
154
155
156
157
158
159
160 public Schema getSchema() {
161 return _schema;
162 }
163
164
165
166
167
168
169
170 protected void setDefaultGroupOrder(Order order) {
171 _defaultGroupOrder = order;
172 }
173
174
175
176
177
178 public void characters(char[] ch, int start, int length)
179 throws org.xml.sax.SAXException
180 {
181 if (_siStack.isEmpty()) return;
182
183 StateInfo sInfo = (StateInfo)_siStack.peek();
184
185 if (sInfo.buffer == null) {
186 sInfo.buffer = new StringBuffer();
187 }
188 sInfo.buffer.append(ch, start, length);
189
190 if (sInfo.complex) {
191 sInfo.mixed = true;
192 }
193 }
194
195 public void endDocument()
196 throws org.xml.sax.SAXException
197 {
198
199
200 }
201
202 public void endElement(String name)
203 throws org.xml.sax.SAXException
204 {
205
206
207 int idx = name.indexOf(':');
208 if (idx >= 0) {
209 name = name.substring(idx+1);
210 }
211
212 StateInfo sInfo = (StateInfo) _siStack.pop();
213
214
215
216
217 if ((sInfo.element.getType() == null) && (sInfo.buffer != null)) {
218
219
220 String typeName = _nsPrefix + ':' +
221 DatatypeHandler.guessType(sInfo.buffer.toString());
222 sInfo.element.setTypeReference(typeName);
223
224 if (sInfo.attributes.size() > 0) {
225 ComplexType cType = new ComplexType(_schema);
226
227
228 cType.setContentType(ContentType.mixed);
229 sInfo.element.setType(cType);
230 Group group = new Group();
231 group.setOrder(_defaultGroupOrder);
232
233 try {
234 cType.addGroup(group);
235 for (int i = 0; i < sInfo.attributes.size(); i++) {
236 AttributeDecl attDecl =
237 (AttributeDecl)sInfo.attributes.elementAt(i);
238 cType.addAttributeDecl(attDecl);
239 }
240 }
241 catch(SchemaException sx) {
242 throw new SAXException(sx);
243 }
244 }
245 }
246 else {
247 ComplexType cType = (ComplexType)sInfo.element.getType();
248
249 if ((cType == null) && (sInfo.attributes.size() > 0)) {
250 cType = new ComplexType(_schema);
251 sInfo.element.setType(cType);
252 Group group = new Group();
253 group.setOrder(_defaultGroupOrder);
254
255 try {
256 cType.addGroup(group);
257 }
258 catch(SchemaException sx) {
259 throw new SAXException(sx);
260 }
261 }
262
263 if (cType != null) {
264 for (int i = 0; i < sInfo.attributes.size(); i++) {
265 AttributeDecl attDecl =
266 (AttributeDecl)sInfo.attributes.elementAt(i);
267 cType.addAttributeDecl(attDecl);
268 }
269 }
270 }
271
272
273 if (!_siStack.isEmpty()) {
274 StateInfo parentInfo = (StateInfo)_siStack.peek();
275 ComplexType type = (ComplexType) parentInfo.element.getType();
276 Group group = null;
277 if ((type == null) || (type.getParticleCount() == 0)) {
278 if (type == null) {
279 parentInfo.complex = true;
280 type = new ComplexType(_schema);
281 parentInfo.element.setType(type);
282 }
283 group = new Group();
284 group.setOrder(_defaultGroupOrder);
285 try {
286 type.addGroup(group);
287
288 group.addElementDecl(sInfo.element);
289 }
290 catch(SchemaException sx) {
291 throw new SAXException(sx);
292 }
293 }
294 else {
295 group = (Group) type.getParticle(0);
296
297
298 ElementDecl element = group.getElementDecl(name);
299 boolean checkGroupType = false;
300 if (element != null) {
301
302 if (sInfo.complex) {
303 try {
304 merge(element, sInfo.element);
305 }
306 catch(SchemaException sx) {
307 throw new SAXException(sx);
308 }
309 }
310 element.setMaxOccurs(Particle.UNBOUNDED);
311 checkGroupType = true;
312 }
313 else {
314 try {
315 group.addElementDecl(sInfo.element);
316 }
317 catch(SchemaException sx) {
318 throw new SAXException(sx);
319 }
320 }
321
322
323 if (checkGroupType && (group.getOrder() == Order.sequence)) {
324
325
326 boolean found = false;
327 boolean changeType = false;
328 for (int i = 0; i < group.getParticleCount(); i++) {
329 if (found) {
330 changeType = true;
331 break;
332 }
333 if (element == group.getParticle(i)) found = true;
334 }
335 if (changeType) {
336 group.setOrder(Order.all);
337 }
338 }
339 }
340 }
341 else {
342 try {
343 _schema.addElementDecl(sInfo.element);
344
345
346
347
348
349
350
351
352
353 }
354 catch(SchemaException sx) {
355 throw new SAXException(sx);
356 }
357 }
358
359 }
360
361
362 public void ignorableWhitespace(char[] ch, int start, int length)
363 throws org.xml.sax.SAXException
364 {
365
366
367 }
368
369 public void processingInstruction(String target, String data)
370 throws org.xml.sax.SAXException
371 {
372
373
374 }
375
376 public void setDocumentLocator(final Locator locator) { }
377
378 public void startDocument()
379 throws org.xml.sax.SAXException
380 {
381
382
383 }
384
385
386 public void startElement(String name, AttributeList atts)
387 throws org.xml.sax.SAXException
388 {
389
390
391 int idx = name.indexOf(':');
392 if (idx >= 0) {
393 name = name.substring(idx+1);
394 }
395
396 StateInfo sInfo = null;
397
398 boolean topLevel = false;
399
400
401 if (!_siStack.isEmpty()) {
402 sInfo = (StateInfo)_siStack.peek();
403 sInfo.complex = true;
404 }
405 else {
406 topLevel = true;
407 }
408
409
410 sInfo = new StateInfo();
411 sInfo.topLevel = topLevel;
412 _siStack.push(sInfo);
413
414
415 sInfo.element = new ElementDecl(_schema, name);
416
417
418 for (int i = 0; i < atts.getLength(); i++) {
419
420 String attName = atts.getName(i);
421
422
423 if (attName.equals(XMLNS)) continue;
424 String prefix = "";
425 idx = attName.indexOf(':');
426 if (idx >= 0) {
427 prefix = attName.substring(0, idx);
428 attName = attName.substring(idx+1);
429 }
430 if (prefix.equals(XMLNS)) continue;
431
432 AttributeDecl attr = new AttributeDecl(_schema, attName);
433
434
435 String typeName = _nsPrefix + ':' +
436 DatatypeHandler.guessType(atts.getValue(i));
437
438 attr.setSimpleTypeReference(typeName);
439
440 sInfo.attributes.addElement(attr);
441 }
442
443 }
444
445
446
447
448
449
450 public void error(SAXParseException exception)
451 throws org.xml.sax.SAXException
452 {
453 throw exception;
454
455 }
456
457 public void fatalError(SAXParseException exception)
458 throws org.xml.sax.SAXException
459 {
460 throw exception;
461
462 }
463
464
465 public void warning(SAXParseException exception)
466 throws org.xml.sax.SAXException
467 {
468 throw exception;
469
470 }
471
472
473
474
475
476
477
478
479
480
481
482
483 private void merge(ElementDecl e1, ElementDecl e2)
484 throws SchemaException
485 {
486
487 XMLType e1Type = e1.getType();
488 XMLType e2Type = e2.getType();
489
490
491 if (e1Type == null) {
492 if (e2Type == null) return;
493 if (e2Type.isSimpleType()) {
494 e1.setType(e2Type);
495 }
496 else {
497 ComplexType cType = new ComplexType(_schema);
498 Group group = new Group();
499 group.setOrder(_defaultGroupOrder);
500 cType.addGroup(group);
501 e1.setType(cType);
502 e1Type = cType;
503 }
504 }
505 else if (e2Type == null) {
506 if (e1Type.isSimpleType()) {
507 e2.setType(e1Type);
508 }
509 else {
510 ComplexType cType = new ComplexType(_schema);
511 Group group = new Group();
512 group.setOrder(_defaultGroupOrder);
513 cType.addGroup(group);
514 e2.setType(cType);
515 e2Type = cType;
516 }
517 }
518
519
520 if (e1Type.isSimpleType() && e2Type.isSimpleType()) {
521 if (!e1Type.getName().equals(e2Type.getName())) {
522 String typeName = _nsPrefix + ':' +
523 DatatypeHandler.whichType(e1Type.getName(),
524 e2Type.getName());
525 e1.setType(null);
526 e1.setTypeReference(typeName);
527 }
528 return;
529 }
530
531 else if (e1Type.isSimpleType()) {
532 ComplexType cType = new ComplexType(_schema);
533 e1.setType(cType);
534 Group group = new Group();
535 group.setOrder(_defaultGroupOrder);
536 cType.addGroup(group);
537 cType.setContentType(ContentType.mixed);
538 e1Type = cType;
539
540
541 }
542
543 else if (e2Type.isSimpleType()) {
544 ComplexType cType = new ComplexType(_schema);
545 e2.setType(cType);
546 Group group = new Group();
547 group.setOrder(_defaultGroupOrder);
548 cType.addGroup(group);
549 cType.setContentType(ContentType.mixed);
550 e2Type = cType;
551
552
553 }
554
555
556 ComplexType cType1 = (ComplexType)e1Type;
557 ComplexType cType2 = (ComplexType)e2Type;
558
559
560
561
562
563 Group e1Group = (Group) cType1.getParticle(0);
564 if (e1Group == null) {
565 e1Group = new Group();
566 e1Group.setOrder(_defaultGroupOrder);
567 cType1.addGroup(e1Group);
568
569 }
570 Group e2Group = (Group) cType2.getParticle(0);
571 if (e2Group == null) {
572 e2Group = new Group();
573 e2Group.setOrder(_defaultGroupOrder);
574 cType2.addGroup(e2Group);
575
576 }
577
578 Enumeration enumeration = e2Group.enumerate();
579 while (enumeration.hasMoreElements()) {
580 Particle particle = (Particle)enumeration.nextElement();
581 if (particle.getStructureType() == Structure.ELEMENT) {
582 ElementDecl element = (ElementDecl)particle;
583 ElementDecl main = e1Group.getElementDecl(element.getName());
584 if (main == null) {
585 e1Group.addElementDecl(element);
586 element.setMinOccurs(0);
587 }
588 else {
589 merge(main, element);
590 }
591 }
592 }
593
594 enumeration = cType2.getAttributeDecls();
595
596 while (enumeration.hasMoreElements()) {
597
598 AttributeDecl attNew = (AttributeDecl)enumeration.nextElement();
599
600 String attName = attNew.getName();
601 AttributeDecl attPrev = cType1.getAttributeDecl(attName);
602 if (attPrev == null) {
603 attNew.setUse(AttributeDecl.USE_OPTIONAL);
604 cType1.addAttributeDecl(attNew);
605 }
606 else {
607 String type1 = attPrev.getSimpleType().getName();
608 String type2 = attNew.getSimpleType().getName();
609 if (!type1.equals(type2)) {
610 String typeName = _nsPrefix + ':' +
611 DatatypeHandler.whichType(type1, type2);
612 attPrev.setSimpleTypeReference(typeName); }
613 }
614 }
615
616
617
618
619 enumeration = e1Group.enumerate();
620 while (enumeration.hasMoreElements()) {
621 Particle particle = (Particle)enumeration.nextElement();
622 if (particle.getStructureType() == Structure.ELEMENT) {
623 ElementDecl element = (ElementDecl)particle;
624 if (e2Group.getElementDecl(element.getName()) == null) {
625 element.setMinOccurs(0);
626 }
627 }
628 }
629
630
631 }
632
633
634
635
636 class StateInfo {
637 Namespaces namespaces = null;
638 ElementDecl element = null;
639 Vector attributes = null;
640 StringBuffer buffer = null;
641 boolean mixed = false;
642 boolean complex = false;
643 boolean topLevel = false;
644
645 public StateInfo() {
646 super();
647 attributes = new Vector();
648 }
649
650 }
651
652 }
653
654