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