View Javadoc
1   /*
2    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
3    * The software in this package is published under the terms of the CPAL v1.0
4    * license, a copy of which has been included with this distribution in the
5    * LICENSE.txt file.
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      * Capture the current event;
131      * 
132      * @param event
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                 // skipping
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 }