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.types;
37
38 import java.io.StringWriter;
39 import java.util.Stack;
40
41 import org.castor.xml.BackwardCompatibilityContext;
42 import org.exolab.castor.xml.Serializer;
43 import org.exolab.castor.xml.util.AnyNode2SAX;
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63 public final class AnyNode implements java.io.Serializable {
64
65
66
67
68 private static final long serialVersionUID = -4104117996051705975L;
69
70
71
72
73 private final static String XMLNS_PREFIX = "xmlns";
74
75
76
77
78 public static final short ELEMENT = 1;
79
80
81
82
83 public static final short ATTRIBUTE = 2;
84
85
86
87
88 public static final short NAMESPACE = 3;
89
90
91
92
93 public static final short PI = 4;
94
95
96
97
98 public static final short COMMENT = 5;
99
100
101
102
103 public static final short TEXT = 6;
104
105
106
107
108 private short _nodeType = ELEMENT;
109
110
111
112
113 private AnyNode _nextSiblingNode = null;
114
115
116
117
118 private AnyNode _firstChildNode = null;
119
120
121
122
123
124 private String _localName;
125
126
127
128
129 private String _uri;
130
131
132
133
134 private String _prefix;
135
136
137
138
139 private static Stack<AnyNode> _elements;
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156 private String _value;
157
158
159
160
161 public AnyNode() {
162 this(ELEMENT, null, null, null, null);
163 }
164
165
166
167
168
169
170
171
172
173
174
175
176 public AnyNode(short type, String localName, String prefix, String uri, String value) {
177 if ((type > 6) && (type < 1)) {
178 throw new IllegalArgumentException("Illegal node type");
179 }
180 _nodeType = type;
181
182
183 if ((type > PI) && (localName != null)) {
184 String err = "This node can not have a local name";
185 throw new IllegalArgumentException(err);
186 }
187 _localName = localName;
188
189
190 if ((type > NAMESPACE) && ((uri != null) || (prefix != null))) {
191 String err = "This node can not handle namespace";
192 throw new IllegalArgumentException(err);
193 }
194 _uri = uri;
195 _prefix = prefix;
196
197
198 if (type == AnyNode.ATTRIBUTE)
199 if (localName.startsWith(XMLNS_PREFIX)) {
200 String err = "Namespaces can't be used as attributes.";
201 throw new IllegalArgumentException(err);
202 }
203
204
205 if ((type == ELEMENT) && (value != null)) {
206 String err = "You can't set a value for this node type";
207 throw new IllegalArgumentException(err);
208 }
209 _value = value;
210 }
211
212
213
214
215
216
217 public void addAnyNode(AnyNode node) {
218 if (node == null) {
219 throw new IllegalArgumentException("null argument in addAnyNode");
220 }
221
222 switch (node.getNodeType()) {
223 case ATTRIBUTE:
224 addAttribute(node);
225 break;
226 case NAMESPACE:
227 addNamespace(node);
228 break;
229 default:
230 addChild(node);
231 break;
232 }
233 }
234
235
236
237
238
239
240
241
242
243
244
245 public void addChild(AnyNode node) {
246 if (node == null) {
247 throw new IllegalArgumentException("null argument in appendChild");
248 }
249
250 if (node.getNodeType() == ATTRIBUTE || node.getNodeType() == NAMESPACE) {
251 throw new IllegalArgumentException("An Attribute or an Namespace can't be added as a child");
252 }
253
254 if (this.getNodeType() == TEXT) {
255 throw new IllegalArgumentException("a TEXT node can't have children.");
256 }
257
258 if (_firstChildNode == null) {
259 _firstChildNode = node;
260 } else if (_firstChildNode.getNodeType() == ATTRIBUTE
261 || _firstChildNode.getNodeType() == NAMESPACE) {
262 _firstChildNode.addChild(node);
263 } else {
264 _firstChildNode.appendSibling(node);
265 }
266 }
267
268
269
270
271
272
273 public void addAttribute(AnyNode node) {
274 if (node == null) {
275 throw new IllegalArgumentException("null argument in addAttribute");
276 }
277
278 if (node.getNodeType() != ATTRIBUTE) {
279 throw new IllegalArgumentException("Only attribute can be added as an attribute");
280 }
281
282 if (_firstChildNode == null) {
283 _firstChildNode = node;
284 } else {
285 if (_firstChildNode.getNodeType() == ATTRIBUTE) {
286
287 _firstChildNode.appendSibling(node);
288 } else if (_firstChildNode.getNodeType() == NAMESPACE) {
289
290
291 _firstChildNode.addAttribute(node);
292 } else {
293
294 node.addChild(_firstChildNode);
295 _firstChildNode = node;
296 }
297 }
298 }
299
300
301
302
303
304
305 public void addNamespace(AnyNode node) {
306 if (node == null) {
307 throw new IllegalArgumentException("null argument in addNamespace");
308 }
309
310 if (node.getNodeType() != NAMESPACE) {
311 throw new IllegalArgumentException("Only namespace can be added as an namespace");
312 }
313
314 if (_firstChildNode == null) {
315 _firstChildNode = node;
316 } else {
317 if (_firstChildNode.getNodeType() == NAMESPACE) {
318
319 _firstChildNode.appendSibling(node);
320 } else if (_firstChildNode.getNodeType() == ATTRIBUTE) {
321
322
323 _firstChildNode.addNamespace(node);
324 } else {
325
326 node.addChild(_firstChildNode);
327 _firstChildNode = node;
328 }
329 }
330 }
331
332
333
334
335
336 public AnyNode getFirstAttribute() {
337 if (this.getNodeType() != ELEMENT) {
338 String err = "This node type can not contain attributes";
339 throw new UnsupportedOperationException(err);
340 }
341
342 boolean found = false;
343 AnyNode tempNode = this.getFirstChildNode();
344 while (tempNode != null && !found) {
345 short type = tempNode.getNodeType();
346
347
348 if (type == ELEMENT || type == COMMENT || type == TEXT || type == PI) {
349 tempNode = null;
350 } else if (type == NAMESPACE) {
351 tempNode = tempNode.getFirstChildNode();
352 } else {
353 found = true;
354 }
355 }
356 return tempNode;
357 }
358
359
360
361
362
363
364
365 public AnyNode getFirstNamespace() {
366 if (this.getNodeType() != ELEMENT) {
367 String err = "This node type can not contain namespaces";
368 throw new UnsupportedOperationException(err);
369 }
370
371 AnyNode tempNode = this.getFirstChildNode();
372 boolean found = false;
373 while (tempNode != null && !found) {
374 short type = tempNode.getNodeType();
375
376
377 if (type == ELEMENT || type == COMMENT || type == TEXT || type == PI) {
378 tempNode = null;
379 } else if (type == ATTRIBUTE) {
380 tempNode = tempNode.getFirstChildNode();
381 } else {
382 found = true;
383 }
384 }
385 return tempNode;
386 }
387
388
389
390
391
392
393
394 public AnyNode getFirstChild() {
395
396
397 if (this.getNodeType() == ATTRIBUTE || this.getNodeType() == NAMESPACE) {
398 return null;
399 }
400
401
402
403 AnyNode tempNode = this.getFirstChildNode();
404 boolean found = false;
405 while (tempNode != null && !found) {
406 short type = tempNode.getNodeType();
407 if (type == ELEMENT || type == COMMENT || type == TEXT || type == PI) {
408 found = true;
409 } else if (type == ATTRIBUTE || type == NAMESPACE) {
410 tempNode = tempNode.getFirstChildNode();
411 }
412 }
413 return tempNode;
414 }
415
416
417
418
419
420
421
422
423 public AnyNode getNextSibling() {
424 return _nextSiblingNode;
425 }
426
427
428
429
430
431
432 public short getNodeType() {
433 return _nodeType;
434 }
435
436
437
438
439
440
441
442
443 public String getLocalName() {
444 return _localName;
445 }
446
447
448
449
450
451
452
453 public String getNamespaceURI() {
454 return _uri;
455 }
456
457
458
459
460
461
462
463
464
465
466 public String getStringValue() {
467 switch (_nodeType) {
468 case ATTRIBUTE:
469 case TEXT:
470 return _value;
471 case NAMESPACE:
472 return _uri;
473
474 case PI:
475 return "";
476 case COMMENT:
477 return _value;
478 case ELEMENT:
479 StringBuffer result = new StringBuffer(4096);
480 AnyNode tempNode = this.getNextSibling();
481 while (tempNode != null && tempNode.getNodeType() == TEXT) {
482 result.append(tempNode.getStringValue());
483 tempNode = tempNode.getNextSibling();
484 }
485
486 tempNode = this.getFirstChild();
487 while (tempNode != null) {
488 result.append(tempNode.getStringValue());
489 tempNode = tempNode.getNextSibling();
490 }
491 tempNode = null;
492 return result.toString();
493 default:
494 return null;
495 }
496 }
497
498
499
500
501
502
503
504
505 public String getNamespacePrefix() {
506 return _prefix;
507 }
508
509
510
511
512
513
514
515 public String toString() {
516 Serializer serializer = new BackwardCompatibilityContext().getSerializer();
517 if (serializer == null) {
518 throw new RuntimeException("Unable to obtain serializer");
519 }
520
521 StringWriter writer = new StringWriter();
522
523 serializer.setOutputCharStream(writer);
524
525 try {
526 AnyNode2SAX.fireEvents(this, serializer.asDocumentHandler());
527 } catch (java.io.IOException ioe) {
528 return privateToString();
529 } catch (org.xml.sax.SAXException saxe) {
530 throw new RuntimeException(saxe.getMessage());
531 }
532
533 return writer.toString();
534 }
535
536 private String privateToString() {
537 StringBuilder sb = new StringBuilder(4096);
538
539 if (_elements == null) {
540 _elements = new Stack<>();
541 }
542
543
544
545 if (_elements.search(this) == -1) {
546 _elements.push(this);
547
548 if (this.getNodeType() == ELEMENT) {
549
550 sb.append('<');
551 String prefix = getNamespacePrefix();
552 if (prefix != null) {
553 sb.append(prefix).append(':');
554 }
555 prefix = null;
556 sb.append(getLocalName());
557
558
559 AnyNode tempNode = this.getFirstAttribute();
560 while (tempNode != null) {
561 sb.append(' ').append(tempNode.getLocalName()).append("='")
562 .append(tempNode.getStringValue()).append('\'');
563 tempNode = tempNode.getNextSibling();
564 }
565
566
567 tempNode = this.getFirstNamespace();
568 while (tempNode != null) {
569 sb.append(' ').append(XMLNS_PREFIX);
570 prefix = tempNode.getNamespacePrefix();
571 if (prefix != null && prefix.length() != 0) {
572 sb.append(':').append(prefix);
573 }
574 sb.append("='").append(tempNode.getNamespaceURI()).append('\'');
575 tempNode = tempNode.getNextSibling();
576 }
577
578 tempNode = this.getFirstChild();
579 if (tempNode != null) {
580 sb.append('>');
581 while (tempNode != null) {
582 sb.append(tempNode.privateToString());
583 tempNode = tempNode.getNextSibling();
584 }
585
586 sb.append("</").append(getLocalName()).append('>');
587 } else {
588 sb.append("/>");
589 }
590 } else {
591 sb.append(this.getStringValue());
592 }
593 }
594 return sb.toString();
595 }
596
597
598
599
600
601
602
603 protected void appendSibling(AnyNode node) {
604 if (node == null) {
605 throw new IllegalArgumentException();
606 }
607
608 if (((node.getNodeType() == ATTRIBUTE) || (node.getNodeType() == NAMESPACE))
609 && (this.getNodeType() != node.getNodeType())) {
610 String err =
611 "a NAMESPACE or an ATTRIBUTE can only be add as a sibling to a node of the same type";
612 throw new UnsupportedOperationException(err);
613 }
614
615 if (_nextSiblingNode == null) {
616
617 if ((node.getNodeType() == TEXT) && (this.getNodeType() == TEXT)) {
618 mergeTextNode(this, node);
619 } else {
620 _nextSiblingNode = node;
621 }
622 } else {
623 _nextSiblingNode.appendSibling(node);
624 }
625 }
626
627
628
629
630
631
632 protected AnyNode getFirstChildNode() {
633 return _firstChildNode;
634 }
635
636
637
638
639
640
641
642 private void mergeTextNode(AnyNode node1, AnyNode node2) {
643 if (node1.getNodeType() != node2.getNodeType()) {
644 return;
645 }
646 if (node1.getNodeType() != AnyNode.TEXT) {
647 return;
648 }
649
650 node1._value = node1.getStringValue() + node2.getStringValue();
651 node2 = null;
652 }
653
654 }