1
2
3
4
5
6
7
8
9
10
11 package org.mule.module.xml.stax;
12
13 import java.util.ArrayList;
14 import java.util.List;
15
16 import javanet.staxutils.events.AttributeEvent;
17 import javanet.staxutils.events.CDataEvent;
18 import javanet.staxutils.events.CharactersEvent;
19 import javanet.staxutils.events.CommentEvent;
20 import javanet.staxutils.events.EndDocumentEvent;
21 import javanet.staxutils.events.EndElementEvent;
22 import javanet.staxutils.events.NamespaceEvent;
23 import javanet.staxutils.events.StartDocumentEvent;
24 import javanet.staxutils.events.StartElementEvent;
25
26 import javax.xml.namespace.NamespaceContext;
27 import javax.xml.namespace.QName;
28 import javax.xml.stream.Location;
29 import javax.xml.stream.XMLStreamConstants;
30 import javax.xml.stream.XMLStreamException;
31 import javax.xml.stream.XMLStreamReader;
32 import javax.xml.stream.events.Attribute;
33 import javax.xml.stream.events.Namespace;
34 import javax.xml.stream.events.XMLEvent;
35
36 public class ReversibleXMLStreamReader extends DelegateXMLStreamReader
37 {
38 private List events;
39 private XMLEvent current;
40 private int replayIndex;
41 private boolean tracking = false;
42 private boolean replay = false;
43
44 public ReversibleXMLStreamReader(XMLStreamReader reader)
45 {
46 super(reader);
47 }
48
49 public int nextTag() throws XMLStreamException
50 {
51 int eventType = next();
52 while ((eventType == XMLStreamConstants.CHARACTERS && isWhiteSpace())
53 || (eventType == XMLStreamConstants.CDATA && isWhiteSpace())
54 || eventType == XMLStreamConstants.SPACE
55 || eventType == XMLStreamConstants.PROCESSING_INSTRUCTION
56 || eventType == XMLStreamConstants.COMMENT)
57 {
58 eventType = next();
59 }
60 if (eventType != XMLStreamConstants.START_ELEMENT && eventType != XMLStreamConstants.END_ELEMENT)
61 {
62 throw new XMLStreamException("expected start or end tag", getLocation());
63 }
64 return eventType;
65 }
66
67 public void reset()
68 {
69 replay = true;
70 replayIndex = 0;
71 current = null;
72 }
73
74 public boolean isTracking()
75 {
76 return tracking;
77 }
78
79 public void setTracking(boolean tracking)
80 {
81 this.tracking = tracking;
82
83 if (tracking)
84 {
85 replayIndex = 0;
86
87 if (events == null)
88 {
89 events = new ArrayList();
90 }
91 }
92 }
93
94 public int next() throws XMLStreamException
95 {
96 int event;
97
98 if (replay)
99 {
100 if (replayIndex == events.size())
101 {
102 replay = false;
103 event = super.next();
104 }
105 else
106 {
107 event = getReplayEvent();
108 }
109 }
110 else
111 {
112 event = super.next();
113 }
114
115 if (tracking && !replay)
116 {
117 capture(event);
118 }
119
120 return event;
121 }
122
123 private int getReplayEvent()
124 {
125 current = (XMLEvent) events.get(replayIndex);
126 replayIndex++;
127
128 return current.getEventType();
129 }
130
131
132
133
134
135
136 private void capture(int event)
137 {
138 switch (event)
139 {
140 case XMLStreamConstants.START_DOCUMENT :
141 events.add(new StartDocumentEvent(getEncoding(), new Boolean(isStandalone()), getVersion(),
142 getLocation()));
143 break;
144 case XMLStreamConstants.END_DOCUMENT :
145 events.add(new EndDocumentEvent(getLocation()));
146 break;
147 case XMLStreamConstants.START_ELEMENT :
148 events.add(createStartElementEvent());
149 break;
150 case XMLStreamConstants.END_ELEMENT :
151 events.add(new EndElementEvent(getName(), getNamespaces().iterator(), getLocation()));
152 break;
153 case XMLStreamConstants.CDATA :
154 events.add(new CDataEvent(getText(), getLocation()));
155 break;
156 case XMLStreamConstants.CHARACTERS :
157 events.add(new CharactersEvent(getText(), getLocation()));
158 break;
159 case XMLStreamConstants.COMMENT :
160 events.add(new CommentEvent(getText(), getLocation()));
161 break;
162 case XMLStreamConstants.DTD :
163 break;
164 case XMLStreamConstants.ENTITY_DECLARATION :
165 break;
166 case XMLStreamConstants.ENTITY_REFERENCE :
167 break;
168 case XMLStreamConstants.NOTATION_DECLARATION :
169 break;
170 case XMLStreamConstants.PROCESSING_INSTRUCTION :
171 break;
172 case XMLStreamConstants.SPACE :
173 break;
174 }
175 }
176
177 private StartElementEvent createStartElementEvent()
178 {
179 List attributes = new ArrayList();
180 for (int i = 0; i < getAttributeCount(); i++)
181 {
182 attributes.add(new AttributeEvent(getAttributeName(i), getAttributeValue(i)));
183 }
184
185 return new StartElementEventX(getName(), attributes, getNamespaces(),
186 createContext(), getLocation(), null);
187 }
188
189 private NamespaceContext createContext()
190 {
191 MapNamespaceContext ctx = new MapNamespaceContext();
192
193 for (int i = 0; i < getNamespaceCount(); i++)
194 {
195 ctx.addNamespace(getNamespacePrefix(i), getNamespaceURI(i));
196 }
197
198 return ctx;
199 }
200
201 private List getNamespaces()
202 {
203 List namespaces = new ArrayList();
204 for (int i = 0; i < getNamespaceCount(); i++)
205 {
206 namespaces.add(new NamespaceEvent(getNamespacePrefix(i), getNamespaceURI(i), getLocation()));
207 }
208 return namespaces;
209 }
210
211 public String getElementText() throws XMLStreamException
212 {
213 if (getEventType() != XMLStreamConstants.START_ELEMENT)
214 {
215 throw new XMLStreamException("parser must be on START_ELEMENT to read next text", getLocation());
216 }
217
218 int eventType = next();
219 StringBuffer buf = new StringBuffer();
220 while (eventType != XMLStreamConstants.END_ELEMENT)
221 {
222 if (eventType == XMLStreamConstants.CHARACTERS || eventType == XMLStreamConstants.CDATA
223 || eventType == XMLStreamConstants.SPACE || eventType == XMLStreamConstants.ENTITY_REFERENCE)
224 {
225 buf.append(getText());
226 }
227 else if (eventType == XMLStreamConstants.PROCESSING_INSTRUCTION
228 || eventType == XMLStreamConstants.COMMENT)
229 {
230
231 }
232 else if (eventType == XMLStreamConstants.END_DOCUMENT)
233 {
234 throw new XMLStreamException("unexpected end of document when reading element text content");
235 }
236 else if (eventType == XMLStreamConstants.START_ELEMENT)
237 {
238 throw new XMLStreamException("element text content may not contain START_ELEMENT",
239 getLocation());
240 }
241 else
242 {
243 throw new XMLStreamException("Unexpected event type " + eventType, getLocation());
244 }
245 eventType = next();
246 }
247 return buf.toString();
248
249 }
250
251 public int getAttributeCount()
252 {
253 if (replay)
254 {
255 return ((StartElementEventX) current).getAttributeList().size();
256 }
257 else
258 {
259 return super.getAttributeCount();
260 }
261 }
262
263 public String getAttributeLocalName(int i)
264 {
265
266 if (replay)
267 {
268 Attribute att = (Attribute) ((StartElementEventX) current).getAttributeList().get(i);
269 return att.getName().getLocalPart();
270 }
271 else
272 {
273 return super.getAttributeLocalName(i);
274 }
275 }
276
277 public QName getAttributeName(int i)
278 {
279
280 if (replay)
281 {
282 Attribute att = (Attribute) ((StartElementEventX) current).getAttributeList().get(i);
283 return att.getName();
284 }
285 else
286 {
287 return super.getAttributeName(i);
288 }
289 }
290
291 public String getAttributeNamespace(int i)
292 {
293
294 if (replay)
295 {
296 Attribute att = (Attribute) ((StartElementEventX) current).getAttributeList().get(i);
297 return att.getName().getNamespaceURI();
298 }
299 else
300 {
301 return super.getAttributeNamespace(i);
302 }
303 }
304
305 public String getAttributePrefix(int i)
306 {
307 if (replay)
308 {
309 Attribute att = (Attribute) ((StartElementEventX) current).getAttributeList().get(i);
310 return att.getName().getPrefix();
311 }
312 else
313 {
314 return super.getAttributePrefix(i);
315 }
316 }
317
318 public String getAttributeType(int i)
319 {
320 if (replay)
321 {
322 Attribute att = (Attribute) ((StartElementEventX) current).getAttributeList().get(i);
323 return att.getDTDType();
324 }
325 else
326 {
327 return super.getAttributeType(i);
328 }
329 }
330
331 public String getAttributeValue(int i)
332 {
333 if (replay)
334 {
335 Attribute att = (Attribute) ((StartElementEventX) current).getAttributeList().get(i);
336 return att.getValue();
337 }
338 else
339 {
340 return super.getAttributeValue(i);
341 }
342 }
343
344 public String getAttributeValue(String ns, String local)
345 {
346 if (replay)
347 {
348 Attribute att = ((StartElementEventX) current).getAttributeByName(new QName(ns, local));
349 if (att != null)
350 {
351 return att.getValue();
352 }
353 else
354 {
355 return null;
356 }
357 }
358 else
359 {
360 return super.getAttributeValue(ns, local);
361 }
362 }
363
364 public int getEventType()
365 {
366 if (replay)
367 {
368 if (current == null)
369 {
370 return START_DOCUMENT;
371 }
372 return current.getEventType();
373 }
374 else
375 {
376 return super.getEventType();
377 }
378 }
379
380 public String getLocalName()
381 {
382 if (replay)
383 {
384 if (isStartElement())
385 {
386 return ((StartElementEventX) current).getName().getLocalPart();
387 }
388 else
389 {
390 return ((EndElementEvent) current).getName().getLocalPart();
391 }
392 }
393 else
394 {
395 return super.getLocalName();
396 }
397 }
398
399 public Location getLocation()
400 {
401 if (replay)
402 {
403 return current.getLocation();
404 }
405 else
406 {
407 return super.getLocation();
408 }
409 }
410
411 public QName getName()
412 {
413 if (replay)
414 {
415 if (isStartElement())
416 {
417 return ((StartElementEventX) current).getName();
418 }
419 else
420 {
421 return ((EndElementEvent) current).getName();
422 }
423 }
424 else
425 {
426 return super.getName();
427 }
428 }
429
430 public NamespaceContext getNamespaceContext()
431 {
432 if (replay)
433 {
434 return ((StartElementEventX) current).getNamespaceContext();
435 }
436 else
437 {
438 return super.getNamespaceContext();
439 }
440 }
441
442 public int getNamespaceCount()
443 {
444 if (replay)
445 {
446 return ((StartElementEventX) current).getNamespaceList().size();
447 }
448 else
449 {
450 return super.getNamespaceCount();
451 }
452 }
453
454 public String getNamespacePrefix(int arg0)
455 {
456 if (replay)
457 {
458 Namespace ns = (Namespace) ((StartElementEventX) current).getNamespaceList().get(arg0);
459
460 return ns.getPrefix();
461 }
462 else
463 {
464 return super.getNamespacePrefix(arg0);
465 }
466 }
467
468 public String getNamespaceURI()
469 {
470 if (replay)
471 {
472 if (isStartElement())
473 {
474 return ((StartElementEventX) current).getName().getNamespaceURI();
475 }
476 else
477 {
478 return ((EndElementEvent) current).getName().getNamespaceURI();
479 }
480 }
481 else
482 {
483 return super.getNamespaceURI();
484 }
485 }
486
487 public String getNamespaceURI(int arg0)
488 {
489 if (replay)
490 {
491 Namespace ns = (Namespace) ((StartElementEventX) current).getNamespaceList().get(arg0);
492
493 return ns.getNamespaceURI();
494 }
495 else
496 {
497 return super.getNamespaceURI(arg0);
498 }
499 }
500
501 public String getNamespaceURI(String prefix)
502 {
503 if (replay)
504 {
505 return ((StartElementEventX) current).getNamespaceURI(prefix);
506 }
507 else
508 {
509 return super.getNamespaceURI(prefix);
510 }
511 }
512
513 public String getPIData()
514 {
515 if (replay)
516 {
517 return null;
518 }
519 else
520 {
521 return super.getPIData();
522 }
523 }
524
525 public String getPITarget()
526 {
527 if (replay)
528 {
529 return null;
530 }
531 else
532 {
533 return super.getPITarget();
534 }
535 }
536
537 public String getPrefix()
538 {
539 if (replay)
540 {
541 if (isStartElement())
542 {
543 return ((StartElementEventX) current).getName().getPrefix();
544 }
545 else
546 {
547 return ((EndElementEvent) current).getName().getPrefix();
548 }
549 }
550 else
551 {
552 return super.getPrefix();
553 }
554 }
555
556 public String getText()
557 {
558 if (replay)
559 {
560 if (current instanceof CommentEvent)
561 {
562 return ((CommentEvent) current).getText();
563 }
564 else
565 {
566 return ((CharactersEvent) current).getData();
567 }
568 }
569 else
570 {
571 return super.getText();
572 }
573 }
574
575 public char[] getTextCharacters()
576 {
577 if (replay)
578 {
579 return ((CharactersEvent) current).getData().toCharArray();
580 }
581 else
582 {
583 return super.getTextCharacters();
584 }
585 }
586
587 public int getTextCharacters(int sourceStart, char[] target, int targetStart, int length) throws XMLStreamException
588 {
589 if (replay)
590 {
591 char[] src = getText().toCharArray();
592
593 if (sourceStart + length >= src.length) {
594 length = src.length - sourceStart;
595 }
596
597 for (int i = 0; i < length; i++) {
598 target[targetStart + i] = src[i + sourceStart];
599 }
600
601 return length;
602 }
603 else
604 {
605 return super.getTextCharacters(sourceStart, target, targetStart, length);
606 }
607 }
608
609 public int getTextLength()
610 {
611 if (replay)
612 {
613 return getText().length();
614 }
615 else
616 {
617 return super.getTextLength();
618 }
619 }
620
621 public int getTextStart()
622 {
623 if (replay)
624 {
625 return 0;
626 }
627 else
628 {
629 return super.getTextStart();
630 }
631 }
632
633 public boolean hasName()
634 {
635 if (replay)
636 {
637 return isStartElement() || isEndElement();
638 }
639 else
640 {
641 return super.hasName();
642 }
643 }
644
645 public boolean hasNext() throws XMLStreamException
646 {
647 if (replay)
648 {
649 if (replayIndex == events.size())
650 {
651 return super.hasNext();
652 }
653 else
654 {
655 return true;
656 }
657 }
658 else
659 {
660 return super.hasNext();
661 }
662 }
663
664 public boolean hasText()
665 {
666 if (replay)
667 {
668 int event = getEventType();
669 return event == CHARACTERS || event == DTD
670 || event == ENTITY_REFERENCE || event == COMMENT || event == SPACE;
671 }
672 else
673 {
674 return super.hasText();
675 }
676 }
677
678 public boolean isAttributeSpecified(int i)
679 {
680 if (replay)
681 {
682 Attribute attr = (Attribute) ((StartElementEventX) current).getAttributeList().get(i);
683 return attr.isSpecified();
684 }
685 else
686 {
687 return super.isAttributeSpecified(i);
688 }
689 }
690
691 public boolean isCharacters()
692 {
693 if (replay)
694 {
695 return current.isCharacters();
696 }
697 else
698 {
699 return super.isCharacters();
700 }
701 }
702
703 public boolean isEndElement()
704 {
705 if (replay)
706 {
707 return current.isEndElement();
708 }
709 else
710 {
711 return super.isEndElement();
712 }
713 }
714
715
716 public boolean isStartElement()
717 {
718 if (replay)
719 {
720 return current.isStartElement();
721 }
722 else
723 {
724 return super.isStartElement();
725 }
726 }
727
728 public boolean isWhiteSpace()
729 {
730 if (replay)
731 {
732 return current.getEventType() == SPACE;
733 }
734 else
735 {
736 return super.isWhiteSpace();
737 }
738 }
739
740 }