View Javadoc

1   /*
2    * $Id: ReversibleXMLStreamReader.java 19191 2010-08-25 21:05:23Z tcarlson $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.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             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 }