KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > xml > serializer > ToXMLSAXHandler


1 /*
2  * Copyright 2001-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 /*
17  * $Id: ToXMLSAXHandler.java,v 1.13 2004/02/17 04:18:19 minchau Exp $
18  */

19  package org.apache.xml.serializer;
20
21 import java.io.IOException JavaDoc;
22 import java.io.OutputStream JavaDoc;
23 import java.io.Writer JavaDoc;
24 import java.util.Properties JavaDoc;
25
26 import javax.xml.transform.Result JavaDoc;
27
28 import org.w3c.dom.Node JavaDoc;
29 import org.xml.sax.Attributes JavaDoc;
30 import org.xml.sax.ContentHandler JavaDoc;
31 import org.xml.sax.Locator JavaDoc;
32 import org.xml.sax.SAXException JavaDoc;
33 import org.xml.sax.ext.LexicalHandler JavaDoc;
34
35 /**
36  * This class receives notification of SAX-like events, and with gathered
37  * information over these calls it will invoke the equivalent SAX methods
38  * on a handler, the ultimate output is known to be XML.
39  *
40  * @author minchau
41  * @author Santiago Pericas-Geertsen
42  * @author G. Todd Miller
43  */

44 public class ToXMLSAXHandler extends ToSAXHandler
45 {
46
47     /**
48      * Keeps track of whether output escaping is currently enabled
49      */

50     protected boolean m_escapeSetting = false;
51
52     public ToXMLSAXHandler()
53     {
54         // default constructor (need to set content handler ASAP !)
55
m_prefixMap = new NamespaceMappings();
56         initCDATA();
57     }
58
59     /**
60      * @see org.apache.xml.serializer.Serializer#getOutputFormat()
61      */

62     public Properties JavaDoc getOutputFormat()
63     {
64         return null;
65     }
66
67     /**
68      * @see org.apache.xml.serializer.Serializer#getOutputStream()
69      */

70     public OutputStream JavaDoc getOutputStream()
71     {
72         return null;
73     }
74
75     /**
76      * @see org.apache.xml.serializer.Serializer#getWriter()
77      */

78     public Writer JavaDoc getWriter()
79     {
80         return null;
81     }
82
83     /**
84      * Do nothing for SAX.
85      */

86     public void indent(int n) throws SAXException JavaDoc
87     {
88     }
89
90
91     /**
92      * @see org.apache.xml.serializer.DOMSerializer#serialize(Node)
93      */

94     public void serialize(Node JavaDoc node) throws IOException JavaDoc
95     {
96     }
97
98     /**
99      * @see org.apache.xml.serializer.SerializationHandler#setEscaping(boolean)
100      */

101     public boolean setEscaping(boolean escape) throws SAXException JavaDoc
102     {
103         boolean oldEscapeSetting = m_escapeSetting;
104         m_escapeSetting = escape;
105
106         if (escape) {
107             processingInstruction(Result.PI_ENABLE_OUTPUT_ESCAPING, "");
108         } else {
109             processingInstruction(Result.PI_DISABLE_OUTPUT_ESCAPING, "");
110         }
111
112         return oldEscapeSetting;
113     }
114
115     /**
116      * @see org.apache.xml.serializer.Serializer#setOutputFormat(Properties)
117      */

118     public void setOutputFormat(Properties JavaDoc format)
119     {
120     }
121
122     /**
123      * @see org.apache.xml.serializer.Serializer#setOutputStream(OutputStream)
124      */

125     public void setOutputStream(OutputStream JavaDoc output)
126     {
127     }
128
129     /**
130      * @see org.apache.xml.serializer.Serializer#setWriter(Writer)
131      */

132     public void setWriter(Writer JavaDoc writer)
133     {
134     }
135
136     /**
137      * @see org.xml.sax.ext.DeclHandler#attributeDecl(String, String, String, String, String)
138      */

139     public void attributeDecl(
140         String JavaDoc arg0,
141         String JavaDoc arg1,
142         String JavaDoc arg2,
143         String JavaDoc arg3,
144         String JavaDoc arg4)
145         throws SAXException JavaDoc
146     {
147     }
148
149     /**
150      * @see org.xml.sax.ext.DeclHandler#elementDecl(String, String)
151      */

152     public void elementDecl(String JavaDoc arg0, String JavaDoc arg1) throws SAXException JavaDoc
153     {
154     }
155
156     /**
157      * @see org.xml.sax.ext.DeclHandler#externalEntityDecl(String, String, String)
158      */

159     public void externalEntityDecl(String JavaDoc arg0, String JavaDoc arg1, String JavaDoc arg2)
160         throws SAXException JavaDoc
161     {
162     }
163
164     /**
165      * @see org.xml.sax.ext.DeclHandler#internalEntityDecl(String, String)
166      */

167     public void internalEntityDecl(String JavaDoc arg0, String JavaDoc arg1)
168         throws SAXException JavaDoc
169     {
170     }
171
172     /**
173      * Receives notification of the end of the document.
174      * @see org.xml.sax.ContentHandler#endDocument()
175      */

176     public void endDocument() throws SAXException JavaDoc
177     {
178
179         flushPending();
180
181         // Close output document
182
m_saxHandler.endDocument();
183
184         if (m_tracer != null)
185             super.fireEndDoc();
186     }
187
188     /**
189      * This method is called when all the data needed for a call to the
190      * SAX handler's startElement() method has been gathered.
191      */

192     protected void closeStartTag() throws SAXException JavaDoc
193     {
194
195         m_elemContext.m_startTagOpen = false;
196
197         final String JavaDoc localName = getLocalName(m_elemContext.m_elementName);
198         final String JavaDoc uri = getNamespaceURI(m_elemContext.m_elementName, true);
199
200         // Now is time to send the startElement event
201
if (m_needToCallStartDocument)
202         {
203             startDocumentInternal();
204         }
205         m_saxHandler.startElement(uri, localName, m_elemContext.m_elementName, m_attributes);
206         // we've sent the official SAX attributes on their way,
207
// now we don't need them anymore.
208
m_attributes.clear();
209
210         if(m_state != null)
211           m_state.setCurrentNode(null);
212     }
213
214     /**
215      * Closes ane open cdata tag, and
216      * unlike the this.endCDATA() method (from the LexicalHandler) interface,
217      * this "internal" method will send the endCDATA() call to the wrapped
218      * handler.
219      *
220      */

221     public void closeCDATA() throws SAXException JavaDoc
222     {
223
224         // Output closing bracket - "]]>"
225
if (m_lexHandler != null && m_cdataTagOpen) {
226             m_lexHandler.endCDATA();
227         }
228         
229
230         // There are no longer any calls made to
231
// m_lexHandler.startCDATA() without a balancing call to
232
// m_lexHandler.endCDATA()
233
// so we set m_cdataTagOpen to false to remember this.
234
m_cdataTagOpen = false;
235     }
236
237     /**
238      * @see org.xml.sax.ContentHandler#endElement(String, String, String)
239      */

240     public void endElement(String JavaDoc namespaceURI, String JavaDoc localName, String JavaDoc qName)
241         throws SAXException JavaDoc
242     {
243         // Close any open elements etc.
244
flushPending();
245         
246         if (namespaceURI == null)
247         {
248             if (m_elemContext.m_elementURI != null)
249                 namespaceURI = m_elemContext.m_elementURI;
250             else
251                 namespaceURI = getNamespaceURI(qName, true);
252         }
253         
254         if (localName == null)
255         {
256             if (m_elemContext.m_elementLocalName != null)
257                 localName = m_elemContext.m_elementLocalName;
258             else
259                 localName = getLocalName(qName);
260         }
261
262         m_saxHandler.endElement(namespaceURI, localName, qName);
263
264         if (m_tracer != null)
265             super.fireEndElem(qName);
266
267         /* Pop all namespaces at the current element depth.
268          * We are not waiting for official endPrefixMapping() calls.
269          */

270         m_prefixMap.popNamespaces(m_elemContext.m_currentElemDepth,
271             m_saxHandler);
272         m_elemContext = m_elemContext.m_prev;
273     }
274
275     /**
276      * @see org.xml.sax.ContentHandler#endPrefixMapping(String)
277      */

278     public void endPrefixMapping(String JavaDoc prefix) throws SAXException JavaDoc
279     {
280         /* poping all prefix mappings should have been done
281          * in endElement() already
282          */

283          return;
284     }
285
286     /**
287      * @see org.xml.sax.ContentHandler#ignorableWhitespace(char[], int, int)
288      */

289     public void ignorableWhitespace(char[] arg0, int arg1, int arg2)
290         throws SAXException JavaDoc
291     {
292         m_saxHandler.ignorableWhitespace(arg0,arg1,arg2);
293     }
294
295     /**
296      * @see org.xml.sax.ContentHandler#setDocumentLocator(Locator)
297      */

298     public void setDocumentLocator(Locator JavaDoc arg0)
299     {
300         m_saxHandler.setDocumentLocator(arg0);
301     }
302
303     /**
304      * @see org.xml.sax.ContentHandler#skippedEntity(String)
305      */

306     public void skippedEntity(String JavaDoc arg0) throws SAXException JavaDoc
307     {
308         m_saxHandler.skippedEntity(arg0);
309     }
310
311     /**
312      * @see org.xml.sax.ContentHandler#startPrefixMapping(String, String)
313      * @param prefix The prefix that maps to the URI
314      * @param uri The URI for the namespace
315      */

316     public void startPrefixMapping(String JavaDoc prefix, String JavaDoc uri)
317         throws SAXException JavaDoc
318     {
319        startPrefixMapping(prefix, uri, true);
320     }
321
322     /**
323      * Remember the prefix/uri mapping at the current nested element depth.
324      *
325      * @see org.xml.sax.ContentHandler#startPrefixMapping(String, String)
326      * @param prefix The prefix that maps to the URI
327      * @param uri The URI for the namespace
328      * @param shouldFlush a flag indicating if the mapping applies to the
329      * current element or an up coming child (not used).
330      */

331
332     public boolean startPrefixMapping(
333         String JavaDoc prefix,
334         String JavaDoc uri,
335         boolean shouldFlush)
336         throws org.xml.sax.SAXException JavaDoc
337     {
338
339         /* Remember the mapping, and at what depth it was declared
340          * This is one greater than the current depth because these
341          * mappings will apply to the next depth. This is in
342          * consideration that startElement() will soon be called
343          */

344
345         boolean pushed;
346         int pushDepth;
347         if (shouldFlush)
348         {
349             flushPending();
350             // the prefix mapping applies to the child element (one deeper)
351
pushDepth = m_elemContext.m_currentElemDepth + 1;
352         }
353         else
354         {
355             // the prefix mapping applies to the current element
356
pushDepth = m_elemContext.m_currentElemDepth;
357         }
358         pushed = m_prefixMap.pushNamespace(prefix, uri, pushDepth);
359
360         if (pushed)
361         {
362             m_saxHandler.startPrefixMapping(prefix,uri);
363             
364             if (getShouldOutputNSAttr())
365             {
366
367                   /* bjm: don't know if we really needto do this. The
368                    * callers of this object should have injected both
369                    * startPrefixMapping and the attributes. We are
370                    * just covering our butt here.
371                    */

372                   String JavaDoc name;
373                 if (EMPTYSTRING.equals(prefix))
374                 {
375                     name = "xmlns";
376                     addAttributeAlways(XMLNS_URI, prefix, name,"CDATA",uri);
377                 }
378                 else
379                 {
380                     if (!EMPTYSTRING.equals(uri)) // hack for XSLTC attribset16 test
381
{ // that maps ns1 prefix to "" URI
382
name = "xmlns:" + prefix;
383     
384                         /* for something like xmlns:abc="w3.pretend.org"
385                              * the uri is the value, that is why we pass it in the
386                              * value, or 5th slot of addAttributeAlways()
387                            */

388                         addAttributeAlways(XMLNS_URI, prefix, name,"CDATA",uri);
389                     }
390                 }
391             }
392         }
393         return pushed;
394     }
395         
396
397     /**
398      * @see org.xml.sax.ext.LexicalHandler#comment(char[], int, int)
399      */

400     public void comment(char[] arg0, int arg1, int arg2) throws SAXException JavaDoc
401     {
402         flushPending();
403         if (m_lexHandler != null)
404             m_lexHandler.comment(arg0, arg1, arg2);
405             
406         if (m_tracer != null)
407             super.fireCommentEvent(arg0, arg1, arg2);
408     }
409
410     /**
411      * @see org.xml.sax.ext.LexicalHandler#endCDATA()
412      */

413     public void endCDATA() throws SAXException JavaDoc
414     {
415         /* Normally we would do somthing with this but we ignore it.
416          * The neccessary call to m_lexHandler.endCDATA() will be made
417          * in flushPending().
418          *
419          * This is so that if we get calls like these:
420          * this.startCDATA();
421          * this.characters(chars1, off1, len1);
422          * this.endCDATA();
423          * this.startCDATA();
424          * this.characters(chars2, off2, len2);
425          * this.endCDATA();
426          *
427          * that we will only make these calls to the wrapped handlers:
428          *
429          * m_lexHandler.startCDATA();
430          * m_saxHandler.characters(chars1, off1, len1);
431          * m_saxHandler.characters(chars1, off2, len2);
432          * m_lexHandler.endCDATA();
433          *
434          * We will merge adjacent CDATA blocks.
435          */

436     }
437
438     /**
439      * @see org.xml.sax.ext.LexicalHandler#endDTD()
440      */

441     public void endDTD() throws SAXException JavaDoc
442     {
443         if (m_lexHandler != null)
444             m_lexHandler.endDTD();
445     }
446
447     /**
448      * @see org.xml.sax.ext.LexicalHandler#startEntity(String)
449      */

450     public void startEntity(String JavaDoc arg0) throws SAXException JavaDoc
451     {
452         if (m_lexHandler != null)
453             m_lexHandler.startEntity(arg0);
454     }
455
456     /**
457      * @see org.apache.xml.serializer.ExtendedContentHandler#characters(String)
458      */

459     public void characters(String JavaDoc chars) throws SAXException JavaDoc
460     {
461         final int length = chars.length();
462         if (length > m_charsBuff.length)
463         {
464             m_charsBuff = new char[length*2 + 1];
465         }
466         chars.getChars(0, length, m_charsBuff, 0);
467         this.characters(m_charsBuff, 0, length);
468     }
469
470     /////////////////// from XSLTC //////////////
471
public ToXMLSAXHandler(ContentHandler JavaDoc handler, String JavaDoc encoding)
472     {
473         super(handler, encoding);
474
475         initCDATA();
476         // initNamespaces();
477
m_prefixMap = new NamespaceMappings();
478     }
479
480     public ToXMLSAXHandler(
481         ContentHandler JavaDoc handler,
482         LexicalHandler JavaDoc lex,
483         String JavaDoc encoding)
484     {
485         super(handler, lex, encoding);
486
487         initCDATA();
488         // initNamespaces();
489
m_prefixMap = new NamespaceMappings();
490     }
491
492     /**
493      * Start an element in the output document. This might be an XML element
494      * (<elem>data</elem> type) or a CDATA section.
495      */

496     public void startElement(
497     String JavaDoc elementNamespaceURI,
498     String JavaDoc elementLocalName,
499     String JavaDoc elementName) throws SAXException JavaDoc
500     {
501         startElement(
502             elementNamespaceURI,elementLocalName,elementName, null);
503
504
505     }
506     public void startElement(String JavaDoc elementName) throws SAXException JavaDoc
507     {
508         startElement(null, null, elementName, null);
509     }
510
511
512     public void characters(char[] ch, int off, int len) throws SAXException JavaDoc
513     {
514         // We do the first two things in flushPending() but we don't
515
// close any open CDATA calls.
516
if (m_needToCallStartDocument)
517         {
518             startDocumentInternal();
519             m_needToCallStartDocument = false;
520         }
521
522         if (m_elemContext.m_startTagOpen)
523         {
524             closeStartTag();
525             m_elemContext.m_startTagOpen = false;
526         }
527
528         if (m_elemContext.m_isCdataSection && !m_cdataTagOpen
529         && m_lexHandler != null)
530         {
531             m_lexHandler.startCDATA();
532             // We have made a call to m_lexHandler.startCDATA() with
533
// no balancing call to m_lexHandler.endCDATA()
534
// so we set m_cdataTagOpen true to remember this.
535
m_cdataTagOpen = true;
536         }
537         
538         /* If there are any occurances of "]]>" in the character data
539          * let m_saxHandler worry about it, we've already warned them with
540          * the previous call of m_lexHandler.startCDATA();
541          */

542         m_saxHandler.characters(ch, off, len);
543
544         // time to generate characters event
545
if (m_tracer != null)
546             fireCharEvent(ch, off, len);
547     }
548     
549
550     /**
551      * @see org.apache.xml.serializer.ExtendedContentHandler#endElement(String)
552      */

553     public void endElement(String JavaDoc elemName) throws SAXException JavaDoc
554     {
555         endElement(null, null, elemName);
556     }
557
558
559     /**
560      * Send a namespace declaration in the output document. The namespace
561      * declaration will not be include if the namespace is already in scope
562      * with the same prefix.
563      */

564     public void namespaceAfterStartElement(
565         final String JavaDoc prefix,
566         final String JavaDoc uri)
567         throws SAXException JavaDoc
568     {
569         startPrefixMapping(prefix,uri,false);
570     }
571
572     /**
573      *
574      * @see org.xml.sax.ContentHandler#processingInstruction(String, String)
575      * Send a processing instruction to the output document
576      */

577     public void processingInstruction(String JavaDoc target, String JavaDoc data)
578         throws SAXException JavaDoc
579     {
580         flushPending();
581
582         // Pass the processing instruction to the SAX handler
583
m_saxHandler.processingInstruction(target, data);
584
585         // we don't want to leave serializer to fire off this event,
586
// so do it here.
587
if (m_tracer != null)
588             super.fireEscapingEvent(target, data);
589     }
590
591     /**
592      * Undeclare the namespace that is currently pointed to by a given
593      * prefix. Inform SAX handler if prefix was previously mapped.
594      */

595     protected boolean popNamespace(String JavaDoc prefix)
596     {
597         try
598         {
599             if (m_prefixMap.popNamespace(prefix))
600             {
601                 m_saxHandler.endPrefixMapping(prefix);
602                 return true;
603             }
604         }
605         catch (SAXException JavaDoc e)
606         {
607             // falls through
608
}
609         return false;
610     }
611
612     public void startCDATA() throws SAXException JavaDoc
613     {
614         /* m_cdataTagOpen can only be true here if we have ignored the
615          * previous call to this.endCDATA() and the previous call
616          * this.startCDATA() before that is still "open". In this way
617          * we merge adjacent CDATA. If anything else happened after the
618          * ignored call to this.endCDATA() and this call then a call to
619          * flushPending() would have been made which would have
620          * closed the CDATA and set m_cdataTagOpen to false.
621          */

622         if (!m_cdataTagOpen )
623         {
624             flushPending();
625             if (m_lexHandler != null) {
626                 m_lexHandler.startCDATA();
627
628                 // We have made a call to m_lexHandler.startCDATA() with
629
// no balancing call to m_lexHandler.endCDATA()
630
// so we set m_cdataTagOpen true to remember this.
631
m_cdataTagOpen = true;
632             }
633         }
634     }
635
636     /**
637      * @see org.xml.sax.ContentHandler#startElement(String, String, String, Attributes)
638      */

639     public void startElement(
640     String JavaDoc namespaceURI,
641     String JavaDoc localName,
642     String JavaDoc name,
643     Attributes JavaDoc atts)
644         throws SAXException JavaDoc
645     {
646         flushPending();
647         super.startElement(namespaceURI, localName, name, atts);
648
649         // Handle document type declaration (for first element only)
650
if (m_needToOutputDocTypeDecl)
651          {
652              String JavaDoc doctypeSystem = getDoctypeSystem();
653              if (doctypeSystem != null && m_lexHandler != null)
654              {
655                  String JavaDoc doctypePublic = getDoctypePublic();
656                  if (doctypeSystem != null)
657                      m_lexHandler.startDTD(
658                          name,
659                          doctypePublic,
660                          doctypeSystem);
661              }
662              m_needToOutputDocTypeDecl = false;
663          }
664         m_elemContext = m_elemContext.push(namespaceURI, localName, name);
665
666         // ensurePrefixIsDeclared depends on the current depth, so
667
// the previous increment is necessary where it is.
668
if (namespaceURI != null)
669             ensurePrefixIsDeclared(namespaceURI, name);
670
671         // add the attributes to the collected ones
672
if (atts != null)
673             addAttributes(atts);
674
675          
676         // do we really need this CDATA section state?
677
m_elemContext.m_isCdataSection = isCdataSection();
678    
679     }
680  
681     private void ensurePrefixIsDeclared(String JavaDoc ns, String JavaDoc rawName)
682         throws org.xml.sax.SAXException JavaDoc
683     {
684
685         if (ns != null && ns.length() > 0)
686         {
687             int index;
688             String JavaDoc prefix =
689                 (index = rawName.indexOf(":")) < 0
690                     ? ""
691                     : rawName.substring(0, index);
692
693             if (null != prefix)
694             {
695                 String JavaDoc foundURI = m_prefixMap.lookupNamespace(prefix);
696
697                 if ((null == foundURI) || !foundURI.equals(ns))
698                 {
699                     this.startPrefixMapping(prefix, ns, false);
700
701                     if (getShouldOutputNSAttr()) {
702                         // Bugzilla1133: Generate attribute as well as namespace event.
703
// SAX does expect both.
704
this.addAttributeAlways(
705                             "http://www.w3.org/2000/xmlns/",
706                             prefix,
707                             "xmlns" + (prefix.length() == 0 ? "" : ":") + prefix,
708                             "CDATA",
709                             ns);
710                     }
711                 }
712
713             }
714         }
715     }
716     /**
717      * Adds the given attribute to the set of attributes, and also makes sure
718      * that the needed prefix/uri mapping is declared, but only if there is a
719      * currently open element.
720      *
721      * @param uri the URI of the attribute
722      * @param localName the local name of the attribute
723      * @param rawName the qualified name of the attribute
724      * @param type the type of the attribute (probably CDATA)
725      * @param value the value of the attribute
726      * @see org.apache.xml.serializer.ExtendedContentHandler#addAttribute(String, String, String, String, String)
727      */

728     public void addAttribute(
729         String JavaDoc uri,
730         String JavaDoc localName,
731         String JavaDoc rawName,
732         String JavaDoc type,
733         String JavaDoc value)
734         throws SAXException JavaDoc
735     {
736         if (m_elemContext.m_startTagOpen)
737         {
738             ensurePrefixIsDeclared(uri, rawName);
739             addAttributeAlways(uri, localName, rawName, type, value);
740         }
741
742     }
743        
744     /**
745      * Try's to reset the super class and reset this class for
746      * re-use, so that you don't need to create a new serializer
747      * (mostly for performance reasons).
748      *
749      * @return true if the class was successfuly reset.
750      * @see org.apache.xml.serializer.Serializer#reset()
751      */

752     public boolean reset()
753     {
754         boolean wasReset = false;
755         if (super.reset())
756         {
757             resetToXMLSAXHandler();
758             wasReset = true;
759         }
760         return wasReset;
761     }
762     
763     /**
764      * Reset all of the fields owned by ToXMLSAXHandler class
765      *
766      */

767     private void resetToXMLSAXHandler()
768     {
769         this.m_escapeSetting = false;
770     }
771
772 }
773
Popular Tags