View Javadoc

1   /*
2    * $Id$
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSource, Inc.  All rights reserved.  http://www.mulesource.com
5    *
6    * The software in this package is published under the terms of the CPAL v1.0
7    * license, a copy of which has been included with this distribution in the
8    * LICENSE.txt file.
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      * Capture the current event;
133      * 
134      * @param event
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                 // skipping
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             return ((CharactersEvent) current).getData();
561         }
562         else
563         {
564             return super.getText();
565         }
566     }
567 
568     public char[] getTextCharacters()
569     {
570         if (replay)
571         {
572             return ((CharactersEvent) current).getData().toCharArray();
573         }
574         else
575         {
576             return super.getTextCharacters();
577         }
578     }
579 
580     public int getTextCharacters(int sourceStart, char[] target, int targetStart, int length) throws XMLStreamException
581     {
582         if (replay)
583         {
584             char[] src = getText().toCharArray();
585 
586             if (sourceStart + length >= src.length) {
587                 length = src.length - sourceStart;
588             }
589 
590             for (int i = 0; i < length; i++) {
591                 target[targetStart + i] = src[i + sourceStart];
592             }
593 
594             return length;
595         }
596         else
597         {
598             return super.getTextCharacters(sourceStart, target, targetStart, length);
599         }
600     }
601 
602     public int getTextLength()
603     {
604         if (replay)
605         {
606             return getText().length();
607         }
608         else
609         {
610             return super.getTextLength();
611         }
612     }
613 
614     public int getTextStart()
615     {
616         if (replay)
617         {
618             return 0;
619         }
620         else
621         {
622             return super.getTextStart();
623         }
624     }
625 
626     public boolean hasName()
627     {
628         if (replay)
629         {
630             return isStartElement() || isEndElement();
631         }
632         else
633         {
634             return super.hasName();
635         }
636     }
637 
638     public boolean hasNext() throws XMLStreamException
639     {
640         if (replay)
641         {
642             if (replayIndex == events.size()) 
643             {
644                 return super.hasNext();
645             }
646             else
647             {
648                 return true;
649             }
650         }
651         else
652         {
653             return super.hasNext();
654         }
655     }
656 
657     public boolean hasText()
658     {
659         if (replay)
660         {
661             int event = getEventType();
662             return event == CHARACTERS || event == DTD
663                 || event == ENTITY_REFERENCE || event == COMMENT || event == SPACE;
664         }
665         else
666         {
667             return super.hasText();
668         }
669     }
670 
671     public boolean isAttributeSpecified(int i)
672     {
673         if (replay)
674         {
675             Attribute attr = (Attribute) ((StartElementEventX) current).getAttributeList().get(i);
676             return attr.isSpecified();
677         }
678         else
679         {
680             return super.isAttributeSpecified(i);
681         }
682     }
683 
684     public boolean isCharacters()
685     {
686         if (replay)
687         {
688             return current.isCharacters();
689         }
690         else
691         {
692             return super.isCharacters();
693         }
694     }
695 
696     public boolean isEndElement()
697     {
698         if (replay)
699         {
700             return current.isEndElement();
701         }
702         else
703         {
704             return super.isEndElement();
705         }
706     }
707 
708 
709     public boolean isStartElement()
710     {
711         if (replay)
712         {
713             return current.isStartElement();
714         }
715         else
716         {
717             return super.isStartElement();
718         }
719     }
720 
721     public boolean isWhiteSpace()
722     {
723         if (replay)
724         {
725             return current.getEventType() == SPACE;
726         }
727         else
728         {
729             return super.isWhiteSpace();
730         }
731     }
732 
733 }