KickJava   Java API By Example, From Geeks To Geeks.

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


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: SerializerBase.java,v 1.10 2004/02/17 04:18:18 minchau Exp $
18  */

19 package org.apache.xml.serializer;
20
21 import java.io.IOException JavaDoc;
22 import java.util.Hashtable JavaDoc;
23 import java.util.Stack JavaDoc;
24 import java.util.Vector JavaDoc;
25
26 import javax.xml.transform.SourceLocator JavaDoc;
27 import javax.xml.transform.Transformer JavaDoc;
28
29 import org.apache.xml.res.XMLErrorResources;
30 import org.apache.xml.res.XMLMessages;
31 import org.apache.xml.utils.BoolStack;
32 import org.xml.sax.Attributes JavaDoc;
33 import org.xml.sax.ContentHandler JavaDoc;
34 import org.xml.sax.Locator JavaDoc;
35 import org.xml.sax.SAXException JavaDoc;
36 import org.xml.sax.SAXParseException JavaDoc;
37
38
39 /**
40  * This class acts as a base class for the XML "serializers"
41  * and the stream serializers.
42  * It contains a number of common fields and methods.
43  * @author Santiago Pericas-Geertsen
44  * @author G. Todd Miller
45  */

46 abstract public class SerializerBase
47     implements SerializationHandler, SerializerConstants, org.apache.xml.dtm.ref.dom2dtm.DOM2DTM.CharacterNodeHandler
48 {
49     
50
51     /**
52      * To fire off the end element trace event
53      * @param name Name of element
54      */

55     protected void fireEndElem(String JavaDoc name)
56         throws org.xml.sax.SAXException JavaDoc
57     {
58         if (m_tracer != null)
59         {
60             flushMyWriter();
61             m_tracer.fireGenerateEvent(SerializerTrace.EVENTTYPE_ENDELEMENT,name, (Attributes JavaDoc)null);
62         }
63     }
64
65     /**
66      * Report the characters trace event
67      * @param chars content of characters
68      * @param start starting index of characters to output
69      * @param length number of characters to output
70      */

71     protected void fireCharEvent(char[] chars, int start, int length)
72         throws org.xml.sax.SAXException JavaDoc
73     {
74         if (m_tracer != null)
75         {
76             flushMyWriter();
77             m_tracer.fireGenerateEvent(SerializerTrace.EVENTTYPE_CHARACTERS, chars, start,length);
78         }
79     }
80
81     /**
82      * true if we still need to call startDocumentInternal()
83      */

84     protected boolean m_needToCallStartDocument = true;
85
86     /** True if a trailing "]]>" still needs to be written to be
87      * written out. Used to merge adjacent CDATA sections
88      */

89     protected boolean m_cdataTagOpen = false;
90
91     /**
92      * All the attributes of the current element, collected from
93      * startPrefixMapping() calls, or addAddtribute() calls, or
94      * from the SAX attributes in a startElement() call.
95      */

96     protected AttributesImplSerializer m_attributes = new AttributesImplSerializer();
97
98     /**
99      * Tells if we're in an EntityRef event.
100      */

101     protected boolean m_inEntityRef = false;
102
103     /** This flag is set while receiving events from the external DTD */
104     protected boolean m_inExternalDTD = false;
105
106     /**
107      * The System ID for the doc type.
108      */

109     private String JavaDoc m_doctypeSystem;
110
111     /**
112      * The public ID for the doc type.
113      */

114     private String JavaDoc m_doctypePublic;
115
116     /**
117      * Flag to tell that we need to add the doctype decl, which we can't do
118      * until the first element is encountered.
119      */

120     boolean m_needToOutputDocTypeDecl = true;
121
122     /**
123      * The character encoding. Must match the encoding used for the
124      * printWriter.
125      */

126     private String JavaDoc m_encoding = null;
127
128     /**
129      * Tells if we should write the XML declaration.
130      */

131     private boolean m_shouldNotWriteXMLHeader = false;
132
133     /**
134      * The standalone value for the doctype.
135      */

136     private String JavaDoc m_standalone;
137
138     /**
139      * True if standalone was specified.
140      */

141     protected boolean m_standaloneWasSpecified = false;
142
143     /**
144      * Flag to tell if indenting (pretty-printing) is on.
145      */

146     protected boolean m_doIndent = false;
147     /**
148      * Amount to indent.
149      */

150     protected int m_indentAmount = 0;
151
152     /**
153      * Tells the XML version, for writing out to the XML decl.
154      */

155     private String JavaDoc m_version = null;
156
157     /**
158      * The mediatype. Not used right now.
159      */

160     private String JavaDoc m_mediatype;
161
162     /**
163      * The transformer that was around when this output handler was created (if
164      * any).
165      */

166     private Transformer JavaDoc m_transformer;
167
168     /**
169      * Pairs of local names and corresponding URIs of CDATA sections. This list
170      * comes from the cdata-section-elements attribute. Every second one is a
171      * local name, and every other second one is the URI for the local name.
172      */

173     protected Vector JavaDoc m_cdataSectionElements = null;
174
175     /**
176      * Namespace support, that keeps track of currently defined
177      * prefix/uri mappings. As processed elements come and go, so do
178      * the associated mappings for that element.
179      */

180     protected NamespaceMappings m_prefixMap;
181     
182     /**
183      * Handle for firing generate events. This interface may be implemented
184      * by the referenced transformer object.
185      */

186     protected SerializerTrace m_tracer;
187     
188     protected SourceLocator JavaDoc m_sourceLocator;
189     
190
191     /**
192      * The writer to send output to. This field is only used in the ToStream
193      * serializers, but exists here just so that the fireStartDoc() and
194      * other fire... methods can flush this writer when tracing.
195      */

196     protected java.io.Writer JavaDoc m_writer = null;
197     
198     /**
199      * A reference to "stack frame" corresponding to
200      * the current element. Such a frame is pushed at a startElement()
201      * and popped at an endElement(). This frame contains information about
202      * the element, such as its namespace URI.
203      */

204     protected ElemContext m_elemContext = new ElemContext();
205     
206     /**
207      * A utility buffer for converting Strings passed to
208      * character() methods to character arrays.
209      * Reusing this buffer means not creating a new character array
210      * everytime and it runs faster.
211      */

212     protected char[] m_charsBuff = new char[60];
213     
214     /**
215      * A utility buffer for converting Strings passed to
216      * attribute methods to character arrays.
217      * Reusing this buffer means not creating a new character array
218      * everytime and it runs faster.
219      */

220     protected char[] m_attrBuff = new char[30];
221
222     /**
223      * Receive notification of a comment.
224      *
225      * @see org.apache.xml.serializer.ExtendedLexicalHandler#comment(String)
226      */

227     public void comment(String JavaDoc data) throws SAXException JavaDoc
228     {
229         final int length = data.length();
230         if (length > m_charsBuff.length)
231         {
232             m_charsBuff = new char[length * 2 + 1];
233         }
234         data.getChars(0, length, m_charsBuff, 0);
235         comment(m_charsBuff, 0, length);
236     }
237
238     /**
239       * TODO: This method is a HACK! Since XSLTC does not have access to the
240       * XML file, it sometimes generates a NS prefix of the form "ns?" for
241       * an attribute. If at runtime, when the qname of the attribute is
242       * known, another prefix is specified for the attribute, then we can get
243       * a qname of the form "ns?:otherprefix:name". This function patches the
244       * qname by simply ignoring "otherprefix".
245       */

246     protected String JavaDoc patchName(String JavaDoc qname)
247     {
248
249         
250         final int lastColon = qname.lastIndexOf(':');
251
252         if (lastColon > 0) {
253             final int firstColon = qname.indexOf(':');
254             final String JavaDoc prefix = qname.substring(0, firstColon);
255             final String JavaDoc localName = qname.substring(lastColon + 1);
256
257         // If uri is "" then ignore prefix
258
final String JavaDoc uri = m_prefixMap.lookupNamespace(prefix);
259             if (uri != null && uri.length() == 0) {
260                 return localName;
261             }
262             else if (firstColon != lastColon) {
263                 return prefix + ':' + localName;
264             }
265         }
266         return qname;
267     }
268
269     /**
270      * Returns the local name of a qualified name. If the name has no prefix,
271      * then it works as the identity (SAX2).
272      * @param qname the qualified name
273      * @return the name, but excluding any prefix and colon.
274      */

275     protected static String JavaDoc getLocalName(String JavaDoc qname)
276     {
277         final int col = qname.lastIndexOf(':');
278         return (col > 0) ? qname.substring(col + 1) : qname;
279     }
280
281     /**
282      * Receive an object for locating the origin of SAX document events.
283      *
284      * @param locator An object that can return the location of any SAX document
285      * event.
286      *
287      * Receive an object for locating the origin of SAX document events.
288      *
289      * <p>SAX parsers are strongly encouraged (though not absolutely
290      * required) to supply a locator: if it does so, it must supply
291      * the locator to the application by invoking this method before
292      * invoking any of the other methods in the DocumentHandler
293      * interface.</p>
294      *
295      * <p>The locator allows the application to determine the end
296      * position of any document-related event, even if the parser is
297      * not reporting an error. Typically, the application will
298      * use this information for reporting its own errors (such as
299      * character content that does not match an application's
300      * business rules). The information returned by the locator
301      * is probably not sufficient for use with a search engine.</p>
302      *
303      * <p>Note that the locator will return correct information only
304      * during the invocation of the events in this interface. The
305      * application should not attempt to use it at any other time.</p>
306      */

307     public void setDocumentLocator(Locator JavaDoc locator)
308     {
309         return;
310
311         // I don't do anything with this yet.
312
}
313
314     /**
315      * Adds the given attribute to the set of collected attributes , but only if
316      * there is a currently open element.
317      *
318      * An element is currently open if a startElement() notification has
319      * occured but the start of the element has not yet been written to the
320      * output. In the stream case this means that we have not yet been forced
321      * to close the elements opening tag by another notification, such as a
322      * character notification.
323      *
324      * @param uri the URI of the attribute
325      * @param localName the local name of the attribute
326      * @param rawName the qualified name of the attribute
327      * @param type the type of the attribute (probably CDATA)
328      * @param value the value of the attribute
329      * @see org.apache.xml.serializer.ExtendedContentHandler#addAttribute(String, String, String, String, String)
330      */

331     public void addAttribute(
332         String JavaDoc uri,
333         String JavaDoc localName,
334         String JavaDoc rawName,
335         String JavaDoc type,
336         String JavaDoc value)
337         throws SAXException JavaDoc
338     {
339         if (m_elemContext.m_startTagOpen)
340         {
341             addAttributeAlways(uri, localName, rawName, type, value);
342         }
343
344     }
345     
346     /**
347      * Adds the given attribute to the set of attributes, even if there is
348      * no currently open element. This is useful if a SAX startPrefixMapping()
349      * should need to add an attribute before the element name is seen.
350      *
351      * @param uri the URI of the attribute
352      * @param localName the local name of the attribute
353      * @param rawName the qualified name of the attribute
354      * @param type the type of the attribute (probably CDATA)
355      * @param value the value of the attribute
356      */

357     public void addAttributeAlways(
358         String JavaDoc uri,
359         String JavaDoc localName,
360         String JavaDoc rawName,
361         String JavaDoc type,
362         String JavaDoc value)
363     {
364 // final int index =
365
// (localName == null || uri == null) ?
366
// m_attributes.getIndex(rawName):m_attributes.getIndex(uri, localName);
367
int index;
368 // if (localName == null || uri == null){
369
// index = m_attributes.getIndex(rawName);
370
// }
371
// else {
372
// index = m_attributes.getIndex(uri, localName);
373
// }
374
index = m_attributes.getIndex(rawName);
375             if (index >= 0)
376             {
377                 /* We've seen the attribute before.
378                  * We may have a null uri or localName, but all
379                  * we really want to re-set is the value anyway.
380                  */

381                 m_attributes.setValue(index,value);
382             }
383             else
384             {
385                 // the attribute doesn't exist yet, create it
386
m_attributes.addAttribute(uri, localName, rawName, type, value);
387             }
388         
389     }
390   
391
392     /**
393      * Adds the given attribute to the set of collected attributes,
394      * but only if there is a currently open element. This method is only
395      * called by XSLTC.
396      *
397      * @param name the attribute's qualified name
398      * @param value the value of the attribute
399      */

400     public void addAttribute(String JavaDoc name, final String JavaDoc value)
401     {
402         if (m_elemContext.m_startTagOpen)
403         {
404             final String JavaDoc patchedName = patchName(name);
405             final String JavaDoc localName = getLocalName(patchedName);
406             final String JavaDoc uri = getNamespaceURI(patchedName, false);
407
408             addAttributeAlways(uri,localName, patchedName, "CDATA", value);
409          }
410     }
411
412
413     /**
414      * Add the given attributes to the currently collected ones. These
415      * attributes are always added, regardless of whether on not an element
416      * is currently open.
417      * @param atts List of attributes to add to this list
418      */

419     public void addAttributes(Attributes JavaDoc atts) throws SAXException JavaDoc
420     {
421
422         int nAtts = atts.getLength();
423
424         for (int i = 0; i < nAtts; i++)
425         {
426             String JavaDoc uri = atts.getURI(i);
427
428             if (null == uri)
429                 uri = "";
430
431             addAttributeAlways(
432                 uri,
433                 atts.getLocalName(i),
434                 atts.getQName(i),
435                 atts.getType(i),
436                 atts.getValue(i));
437
438         }
439     }
440
441     /**
442      * Return a {@link ContentHandler} interface into this serializer.
443      * If the serializer does not support the {@link ContentHandler}
444      * interface, it should return null.
445      *
446      * @return A {@link ContentHandler} interface into this serializer,
447      * or null if the serializer is not SAX 2 capable
448      * @throws IOException An I/O exception occured
449      */

450     public ContentHandler JavaDoc asContentHandler() throws IOException JavaDoc
451     {
452         return this;
453     }
454
455     /**
456      * Report the end of an entity.
457      *
458      * @param name The name of the entity that is ending.
459      * @throws org.xml.sax.SAXException The application may raise an exception.
460      * @see #startEntity
461      */

462     public void endEntity(String JavaDoc name) throws org.xml.sax.SAXException JavaDoc
463     {
464         if (name.equals("[dtd]"))
465             m_inExternalDTD = false;
466         m_inEntityRef = false;
467
468         if (m_tracer != null)
469             this.fireEndEntity(name);
470     }
471
472     /**
473      * Flush and close the underlying java.io.Writer. This method applies to
474      * ToStream serializers, not ToSAXHandler serializers.
475      * @see org.apache.xml.serializer.ToStream
476      */

477     public void close()
478     {
479         // do nothing (base behavior)
480
}
481
482     /**
483      * Initialize global variables
484      */

485     protected void initCDATA()
486     {
487         // CDATA stack
488
// _cdataStack = new Stack();
489
// _cdataStack.push(new Integer(-1)); // push dummy value
490
}
491
492     /**
493      * Returns the character encoding to be used in the output document.
494      * @return the character encoding to be used in the output document.
495      */

496     public String JavaDoc getEncoding()
497     {
498         return m_encoding;
499     }
500
501    /**
502      * Sets the character encoding coming from the xsl:output encoding stylesheet attribute.
503      * @param encoding the character encoding
504      */

505     public void setEncoding(String JavaDoc m_encoding)
506     {
507         this.m_encoding = m_encoding;
508     }
509
510     /**
511      * Sets the value coming from the xsl:output omit-xml-declaration stylesheet attribute
512      * @param b true if the XML declaration is to be omitted from the output
513      * document.
514      */

515     public void setOmitXMLDeclaration(boolean b)
516     {
517         this.m_shouldNotWriteXMLHeader = b;
518     }
519
520
521     /**
522      * @return true if the XML declaration is to be omitted from the output
523      * document.
524      */

525     public boolean getOmitXMLDeclaration()
526     {
527         return m_shouldNotWriteXMLHeader;
528     }
529
530     /**
531      * Returns the previously set value of the value to be used as the public
532      * identifier in the document type declaration (DTD).
533      *
534      *@return the public identifier to be used in the DOCTYPE declaration in the
535      * output document.
536      */

537     public String JavaDoc getDoctypePublic()
538     {
539         return m_doctypePublic;
540     }
541
542     /** Set the value coming from the xsl:output doctype-public stylesheet attribute.
543       * @param doctypePublic the public identifier to be used in the DOCTYPE
544       * declaration in the output document.
545       */

546     public void setDoctypePublic(String JavaDoc doctypePublic)
547     {
548         this.m_doctypePublic = doctypePublic;
549     }
550
551
552     /**
553      * Returns the previously set value of the value to be used
554      * as the system identifier in the document type declaration (DTD).
555      * @return the system identifier to be used in the DOCTYPE declaration in
556      * the output document.
557      *
558      */

559     public String JavaDoc getDoctypeSystem()
560     {
561         return m_doctypeSystem;
562     }
563
564     /** Set the value coming from the xsl:output doctype-system stylesheet attribute.
565       * @param doctypeSystem the system identifier to be used in the DOCTYPE
566       * declaration in the output document.
567       */

568     public void setDoctypeSystem(String JavaDoc doctypeSystem)
569     {
570         this.m_doctypeSystem = doctypeSystem;
571     }
572
573     /** Set the value coming from the xsl:output doctype-public and doctype-system stylesheet properties
574      * @param doctypeSystem the system identifier to be used in the DOCTYPE
575      * declaration in the output document.
576      * @param doctypePublic the public identifier to be used in the DOCTYPE
577      * declaration in the output document.
578      */

579     public void setDoctype(String JavaDoc doctypeSystem, String JavaDoc doctypePublic)
580     {
581         this.m_doctypeSystem = doctypeSystem;
582         this.m_doctypePublic = doctypePublic;
583     }
584
585     /**
586      * Sets the value coming from the xsl:output standalone stylesheet attribute.
587      * @param standalone a value of "yes" indicates that the
588      * <code>standalone</code> delaration is to be included in the output
589      * document. This method remembers if the value was explicitly set using
590      * this method, verses if the value is the default value.
591      */

592     public void setStandalone(String JavaDoc standalone)
593     {
594         if (standalone != null)
595         {
596             m_standaloneWasSpecified = true;
597             setStandaloneInternal(standalone);
598         }
599     }
600     /**
601      * Sets the XSL standalone attribute, but does not remember if this is a
602      * default or explicite setting.
603      * @param standalone "yes" | "no"
604      */

605     protected void setStandaloneInternal(String JavaDoc standalone)
606     {
607         if ("yes".equals(standalone))
608             m_standalone = "yes";
609         else
610             m_standalone = "no";
611         
612     }
613
614     /**
615      * Gets the XSL standalone attribute
616      * @return a value of "yes" if the <code>standalone</code> delaration is to
617      * be included in the output document.
618      * @see org.apache.xml.serializer.XSLOutputAttributes#getStandalone()
619      */

620     public String JavaDoc getStandalone()
621     {
622         return m_standalone;
623     }
624
625     /**
626      * @return true if the output document should be indented to visually
627      * indicate its structure.
628      */

629     public boolean getIndent()
630     {
631         return m_doIndent;
632     }
633     /**
634      * Gets the mediatype the media-type or MIME type associated with the output
635      * document.
636      * @return the mediatype the media-type or MIME type associated with the
637      * output document.
638      */

639     public String JavaDoc getMediaType()
640     {
641         return m_mediatype;
642     }
643
644     /**
645      * Gets the version of the output format.
646      * @return the version of the output format.
647      */

648     public String JavaDoc getVersion()
649     {
650         return m_version;
651     }
652
653     /**
654      * Sets the value coming from the xsl:output version attribute.
655      * @param version the version of the output format.
656      * @see org.apache.xml.serializer.SerializationHandler#setVersion(String)
657      */

658     public void setVersion(String JavaDoc version)
659     {
660         m_version = version;
661     }
662
663     /**
664      * Sets the value coming from the xsl:output media-type stylesheet attribute.
665      * @param mediaType the non-null media-type or MIME type associated with the
666      * output document.
667      * @see javax.xml.transform.OutputKeys#MEDIA_TYPE
668      * @see org.apache.xml.serializer.SerializationHandler#setMediaType(String)
669      */

670     public void setMediaType(String JavaDoc mediaType)
671     {
672         m_mediatype = mediaType;
673     }
674
675     /**
676      * @return the number of spaces to indent for each indentation level.
677      */

678     public int getIndentAmount()
679     {
680         return m_indentAmount;
681     }
682
683     /**
684      * Sets the indentation amount.
685      * @param m_indentAmount The m_indentAmount to set
686      */

687     public void setIndentAmount(int m_indentAmount)
688     {
689         this.m_indentAmount = m_indentAmount;
690     }
691
692     /**
693      * Sets the value coming from the xsl:output indent stylesheet
694      * attribute.
695      * @param doIndent true if the output document should be indented to
696      * visually indicate its structure.
697      * @see org.apache.xml.serializer.XSLOutputAttributes#setIndent(boolean)
698      */

699     public void setIndent(boolean doIndent)
700     {
701         m_doIndent = doIndent;
702     }
703
704     /**
705      * This method is used when a prefix/uri namespace mapping
706      * is indicated after the element was started with a
707      * startElement() and before and endElement().
708      * startPrefixMapping(prefix,uri) would be used before the
709      * startElement() call.
710      * @param uri the URI of the namespace
711      * @param prefix the prefix associated with the given URI.
712      *
713      * @see org.apache.xml.serializer.ExtendedContentHandler#namespaceAfterStartElement(String, String)
714      */

715     public void namespaceAfterStartElement(String JavaDoc uri, String JavaDoc prefix)
716         throws SAXException JavaDoc
717     {
718         // default behavior is to do nothing
719
}
720
721     /**
722      * Return a {@link DOMSerializer} interface into this serializer. If the
723      * serializer does not support the {@link DOMSerializer} interface, it should
724      * return null.
725      *
726      * @return A {@link DOMSerializer} interface into this serializer, or null
727      * if the serializer is not DOM capable
728      * @throws IOException An I/O exception occured
729      * @see org.apache.xml.serializer.Serializer#asDOMSerializer()
730      */

731     public DOMSerializer asDOMSerializer() throws IOException JavaDoc
732     {
733         return this;
734     }
735
736     /**
737      * Push a boolean state based on if the name of the element
738      * is found in the list of qnames. A state is only pushed if
739      * there were some cdata-section-names were specified.
740      *
741      * @param namespaceURI Should be a non-null reference to the namespace URL
742      * of the element that owns the state, or empty string.
743      * @param localName Should be a non-null reference to the local name
744      * of the element that owns the state.
745      *
746      * Hidden parameters are the vector of qualified elements specified in
747      * cdata-section-names attribute, and the m_cdataSectionStates stack
748      * onto which whether the current element is in the list is pushed (true or
749      * false). Other hidden parameters are the current elements namespaceURI,
750      * localName and qName
751      */

752     protected boolean isCdataSection()
753     {
754
755         boolean b = false;
756
757         if (null != m_cdataSectionElements)
758         {
759             if (m_elemContext.m_elementLocalName == null)
760                 m_elemContext.m_elementLocalName =
761                     getLocalName(m_elemContext.m_elementName);
762             if (m_elemContext.m_elementURI == null)
763             {
764                 String JavaDoc prefix = getPrefixPart(m_elemContext.m_elementName);
765                 if (prefix != null)
766                     m_elemContext.m_elementURI =
767                         m_prefixMap.lookupNamespace(prefix);
768
769             }
770
771             if ((null != m_elemContext.m_elementURI)
772                 && m_elemContext.m_elementURI.length() == 0)
773                 m_elemContext.m_elementURI = null;
774
775             int nElems = m_cdataSectionElements.size();
776
777             // loop through 2 at a time, as these are pairs of URI and localName
778
for (int i = 0; i < nElems; i += 2)
779             {
780                 String JavaDoc uri = (String JavaDoc) m_cdataSectionElements.elementAt(i);
781                 String JavaDoc loc = (String JavaDoc) m_cdataSectionElements.elementAt(i + 1);
782                 if (loc.equals(m_elemContext.m_elementLocalName)
783                     && subPartMatch(m_elemContext.m_elementURI, uri))
784                 {
785                     b = true;
786
787                     break;
788                 }
789             }
790         }
791         return b;
792     }
793
794     /**
795      * Tell if two strings are equal, without worry if the first string is null.
796      *
797      * @param p String reference, which may be null.
798      * @param t String reference, which may be null.
799      *
800      * @return true if strings are equal.
801      */

802     private static final boolean subPartMatch(String JavaDoc p, String JavaDoc t)
803     {
804         return (p == t) || ((null != p) && (p.equals(t)));
805     }
806
807     /**
808      * Returns the local name of a qualified name.
809      * If the name has no prefix,
810      * then it works as the identity (SAX2).
811      *
812      * @param qname a qualified name
813      * @return returns the prefix of the qualified name,
814      * or null if there is no prefix.
815      */

816     protected static final String JavaDoc getPrefixPart(String JavaDoc qname)
817     {
818         final int col = qname.indexOf(':');
819         return (col > 0) ? qname.substring(0, col) : null;
820         //return (col > 0) ? qname.substring(0,col) : "";
821
}
822
823     /**
824      * Some users of the serializer may need the current namespace mappings
825      * @return the current namespace mappings (prefix/uri)
826      * @see org.apache.xml.serializer.ExtendedContentHandler#getNamespaceMappings()
827      */

828     public NamespaceMappings getNamespaceMappings()
829     {
830         return m_prefixMap;
831     }
832
833     /**
834      * Returns the prefix currently pointing to the given URI (if any).
835      * @param namespaceURI the uri of the namespace in question
836      * @return a prefix pointing to the given URI (if any).
837      * @see org.apache.xml.serializer.ExtendedContentHandler#getPrefix(String)
838      */

839     public String JavaDoc getPrefix(String JavaDoc namespaceURI)
840     {
841         String JavaDoc prefix = m_prefixMap.lookupPrefix(namespaceURI);
842         return prefix;
843     }
844
845     /**
846      * Returns the URI of an element or attribute. Note that default namespaces
847      * do not apply directly to attributes.
848      * @param qname a qualified name
849      * @param isElement true if the qualified name is the name of
850      * an element.
851      * @return returns the namespace URI associated with the qualified name.
852      */

853     public String JavaDoc getNamespaceURI(String JavaDoc qname, boolean isElement)
854     {
855         String JavaDoc uri = EMPTYSTRING;
856         int col = qname.lastIndexOf(':');
857         final String JavaDoc prefix = (col > 0) ? qname.substring(0, col) : EMPTYSTRING;
858
859         if (!EMPTYSTRING.equals(prefix) || isElement)
860         {
861             if (m_prefixMap != null)
862             {
863                 uri = m_prefixMap.lookupNamespace(prefix);
864                 if (uri == null && !prefix.equals(XMLNS_PREFIX))
865                 {
866                     throw new RuntimeException JavaDoc(
867                         XMLMessages.createXMLMessage(
868                             XMLErrorResources.ER_NAMESPACE_PREFIX,
869                             new Object JavaDoc[] { qname.substring(0, col) } ));
870                 }
871             }
872         }
873         return uri;
874     }
875
876     /**
877      * Returns the URI of prefix (if any)
878      *
879      * @param prefix the prefix whose URI is searched for
880      * @return the namespace URI currently associated with the
881      * prefix, null if the prefix is undefined.
882      */

883     public String JavaDoc getNamespaceURIFromPrefix(String JavaDoc prefix)
884     {
885         String JavaDoc uri = null;
886         if (m_prefixMap != null)
887             uri = m_prefixMap.lookupNamespace(prefix);
888         return uri;
889     }
890
891     /**
892      * Entity reference event.
893      *
894      * @param name Name of entity
895      *
896      * @throws org.xml.sax.SAXException
897      */

898     public void entityReference(String JavaDoc name) throws org.xml.sax.SAXException JavaDoc
899     {
900
901         flushPending();
902
903         startEntity(name);
904         endEntity(name);
905
906         if (m_tracer != null)
907             fireEntityReference(name);
908     }
909
910     /**
911      * Sets the transformer associated with this serializer
912      * @param t the transformer associated with this serializer.
913      * @see org.apache.xml.serializer.SerializationHandler#setTransformer(Transformer)
914      */

915     public void setTransformer(Transformer JavaDoc t)
916     {
917         m_transformer = t;
918         
919         // If this transformer object implements the SerializerTrace interface
920
// then assign m_tracer to the transformer object so it can be used
921
// to fire trace events.
922
if ((m_transformer instanceof SerializerTrace) &&
923             (((SerializerTrace) m_transformer).hasTraceListeners())) {
924            m_tracer = (SerializerTrace) m_transformer;
925         } else {
926            m_tracer = null;
927         }
928     }
929     /**
930      * Gets the transformer associated with this serializer
931      * @return returns the transformer associated with this serializer.
932      * @see org.apache.xml.serializer.SerializationHandler#getTransformer()
933      */

934     public Transformer JavaDoc getTransformer()
935     {
936         return m_transformer;
937     }
938     
939     /**
940      * This method gets the nodes value as a String and uses that String as if
941      * it were an input character notification.
942      * @param node the Node to serialize
943      * @throws org.xml.sax.SAXException
944      */

945     public void characters(org.w3c.dom.Node JavaDoc node)
946         throws org.xml.sax.SAXException JavaDoc
947     {
948         flushPending();
949         String JavaDoc data = node.getNodeValue();
950         if (data != null)
951         {
952             final int length = data.length();
953             if (length > m_charsBuff.length)
954             {
955                 m_charsBuff = new char[length * 2 + 1];
956             }
957             data.getChars(0, length, m_charsBuff, 0);
958             characters(m_charsBuff, 0, length);
959         }
960     }
961     
962
963     /**
964      * @see org.xml.sax.ErrorHandler#error(SAXParseException)
965      */

966     public void error(SAXParseException JavaDoc exc) throws SAXException JavaDoc {
967     }
968
969     /**
970      * @see org.xml.sax.ErrorHandler#fatalError(SAXParseException)
971      */

972     public void fatalError(SAXParseException JavaDoc exc) throws SAXException JavaDoc {
973         
974       m_elemContext.m_startTagOpen = false;
975
976     }
977
978     /**
979      * @see org.xml.sax.ErrorHandler#warning(SAXParseException)
980      */

981     public void warning(SAXParseException JavaDoc exc) throws SAXException JavaDoc
982     {
983     }
984
985     /**
986      * To fire off start entity trace event
987      * @param name Name of entity
988      */

989     protected void fireStartEntity(String JavaDoc name)
990         throws org.xml.sax.SAXException JavaDoc
991     {
992         if (m_tracer != null)
993         {
994             flushMyWriter();
995             m_tracer.fireGenerateEvent(SerializerTrace.EVENTTYPE_ENTITYREF, name);
996         }
997     }
998
999     /**
1000     * Report the characters event
1001     * @param chars content of characters
1002     * @param start starting index of characters to output
1003     * @param length number of characters to output
1004     */

1005// protected void fireCharEvent(char[] chars, int start, int length)
1006
// throws org.xml.sax.SAXException
1007
// {
1008
// if (m_tracer != null)
1009
// m_tracer.fireGenerateEvent(SerializerTrace.EVENTTYPE_CHARACTERS, chars, start,length);
1010
// }
1011
//
1012

1013    /**
1014     * This method is only used internally when flushing the writer from the
1015     * various fire...() trace events. Due to the writer being wrapped with
1016     * SerializerTraceWriter it may cause the flush of these trace events:
1017     * EVENTTYPE_OUTPUT_PSEUDO_CHARACTERS
1018     * EVENTTYPE_OUTPUT_CHARACTERS
1019     * which trace the output written to the output stream.
1020     *
1021     */

1022    private void flushMyWriter()
1023    {
1024        if (m_writer != null)
1025        {
1026            try
1027            {
1028                m_writer.flush();
1029            }
1030            catch(IOException JavaDoc ioe)
1031            {
1032            
1033            }
1034        }
1035    }
1036    /**
1037     * Report the CDATA trace event
1038     * @param chars content of CDATA
1039     * @param start starting index of characters to output
1040     * @param length number of characters to output
1041     */

1042    protected void fireCDATAEvent(char[] chars, int start, int length)
1043        throws org.xml.sax.SAXException JavaDoc
1044    {
1045        if (m_tracer != null)
1046        {
1047            flushMyWriter();
1048            m_tracer.fireGenerateEvent(SerializerTrace.EVENTTYPE_CDATA, chars, start,length);
1049        }
1050    }
1051
1052    /**
1053     * Report the comment trace event
1054     * @param chars content of comment
1055     * @param start starting index of comment to output
1056     * @param length number of characters to output
1057     */

1058    protected void fireCommentEvent(char[] chars, int start, int length)
1059        throws org.xml.sax.SAXException JavaDoc
1060    {
1061        if (m_tracer != null)
1062        {
1063            flushMyWriter();
1064            m_tracer.fireGenerateEvent(SerializerTrace.EVENTTYPE_COMMENT, new String JavaDoc(chars, start, length));
1065        }
1066    }
1067
1068
1069    /**
1070     * To fire off end entity trace event
1071     * @param name Name of entity
1072     */

1073    public void fireEndEntity(String JavaDoc name)
1074        throws org.xml.sax.SAXException JavaDoc
1075    {
1076        if (m_tracer != null)
1077            flushMyWriter();
1078        // we do not need to handle this.
1079
}
1080
1081    /**
1082     * To fire off start document trace event
1083     */

1084     protected void fireStartDoc()
1085        throws org.xml.sax.SAXException JavaDoc
1086    {
1087        if (m_tracer != null)
1088        {
1089            flushMyWriter();
1090            m_tracer.fireGenerateEvent(SerializerTrace.EVENTTYPE_STARTDOCUMENT);
1091        }
1092    }
1093
1094
1095    /**
1096     * To fire off end document trace event
1097     */

1098    protected void fireEndDoc()
1099        throws org.xml.sax.SAXException JavaDoc
1100    {
1101        if (m_tracer != null)
1102        {
1103            flushMyWriter();
1104            m_tracer.fireGenerateEvent(SerializerTrace.EVENTTYPE_ENDDOCUMENT);
1105        }
1106    }
1107    
1108    /**
1109     * Report the start element trace event. This trace method needs to be
1110     * called just before the attributes are cleared.
1111     *
1112     * @param elemName the qualified name of the element
1113     *
1114     */

1115    protected void fireStartElem(String JavaDoc elemName)
1116        throws org.xml.sax.SAXException JavaDoc
1117    {
1118        if (m_tracer != null)
1119        {
1120            flushMyWriter();
1121            m_tracer.fireGenerateEvent(SerializerTrace.EVENTTYPE_STARTELEMENT,
1122                elemName, m_attributes);
1123        }
1124    }
1125
1126
1127    /**
1128     * To fire off the end element event
1129     * @param name Name of element
1130     */

1131// protected void fireEndElem(String name)
1132
// throws org.xml.sax.SAXException
1133
// {
1134
// if (m_tracer != null)
1135
// m_tracer.fireGenerateEvent(SerializerTrace.EVENTTYPE_ENDELEMENT,name, (Attributes)null);
1136
// }
1137

1138
1139    /**
1140     * To fire off the PI trace event
1141     * @param name Name of PI
1142     */

1143    protected void fireEscapingEvent(String JavaDoc name, String JavaDoc data)
1144        throws org.xml.sax.SAXException JavaDoc
1145    {
1146
1147        if (m_tracer != null)
1148        {
1149            flushMyWriter();
1150            m_tracer.fireGenerateEvent(SerializerTrace.EVENTTYPE_PI,name, data);
1151        }
1152    }
1153
1154
1155    /**
1156     * To fire off the entity reference trace event
1157     * @param name Name of entity reference
1158     */

1159    protected void fireEntityReference(String JavaDoc name)
1160        throws org.xml.sax.SAXException JavaDoc
1161    {
1162        if (m_tracer != null)
1163        {
1164            flushMyWriter();
1165            m_tracer.fireGenerateEvent(SerializerTrace.EVENTTYPE_ENTITYREF,name, (Attributes JavaDoc)null);
1166        }
1167    }
1168
1169    /**
1170     * Receive notification of the beginning of a document.
1171     * This method is never a self generated call,
1172     * but only called externally.
1173     *
1174     * <p>The SAX parser will invoke this method only once, before any
1175     * other methods in this interface or in DTDHandler (except for
1176     * setDocumentLocator).</p>
1177     *
1178     * @throws org.xml.sax.SAXException Any SAX exception, possibly
1179     * wrapping another exception.
1180     *
1181     * @throws org.xml.sax.SAXException
1182     */

1183    public void startDocument() throws org.xml.sax.SAXException JavaDoc
1184    {
1185
1186        // if we do get called with startDocument(), handle it right away
1187
startDocumentInternal();
1188        m_needToCallStartDocument = false;
1189        return;
1190    }
1191    
1192    /**
1193     * This method handles what needs to be done at a startDocument() call,
1194     * whether from an external caller, or internally called in the
1195     * serializer. Historically Xalan has not always called a startDocument()
1196     * although it always calls endDocument() on the serializer.
1197     * So the serializer must be flexible for that. Even if no external call is
1198     * made into startDocument() this method will always be called as a self
1199     * generated internal startDocument, it handles what needs to be done at a
1200     * startDocument() call.
1201     *
1202     * This method exists just to make sure that startDocument() is only ever
1203     * called from an external caller, which in principle is just a matter of
1204     * style.
1205     *
1206     * @throws SAXException
1207     */

1208    protected void startDocumentInternal() throws org.xml.sax.SAXException JavaDoc
1209    {
1210        if (m_tracer != null)
1211            this.fireStartDoc();
1212    }
1213    /**
1214     * This method is used to set the source locator, which might be used to
1215     * generated an error message.
1216     * @param locator the source locator
1217     *
1218     * @see org.apache.xml.serializer.ExtendedContentHandler#setSourceLocator(javax.xml.transform.SourceLocator)
1219     */

1220    public void setSourceLocator(SourceLocator JavaDoc locator)
1221    {
1222        m_sourceLocator = locator;
1223    }
1224
1225    
1226    /**
1227     * Used only by TransformerSnapshotImpl to restore the serialization
1228     * to a previous state.
1229     *
1230     * @param NamespaceMappings
1231     */

1232    public void setNamespaceMappings(NamespaceMappings mappings) {
1233        m_prefixMap = mappings;
1234    }
1235    
1236    public boolean reset()
1237    {
1238        resetSerializerBase();
1239        return true;
1240    }
1241    
1242    /**
1243     * Reset all of the fields owned by SerializerBase
1244     *
1245     */

1246    private void resetSerializerBase()
1247    {
1248        this.m_attributes.clear();
1249        this.m_cdataSectionElements = null;
1250        this.m_elemContext = new ElemContext();
1251        this.m_doctypePublic = null;
1252        this.m_doctypeSystem = null;
1253        this.m_doIndent = false;
1254        this.m_encoding = null;
1255        this.m_indentAmount = 0;
1256        this.m_inEntityRef = false;
1257        this.m_inExternalDTD = false;
1258        this.m_mediatype = null;
1259        this.m_needToCallStartDocument = true;
1260        this.m_needToOutputDocTypeDecl = false;
1261        if (this.m_prefixMap != null)
1262            this.m_prefixMap.reset();
1263        this.m_shouldNotWriteXMLHeader = false;
1264        this.m_sourceLocator = null;
1265        this.m_standalone = null;
1266        this.m_standaloneWasSpecified = false;
1267        this.m_tracer = null;
1268        this.m_transformer = null;
1269        this.m_version = null;
1270        // don't set writer to null, so that it might be re-used
1271
//this.m_writer = null;
1272
}
1273
1274}
1275
Popular Tags