You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@xalan.apache.org by sb...@apache.org on 2001/01/02 04:29:10 UTC
cvs commit: xml-xalan/java/src/org/apache/xalan/serialize SerializerToHTML.java SerializerToText.java SerializerToXML.java ElemDesc.java Serializer.java package.html FormatterToHTML.java FormatterToText.java FormatterToXML.java
sboag 01/01/01 19:29:10
Modified: java/src/org/apache/xalan/serialize ElemDesc.java
Serializer.java package.html
Added: java/src/org/apache/xalan/serialize SerializerToHTML.java
SerializerToText.java SerializerToXML.java
Removed: java/src/org/apache/xalan/serialize FormatterToHTML.java
FormatterToText.java FormatterToXML.java
Log:
Names of serializers changed from FormatterToXXX to SerializerToXXX.
Also, javadoc work done.
Revision Changes Path
1.3 +1 -1 xml-xalan/java/src/org/apache/xalan/serialize/ElemDesc.java
Index: ElemDesc.java
===================================================================
RCS file: /home/cvs/xml-xalan/java/src/org/apache/xalan/serialize/ElemDesc.java,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- ElemDesc.java 2000/12/06 05:37:08 1.2
+++ ElemDesc.java 2001/01/02 03:29:09 1.3
@@ -60,7 +60,7 @@
/**
* <meta name="usage" content="internal"/>
- * This class is in support of FormatterToHTML, and acts as a sort
+ * This class is in support of SerializerToHTML, and acts as a sort
* of element representative for HTML elements.
*/
class ElemDesc
1.3 +3 -47 xml-xalan/java/src/org/apache/xalan/serialize/Serializer.java
Index: Serializer.java
===================================================================
RCS file: /home/cvs/xml-xalan/java/src/org/apache/xalan/serialize/Serializer.java,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- Serializer.java 2000/12/06 05:37:09 1.2
+++ Serializer.java 2001/01/02 03:29:10 1.3
@@ -64,53 +64,9 @@
import org.xml.sax.ContentHandler;
/**
- * A serializer is used for serializing a document with a given output
- * method. The {@link Serializer} object serves as an anchor point for
- * setting the output stream and output format, for obtaining objects
- * for serializing the document, and for resetting the serializer.
- * <p>
- * Prior to using the serializer, the output format and output stream
- * or writer should be set. The serializer is then used in one of
- * three ways:
- * <ul>
- * <li>To serialize SAX 1 events call {@link #asDocumentHandler}
- * <li>To serialize SAX 2 events call {@link #asContentHandler}
- * <li>To serialize a DOM document call {@link #asDOMSerializer}
- * </ul>
- * <p>
- * The application may call one of these methods to obtain a way to
- * serialize the document. It may not attempt to use two different
- * handlers at the same time, nor should it use the same handler to
- * serialize two documents.
- * <p>
- * The serializer may be recycled and used with a different or the
- * same output format and output stream, by calling the {@link #reset}
- * method after completing serialization.
- * <p>
- * A serializer is not thread safe. Only one thread should call the
- * <tt>asXXX</tt> methods and use the returned handler.
- * <p>
- * Example:
- * <pre>
- * ser = SerializerFactory.getSerializer( Method.XML );
- * emptyDoc( ser, System.out );
- * emptyDoc( ser, System.err );
- * . . .
- *
- * void emptyDoc( Serializer ser, OutputStream os )
- * {
- * ser.setOutputStream( os );
- * ser.asDocumentHandler().startDocument();
- * ser.asDocumentHandler().startElement( "empty", new AttributeListImpl() );
- * ser.asDocumentHandler().endElement( "empty" );
- * ser.asDocumentHandler().endDocument();
- * ser.reset();
- * }
- * </pre>
- *
- * @version Alpha
- * @author <a href="mailto:arkin@exoffice.com">Assaf Arkin</a>
- * @author <a href="mailto:Scott_Boag/CAM/Lotus@lotus.com">Scott Boag</a>
+ * The Serializer interface is implemented by Serializers to publish methods
+ * to get and set streams and writers, to set the output properties, and
+ * get the Serializer as a ContentHandler or DOMSerializer.
*/
public interface Serializer
{
1.2 +15 -131 xml-xalan/java/src/org/apache/xalan/serialize/package.html
Index: package.html
===================================================================
RCS file: /home/cvs/xml-xalan/java/src/org/apache/xalan/serialize/package.html,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- package.html 2000/11/13 16:27:02 1.1
+++ package.html 2001/01/02 03:29:10 1.2
@@ -1,136 +1,20 @@
-<!-- CVS $Revision: 1.1 $ $Date: 2000/11/13 16:27:02 $ -->
<html>
- <title>Interfaces for SAX and DOM serializers.</title>
+ <title>Xalan Serialize Package.</title>
<body>
- <p>Defines an interface for SAX and DOM serializers, a serializer
- factory and its configuration, the output format properties,
- and related interfaces.<p>
-
- <dl>
- <dt><b>Version: </b></dt><dd>Alpha $Revision: 1.1 $ $Date: 2000/11/13 16:27:02 $</dd>
- <dt><b>Author: </b></dt><dd><a href="mailto:arkin@exoffice.com">Assaf Arkin</a></dd>
- <dt><b>Goals: </b></dt><dd>
- <ul>
- <li>Define an interface for serializers that will allow an application
- to use any implementation.</li>
- <li>Support SAX 1, SAX 2, DOM Level 1, DOM Level 2 serialization</li>
- <li>Allow implementations to extend the interfaces and provide additional
- functionality, and support implementations for any output method.</li>
- <li>Provide a factory for the default output methods (XML, HTML, Text).</li>
- </ul>
- </dd>
- </dl>
-
- <h3>The Serializer Interfaces</h3>
-
- <p>{@link serialize.Serializer} defines the interface supported by
- a serializer. A serializer implements a mechanism for producing output from
- a series of SAX events or a DOM document, in a given format (aka the output
- method). A serializer can be constructed directly, or obtained from some
- factory, it may implement the base functionality or provide additional
- functionality suitable for the given output method (e.g. indentation in
- XML, page control in PDF, etc).</p>
-
- <p>A serializer is not thread safe and may not be used concurrently, however,
- a serializer may be recyclable and used to serialize any number of documents
- with the same output method.</p>
-
- <p>Before serializing a document, the serializer must be set with the output
- stream or writer, and optionally with an {@link serialize.OutputFormat}
- specifying the output properties. Serializer implementations may support
- additional methods to control the way in which documents are serialized,
- or extend {@link serialize.OutputFormat} and offer additional
- output properties.</p>
-
- <p>{@link serialize.Serializer} and {@link serialize.OutputFormat}
- provides the minimum functionality that all serializers must support
- and that an application may depend on, and are based on the XSLT 1.0
- specification.</p>
-
- <p>For the purpose of serializing, a handle to the serializer is obtained
- that can be either a SAX 1 <tt>DocumentHandler</tt>, a SAX 2 <tt>ContentHandler</tt>
- or a DOM Level 1/2 {@link serialize.DOMSerializer}. The application
- should obtain and use only one handle at any given time and may not reuse
- the handle to serialize multiple documents. It is illegal for the application
- to call two different handle returning methods without resetting the serializer,
- or two use the same handle after resetting the serializer.</p>
-
- <p>{@link serialize.SerializerFactory} provides a means of obtaining
- the default serializers available from a given implementation. At the minimum
- an implementation should support XML, HTML and Text serializers. When additional
- serializers are available, the application may obtain them through the {@link
- serialize.SerializerFactory} or construct them directly.</p>
-
- <p>Non-escaping and whitespace preserving output control is offered for
- XML, HTML and similar output methods, but it is not mandatory that a
- serializer support these output control methods. Non-escaping and whitespace
- preserving can be set globally through {@link serialize.OutputFormat},
- or directly when serializing SAX events through {@link serialize.SerializerHandler}.
- Serializers are not required to implement the {@link serialize.SerializerHandler}
- interface.</p>
-
- <h3>Usage Examples</h3>
-
- <p>Serialize a DOM document as XML:</p>
-
- <pre>
- void printXML( Document doc, OutputStream stream, String encoding )
- {
- OutputFormat format;
- Serializer ser;
-
- // Obtain a suitable output format for the XML method and
- // set the encoding.
- format = SerializerFactory.getOutputFormat( Method.XML );
- format.setEncoding( encoding );
-
- // Obtain a suitable serializer for the XML method and
- // set the output stream.
- ser = SerializerFactory.getSerializer( format );
- ser.setOutputStream( stream );
-
- // Use DOMSerializer to serialize the document
- ser.asDOMSerializer().serialize( doc );
- }
- </pre>
-
- <p>Serialize an empty HTML document using SAX events, reuse the serializer:</p>
-
- <pre>
- Serializer ser;
-
- // Obtain an HTML serializer once, use it multiple times.
- ser = SerializerFactory.getSerializer( Method.HTML );
- printEmptyHTML( ser, System.out );
- printEmptyHTML( ser, System.err );
- . . .
-
- void printEmptyHTML( Serializer ser, OutputStream os )
- {
- ser.setOutputStream( os );
- ser.asDocumentHandler().startDocument();
- ser.asDocumentHandler().startElement( "html", new AttributeListImpl() );
- ser.asDocumentHandler().endElement( "html" );
- ser.asDocumentHandler().endDocument();
- ser.reset();
- }
- </pre>
-
- <h3>The Properties File</h3>
-
- <p>An implementation will include a serializer properties file called
- <tt>serializer.properties</tt> located in the <tt>serialize</tt>
- package. The properties file lists all the default serializers supported
- by that implementation. Serializers that are not listed in the properties
- file may be constructed directly by the application.</p>
-
- <p>The properties file contains a property <tt>serialize.methods</tt>
- listing all the output methods supported by the implementation (comma
- separated list). For each method a property <tt>serialize.[method]</tt>
- names the class of the {@link serialize.Serializer} implementation.
- The optional property <tt>serialize.format.[method]</tt> names the
- class of a suitable {@link serialize.OutputFormat} implementation.</p>
-
+ <p>Processes SAX events into streams.</p>
+
+ <p>The {@link org.apache.xalan.serialize.SerializerFactory} is used to
+ create a {@link org.apache.xalan.serialize.Serializer} from a set of
+ output properties (see {@link javax.xml.transform.OutputKeys}).</p>
+ <p>{@link org.apache.xalan.serialize.SerializerToXML} acts as the main
+ baseclass for the Xalan serializer implementations.
+ {@link org.apache.xalan.serialize.SerializerToHTML} derives from this
+ to implement HTML serialization. {@link org.apache.xalan.serialize.SerializerToText}
+ implements plain text serialization.</p>
+ <p>XML mapping from characters to entity references is defined in
+ XMLEntities.res. HTML entity reference mapping is defined in HTMLEntities.res.
+ </p>
+ <p>Encoding information is defined in {@link org.apache.xalan.serialize.Encodings}.</p>
</body>
</html>
1.1 xml-xalan/java/src/org/apache/xalan/serialize/SerializerToHTML.java
Index: SerializerToHTML.java
===================================================================
/*
* The Apache Software License, Version 1.1
*
*
* Copyright (c) 1999 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Xalan" and "Apache Software Foundation" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation and was
* originally based on software copyright (c) 1999, Lotus
* Development Corporation., http://www.lotus.com. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
package org.apache.xalan.serialize;
import java.util.Stack;
import java.io.Writer;
import java.io.IOException;
import java.util.Hashtable;
import java.util.Vector;
import java.util.Properties;
import java.util.BitSet;
import org.xml.sax.*;
import org.apache.xml.utils.BoolStack;
import org.apache.xml.utils.Trie;
import org.apache.xml.utils.FastStringBuffer;
import org.apache.xalan.res.XSLMessages;
import org.apache.xpath.res.XPATHErrorResources;
import org.apache.xml.utils.StringToIntTable;
import org.apache.xalan.templates.OutputProperties;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
/**
* <meta name="usage" content="general"/>
* SerializerToHTML formats SAX-style events into XML.
*/
public class SerializerToHTML extends SerializerToXML
{
/** State stack to keep track of if the current element has output
* escaping disabled. */
private BoolStack m_isRawStack = new BoolStack();
/** True if the current element is a block element. (seems like
* this needs to be a stack. -sb). */
private boolean m_inBlockElem = false;
/**
* Map that tells which XML characters should have special treatment, and it
* provides character to entity name lookup.
*/
protected static CharInfo m_htmlcharInfo =
new CharInfo(CharInfo.HTML_ENTITIES_RESOURCE);
/** A digital search trie for fast, case insensitive lookup of ElemDesc objects. */
static Trie m_elementFlags = new Trie();
static
{
// HTML 4.0 loose DTD
m_elementFlags.put("BASEFONT", new ElemDesc(0 | ElemDesc.EMPTY));
m_elementFlags.put("FRAME",
new ElemDesc(0 | ElemDesc.EMPTY | ElemDesc.BLOCK));
m_elementFlags.put("FRAMESET", new ElemDesc(0 | ElemDesc.BLOCK));
m_elementFlags.put("NOFRAMES", new ElemDesc(0 | ElemDesc.BLOCK));
m_elementFlags.put("ISINDEX",
new ElemDesc(0 | ElemDesc.EMPTY | ElemDesc.BLOCK));
m_elementFlags.put("APPLET",
new ElemDesc(0 | ElemDesc.WHITESPACESENSITIVE));
m_elementFlags.put("CENTER", new ElemDesc(0 | ElemDesc.BLOCK));
m_elementFlags.put("DIR", new ElemDesc(0 | ElemDesc.BLOCK));
m_elementFlags.put("MENU", new ElemDesc(0 | ElemDesc.BLOCK));
// HTML 4.0 strict DTD
m_elementFlags.put("TT", new ElemDesc(0 | ElemDesc.FONTSTYLE));
m_elementFlags.put("I", new ElemDesc(0 | ElemDesc.FONTSTYLE));
m_elementFlags.put("B", new ElemDesc(0 | ElemDesc.FONTSTYLE));
m_elementFlags.put("BIG", new ElemDesc(0 | ElemDesc.FONTSTYLE));
m_elementFlags.put("SMALL", new ElemDesc(0 | ElemDesc.FONTSTYLE));
m_elementFlags.put("EM", new ElemDesc(0 | ElemDesc.PHRASE));
m_elementFlags.put("STRONG", new ElemDesc(0 | ElemDesc.PHRASE));
m_elementFlags.put("DFN", new ElemDesc(0 | ElemDesc.PHRASE));
m_elementFlags.put("CODE", new ElemDesc(0 | ElemDesc.PHRASE));
m_elementFlags.put("SAMP", new ElemDesc(0 | ElemDesc.PHRASE));
m_elementFlags.put("KBD", new ElemDesc(0 | ElemDesc.PHRASE));
m_elementFlags.put("VAR", new ElemDesc(0 | ElemDesc.PHRASE));
m_elementFlags.put("CITE", new ElemDesc(0 | ElemDesc.PHRASE));
m_elementFlags.put("ABBR", new ElemDesc(0 | ElemDesc.PHRASE));
m_elementFlags.put("ACRONYM", new ElemDesc(0 | ElemDesc.PHRASE));
m_elementFlags.put("SUP",
new ElemDesc(0 | ElemDesc.SPECIAL
| ElemDesc.ASPECIAL));
m_elementFlags.put("SUB",
new ElemDesc(0 | ElemDesc.SPECIAL
| ElemDesc.ASPECIAL));
m_elementFlags.put("SPAN",
new ElemDesc(0 | ElemDesc.SPECIAL
| ElemDesc.ASPECIAL));
m_elementFlags.put("BDO",
new ElemDesc(0 | ElemDesc.SPECIAL
| ElemDesc.ASPECIAL));
m_elementFlags.put("BR",
new ElemDesc(0 | ElemDesc.SPECIAL | ElemDesc.ASPECIAL
| ElemDesc.EMPTY | ElemDesc.BLOCK));
m_elementFlags.put("BODY", new ElemDesc(0 | ElemDesc.BLOCK));
m_elementFlags.put("ADDRESS",
new ElemDesc(0 | ElemDesc.BLOCK | ElemDesc.BLOCKFORM
| ElemDesc.BLOCKFORMFIELDSET));
m_elementFlags.put("DIV",
new ElemDesc(0 | ElemDesc.BLOCK | ElemDesc.BLOCKFORM
| ElemDesc.BLOCKFORMFIELDSET));
m_elementFlags.put("A", new ElemDesc(0 | ElemDesc.SPECIAL));
m_elementFlags.put("MAP",
new ElemDesc(0 | ElemDesc.SPECIAL | ElemDesc.ASPECIAL
| ElemDesc.BLOCK));
m_elementFlags.put("AREA",
new ElemDesc(0 | ElemDesc.EMPTY | ElemDesc.BLOCK));
m_elementFlags.put("LINK",
new ElemDesc(0 | ElemDesc.HEADMISC | ElemDesc.EMPTY
| ElemDesc.BLOCK));
m_elementFlags.put("IMG",
new ElemDesc(0 | ElemDesc.SPECIAL | ElemDesc.ASPECIAL
| ElemDesc.EMPTY
| ElemDesc.WHITESPACESENSITIVE));
m_elementFlags.put("OBJECT",
new ElemDesc(0 | ElemDesc.SPECIAL | ElemDesc.ASPECIAL
| ElemDesc.HEADMISC
| ElemDesc.WHITESPACESENSITIVE));
m_elementFlags.put("PARAM", new ElemDesc(0 | ElemDesc.EMPTY));
m_elementFlags.put("HR",
new ElemDesc(0 | ElemDesc.BLOCK | ElemDesc.BLOCKFORM
| ElemDesc.BLOCKFORMFIELDSET
| ElemDesc.EMPTY));
m_elementFlags.put("P",
new ElemDesc(0 | ElemDesc.BLOCK | ElemDesc.BLOCKFORM
| ElemDesc.BLOCKFORMFIELDSET));
m_elementFlags.put("H1",
new ElemDesc(0 | ElemDesc.HEAD | ElemDesc.BLOCK));
m_elementFlags.put("H2",
new ElemDesc(0 | ElemDesc.HEAD | ElemDesc.BLOCK));
m_elementFlags.put("H3",
new ElemDesc(0 | ElemDesc.HEAD | ElemDesc.BLOCK));
m_elementFlags.put("H4",
new ElemDesc(0 | ElemDesc.HEAD | ElemDesc.BLOCK));
m_elementFlags.put("H5",
new ElemDesc(0 | ElemDesc.HEAD | ElemDesc.BLOCK));
m_elementFlags.put("H6",
new ElemDesc(0 | ElemDesc.HEAD | ElemDesc.BLOCK));
m_elementFlags.put("PRE",
new ElemDesc(0 | ElemDesc.PREFORMATTED
| ElemDesc.BLOCK));
m_elementFlags.put("Q",
new ElemDesc(0 | ElemDesc.SPECIAL
| ElemDesc.ASPECIAL));
m_elementFlags.put("BLOCKQUOTE",
new ElemDesc(0 | ElemDesc.BLOCK | ElemDesc.BLOCKFORM
| ElemDesc.BLOCKFORMFIELDSET));
m_elementFlags.put("INS", new ElemDesc(0));
m_elementFlags.put("DEL", new ElemDesc(0));
m_elementFlags.put("DL",
new ElemDesc(0 | ElemDesc.BLOCK | ElemDesc.BLOCKFORM
| ElemDesc.BLOCKFORMFIELDSET));
m_elementFlags.put("DT", new ElemDesc(0 | ElemDesc.BLOCK));
m_elementFlags.put("DD", new ElemDesc(0 | ElemDesc.BLOCK));
m_elementFlags.put("OL",
new ElemDesc(0 | ElemDesc.LIST | ElemDesc.BLOCK));
m_elementFlags.put("UL",
new ElemDesc(0 | ElemDesc.LIST | ElemDesc.BLOCK));
m_elementFlags.put("LI", new ElemDesc(0 | ElemDesc.BLOCK));
m_elementFlags.put("FORM", new ElemDesc(0 | ElemDesc.BLOCK));
m_elementFlags.put("LABEL", new ElemDesc(0 | ElemDesc.FORMCTRL));
m_elementFlags.put("INPUT",
new ElemDesc(0 | ElemDesc.FORMCTRL
| ElemDesc.INLINELABEL | ElemDesc.EMPTY));
m_elementFlags.put("SELECT",
new ElemDesc(0 | ElemDesc.FORMCTRL
| ElemDesc.INLINELABEL));
m_elementFlags.put("OPTGROUP", new ElemDesc(0));
m_elementFlags.put("OPTION", new ElemDesc(0));
m_elementFlags.put("TEXTAREA",
new ElemDesc(0 | ElemDesc.FORMCTRL
| ElemDesc.INLINELABEL));
m_elementFlags.put("FIELDSET",
new ElemDesc(0 | ElemDesc.BLOCK | ElemDesc.BLOCKFORM));
m_elementFlags.put("LEGEND", new ElemDesc(0));
m_elementFlags.put("BUTTON",
new ElemDesc(0 | ElemDesc.FORMCTRL
| ElemDesc.INLINELABEL));
m_elementFlags.put("TABLE",
new ElemDesc(0 | ElemDesc.BLOCK | ElemDesc.BLOCKFORM
| ElemDesc.BLOCKFORMFIELDSET));
m_elementFlags.put("CAPTION", new ElemDesc(0 | ElemDesc.BLOCK));
m_elementFlags.put("THEAD", new ElemDesc(0 | ElemDesc.BLOCK));
m_elementFlags.put("TFOOT", new ElemDesc(0 | ElemDesc.BLOCK));
m_elementFlags.put("TBODY", new ElemDesc(0 | ElemDesc.BLOCK));
m_elementFlags.put("COLGROUP", new ElemDesc(0 | ElemDesc.BLOCK));
m_elementFlags.put("COL",
new ElemDesc(0 | ElemDesc.EMPTY | ElemDesc.BLOCK));
m_elementFlags.put("TR", new ElemDesc(0 | ElemDesc.BLOCK));
m_elementFlags.put("TH", new ElemDesc(0));
m_elementFlags.put("TD", new ElemDesc(0));
m_elementFlags.put("HEAD",
new ElemDesc(0 | ElemDesc.BLOCK | ElemDesc.HEADELEM));
m_elementFlags.put("TITLE", new ElemDesc(0 | ElemDesc.BLOCK));
m_elementFlags.put("BASE",
new ElemDesc(0 | ElemDesc.EMPTY | ElemDesc.BLOCK));
m_elementFlags.put("META",
new ElemDesc(0 | ElemDesc.HEADMISC | ElemDesc.EMPTY
| ElemDesc.BLOCK));
m_elementFlags.put("STYLE",
new ElemDesc(0 | ElemDesc.HEADMISC | ElemDesc.RAW
| ElemDesc.BLOCK));
m_elementFlags.put("SCRIPT",
new ElemDesc(0 | ElemDesc.SPECIAL | ElemDesc.ASPECIAL
| ElemDesc.HEADMISC | ElemDesc.RAW));
m_elementFlags.put("NOSCRIPT",
new ElemDesc(0 | ElemDesc.BLOCK | ElemDesc.BLOCKFORM
| ElemDesc.BLOCKFORMFIELDSET));
m_elementFlags.put("HTML", new ElemDesc(0 | ElemDesc.BLOCK));
// From "John Ky" <hand@syd.speednet.com.au
// Transitional Document Type Definition ()
// file:///C:/Documents%20and%20Settings/sboag.BOAG600E/My%20Documents/html/sgml/loosedtd.html#basefont
m_elementFlags.put("FONT", new ElemDesc(0 | ElemDesc.FONTSTYLE));
// file:///C:/Documents%20and%20Settings/sboag.BOAG600E/My%20Documents/html/present/graphics.html#edef-STRIKE
m_elementFlags.put("S", new ElemDesc(0 | ElemDesc.FONTSTYLE));
m_elementFlags.put("STRIKE", new ElemDesc(0 | ElemDesc.FONTSTYLE));
// file:///C:/Documents%20and%20Settings/sboag.BOAG600E/My%20Documents/html/present/graphics.html#edef-U
m_elementFlags.put("U", new ElemDesc(0 | ElemDesc.FONTSTYLE));
// From "John Ky" <hand@syd.speednet.com.au
m_elementFlags.put("NOBR", new ElemDesc(0 | ElemDesc.FONTSTYLE));
ElemDesc elemDesc;
elemDesc = (ElemDesc) m_elementFlags.get("BASE");
elemDesc.setAttr("HREF", ElemDesc.ATTRURL);
elemDesc = (ElemDesc) m_elementFlags.get("BLOCKQUOTE");
elemDesc.setAttr("CITE", ElemDesc.ATTRURL);
elemDesc = (ElemDesc) m_elementFlags.get("Q");
elemDesc.setAttr("CITE", ElemDesc.ATTRURL);
elemDesc = (ElemDesc) m_elementFlags.get("INS");
elemDesc.setAttr("CITE", ElemDesc.ATTRURL);
elemDesc = (ElemDesc) m_elementFlags.get("DEL");
elemDesc.setAttr("CITE", ElemDesc.ATTRURL);
elemDesc = (ElemDesc) m_elementFlags.get("A");
elemDesc.setAttr("HREF", ElemDesc.ATTRURL);
elemDesc.setAttr("NAME", ElemDesc.ATTRURL);
elemDesc = (ElemDesc) m_elementFlags.get("INPUT");
elemDesc.setAttr("SRC", ElemDesc.ATTRURL);
elemDesc.setAttr("USEMAP", ElemDesc.ATTRURL);
elemDesc.setAttr("CHECKED", ElemDesc.ATTREMPTY);
elemDesc.setAttr("DISABLED", ElemDesc.ATTREMPTY);
elemDesc.setAttr("READONLY", ElemDesc.ATTREMPTY);
elemDesc = (ElemDesc) m_elementFlags.get("SELECT");
elemDesc.setAttr("READONLY", ElemDesc.ATTREMPTY);
elemDesc.setAttr("MULTIPLE", ElemDesc.ATTREMPTY);
elemDesc = (ElemDesc) m_elementFlags.get("OPTGROUP");
elemDesc.setAttr("DISABLED", ElemDesc.ATTREMPTY);
elemDesc = (ElemDesc) m_elementFlags.get("OPTION");
elemDesc.setAttr("SELECTED", ElemDesc.ATTREMPTY);
elemDesc.setAttr("DISABLED", ElemDesc.ATTREMPTY);
elemDesc = (ElemDesc) m_elementFlags.get("TEXTAREA");
elemDesc.setAttr("DISABLED", ElemDesc.ATTREMPTY);
elemDesc.setAttr("READONLY", ElemDesc.ATTREMPTY);
elemDesc = (ElemDesc) m_elementFlags.get("BUTTON");
elemDesc.setAttr("DISABLED", ElemDesc.ATTREMPTY);
elemDesc = (ElemDesc) m_elementFlags.get("SCRIPT");
elemDesc.setAttr("SRC", ElemDesc.ATTRURL);
elemDesc.setAttr("FOR", ElemDesc.ATTRURL);
elemDesc = (ElemDesc) m_elementFlags.get("IMG");
elemDesc.setAttr("SRC", ElemDesc.ATTRURL);
elemDesc.setAttr("LONGDESC", ElemDesc.ATTRURL);
elemDesc.setAttr("USEMAP", ElemDesc.ATTRURL);
elemDesc = (ElemDesc) m_elementFlags.get("OBJECT");
elemDesc.setAttr("CLASSID", ElemDesc.ATTRURL);
elemDesc.setAttr("CODEBASE", ElemDesc.ATTRURL);
elemDesc.setAttr("DATA", ElemDesc.ATTRURL);
elemDesc.setAttr("ARCHIVE", ElemDesc.ATTRURL);
elemDesc.setAttr("USEMAP", ElemDesc.ATTRURL);
elemDesc = (ElemDesc) m_elementFlags.get("FORM");
elemDesc.setAttr("ACTION", ElemDesc.ATTRURL);
elemDesc = (ElemDesc) m_elementFlags.get("HEAD");
elemDesc.setAttr("PROFILE", ElemDesc.ATTRURL);
// Attribution to: "Voytenko, Dimitry" <DV...@SECTORBASE.COM>
elemDesc = (ElemDesc) m_elementFlags.get("FRAME");
elemDesc.setAttr("SRC", ElemDesc.ATTRURL);
}
/**
* Dummy element for elements not found.
*/
static private ElemDesc m_dummy = new ElemDesc(0 | ElemDesc.BLOCK);
/** True if URLs should be specially escaped with the %xx form. */
private boolean m_specialEscapeURLs = true;
/**
* Tells if the formatter should use special URL escaping.
*
* @param bool True if URLs should be specially escaped with the %xx form.
*/
public void setSpecialEscapeURLs(boolean bool)
{
m_specialEscapeURLs = bool;
}
/**
* Specifies an output format for this serializer. It the
* serializer has already been associated with an output format,
* it will switch to the new format. This method should not be
* called while the serializer is in the process of serializing
* a document.
*
* @param format The output format to use
*/
public void setOutputFormat(Properties format)
{
m_specialEscapeURLs =
OutputProperties.getBooleanProperty(OutputProperties.S_USE_URL_ESCAPING,
format);
super.setOutputFormat(format);
}
/**
* Tells if the formatter should use special URL escaping.
*
* @return True if URLs should be specially escaped with the %xx form.
*/
public boolean getSpecialEscapeURLs()
{
return m_specialEscapeURLs;
}
/**
* Get a description of the given element.
*
* @param name non-null name of element, case insensitive.
*
* @return non-null reference to ElemDesc, which may be m_dummy if no
* element description matches the given name.
*/
ElemDesc getElemDesc(String name)
{
if (null != name)
{
Object obj = m_elementFlags.get(name);
if (null != obj)
return (ElemDesc) obj;
}
return m_dummy;
}
/**
* Default constructor.
*/
public SerializerToHTML()
{
super();
m_charInfo = m_htmlcharInfo;
}
/** The name of the current element. */
private String m_currentElementName = null;
/**
* Receive notification of the beginning of a document.
*
* @throws org.xml.sax.SAXException Any SAX exception, possibly
* wrapping another exception.
*
* @throws org.xml.sax.SAXException
*/
public void startDocument() throws org.xml.sax.SAXException
{
m_needToOutputDocTypeDecl = true;
m_startNewLine = false;
m_shouldNotWriteXMLHeader = true;
if (true == m_needToOutputDocTypeDecl)
{
if ((null != m_doctypeSystem) || (null != m_doctypePublic))
{
accum("<!DOCTYPE HTML");
if (null != m_doctypePublic)
{
accum(" PUBLIC \"");
accum(m_doctypePublic);
accum("\"");
}
if (null != m_doctypeSystem)
{
if (null == m_doctypePublic)
accum(" SYSTEM \"");
else
accum(" \"");
accum(m_doctypeSystem);
accum("\"");
}
accum(">");
accum(m_lineSep);
}
}
m_needToOutputDocTypeDecl = false;
}
/**
* Receive notification of the beginning of an element.
*
*
* @param namespaceURI
* @param localName
* @param name The element type name.
* @param atts The attributes attached to the element, if any.
* @throws org.xml.sax.SAXException Any SAX exception, possibly
* wrapping another exception.
* @see #endElement
* @see org.xml.sax.AttributeList
*/
public void startElement(
String namespaceURI, String localName, String name, Attributes atts)
throws org.xml.sax.SAXException
{
// System.out.println("SerializerToHTML#startElement("+namespaceURI+", "+localName+", "+name+", ...);");
if (null != namespaceURI && namespaceURI.length() > 0)
{
super.startElement(namespaceURI, localName, name, atts);
return;
}
boolean savedDoIndent = m_doIndent;
boolean noLineBreak;
writeParentTagEnd();
pushState(
namespaceURI, localName,
m_cdataSectionNames, m_cdataSectionStates);
// pushState(namespaceURI, localName, m_format.getNonEscapingElements(),
// m_disableOutputEscapingStates);
ElemDesc elemDesc = getElemDesc(name);
// ElemDesc parentElemDesc = getElemDesc(m_currentElementName);
boolean isBlockElement = elemDesc.is(ElemDesc.BLOCK);
boolean isHeadElement = elemDesc.is(ElemDesc.HEADELEM);
// boolean isWhiteSpaceSensitive = elemDesc.is(ElemDesc.WHITESPACESENSITIVE);
if (m_ispreserve)
m_ispreserve = false;
else if (m_doIndent && (null != m_currentElementName)
&& (!m_inBlockElem || isBlockElement)
/* && !isWhiteSpaceSensitive */
)
{
m_startNewLine = true;
indent(m_currentIndent);
}
m_inBlockElem = !isBlockElement;
m_isRawStack.push(elemDesc.is(ElemDesc.RAW));
m_currentElementName = name;
// m_parents.push(m_currentElementName);
this.accum('<');
this.accum(name);
int nAttrs = atts.getLength();
for (int i = 0; i < nAttrs; i++)
{
processAttribute(atts.getQName(i), elemDesc, atts.getValue(i));
}
// Flag the current element as not yet having any children.
openElementForChildren();
m_currentIndent += this.m_indentAmount;
m_isprevtext = false;
m_doIndent = savedDoIndent;
if (isHeadElement)
{
writeParentTagEnd();
if (m_doIndent)
indent(m_currentIndent);
accum(
"<META http-equiv=\"Content-Type\" content=\"text/html; charset=");
String encoding = Encodings.getMimeEncoding(m_encoding);
accum(encoding);
accum('"');
accum('>');
}
}
/**
* Receive notification of the end of an element.
*
*
* @param namespaceURI
* @param localName
* @param name The element type name
* @throws org.xml.sax.SAXException Any SAX exception, possibly
* wrapping another exception.
*/
public void endElement(String namespaceURI, String localName, String name)
throws org.xml.sax.SAXException
{
// System.out.println("SerializerToHTML#endElement("+namespaceURI+", "+localName+", "+name+");");
if (null != namespaceURI && namespaceURI.length() > 0)
{
super.endElement(namespaceURI, localName, name);
return;
}
m_currentIndent -= this.m_indentAmount;
boolean hasChildNodes = childNodesWereAdded();
// System.out.println(m_currentElementName);
// m_parents.pop();
m_isRawStack.pop();
ElemDesc elemDesc = getElemDesc(name);
// ElemDesc parentElemDesc = getElemDesc(m_currentElementName);
boolean isBlockElement = elemDesc.is(ElemDesc.BLOCK);
boolean shouldIndent = false;
if (m_ispreserve)
{
m_ispreserve = false;
}
else if (m_doIndent && (!m_inBlockElem || isBlockElement))
{
m_startNewLine = true;
shouldIndent = true;
// indent(m_currentIndent);
}
m_inBlockElem = !isBlockElement;
if (hasChildNodes)
{
if (shouldIndent)
indent(m_currentIndent);
this.accum("</");
this.accum(name);
this.accum('>');
m_currentElementName = name;
}
else
{
if (!elemDesc.is(ElemDesc.EMPTY))
{
this.accum('>');
// As per Dave/Paul recommendation 12/06/2000
// if (shouldIndent)
// indent(m_currentIndent);
this.accum('<');
this.accum('/');
this.accum(name);
this.accum('>');
}
else
{
this.accum('>');
}
}
if (elemDesc.is(ElemDesc.WHITESPACESENSITIVE))
m_ispreserve = true;
if (hasChildNodes)
{
if (!m_preserves.isEmpty())
m_preserves.pop();
}
m_isprevtext = false;
// m_disableOutputEscapingStates.pop();
m_cdataSectionStates.pop();
}
/**
* Process an attribute.
* @param name The name of the attribute.
* @param elemDesc non-null reference to the owning element description.
* @param value The value of the attribute.
*
* @throws org.xml.sax.SAXException
*/
protected void processAttribute(
String name, ElemDesc elemDesc, String value)
throws org.xml.sax.SAXException
{
this.accum(' ');
if (((value.length() == 0) || value.equalsIgnoreCase(name))
&& elemDesc.isAttrFlagSet(name, ElemDesc.ATTREMPTY))
{
this.accum(name);
}
else
{
this.accum(name);
this.accum('=');
this.accum('\"');
if (elemDesc.isAttrFlagSet(name, ElemDesc.ATTRURL))
writeAttrURI(value, m_specialEscapeURLs);
else
writeAttrString(value, this.m_encoding);
this.accum('\"');
}
}
/**
* Tell if a character is an ASCII digit.
*/
private boolean isASCIIDigit(char c)
{
return (c >= '0' && c <= '9');
}
/**
* Make an integer into an HH hex value.
* Does no checking on the size of the input, since this
* is only meant to be used locally by writeAttrURI.
*
* @param i must be a value less than 255.
*
* @return should be a two character string.
*/
private String makeHHString(int i)
{
String s = Integer.toHexString(i).toUpperCase();
if(s.length() == 1)
{
s = "0"+s;
}
return s;
}
/**
* Write the specified <var>string</var> after substituting non ASCII characters,
* with <CODE>%HH</CODE>, where HH is the hex of the byte value.
*
* @param string String to convert to XML format.
* @param doURLEscaping True if we should try to encode as
* per http://www.ietf.org/rfc/rfc2396.txt.
*
* @throws org.xml.sax.SAXException if a bad surrogate pair is detected.
*/
public void writeAttrURI(String string, boolean doURLEscaping)
throws org.xml.sax.SAXException
{
// http://www.ietf.org/rfc/rfc2396.txt says:
// A URI is always in an "escaped" form, since escaping or unescaping a
// completed URI might change its semantics. Normally, the only time
// escape encodings can safely be made is when the URI is being created
// from its component parts; each component may have its own set of
// characters that are reserved, so only the mechanism responsible for
// generating or interpreting that component can determine whether or
// not escaping a character will change its semantics. Likewise, a URI
// must be separated into its components before the escaped characters
// within those components can be safely decoded.
//
// ...So we do our best to do limited escaping of the URL, without
// causing damage. If the URL is already properly escaped, in theory, this
// function should not change the string value.
char[] stringArray = string.toCharArray();
int len = stringArray.length;
for (int i = 0; i < len; i++)
{
char ch = stringArray[i];
if ((ch < 33) || (ch > 126))
{
if (doURLEscaping)
{
// Encode UTF16 to UTF8.
// Reference is Unicode, A Primer, by Tony Graham.
// Page 92.
if(ch <= 0x7F)
{
accum('%');
accum(makeHHString(ch));
}
else if(ch <= 0x7FF)
{
// Clear low 6 bits before rotate, put high 4 bits in low byte,
// and set two high bits.
int high = (ch >> 6) | 0xC0;
int low = (ch & 0x3F) | 0x80; // First 6 bits, + high bit
accum('%');
accum(makeHHString(high));
accum('%');
accum(makeHHString(low));
}
else if( isUTF16Surrogate(ch) ) // high surrogate
{
// I'm sure this can be done in 3 instructions, but I choose
// to try and do it exactly like it is done in the book, at least
// until we are sure this is totally clean. I don't think performance
// is a big issue with this particular function, though I could be
// wrong. Also, the stuff below clearly does more masking than
// it needs to do.
// Clear high 6 bits.
int highSurrogate = ((int) ch) & 0x03FF;
// Middle 4 bits (wwww) + 1
// "Note that the value of wwww from the high surrogate bit pattern
// is incremented to make the uuuuu bit pattern in the scalar value
// so the surrogate pair don't address the BMP."
int wwww = ((highSurrogate & 0x03C0) >> 6);
int uuuuu = wwww+1;
// next 4 bits
int zzzz = (highSurrogate & 0x003C) >> 2;
// low 2 bits
int yyyyyy = ((highSurrogate & 0x0003) << 4) & 0x30;
// Get low surrogate character.
ch = stringArray[++i];
// Clear high 6 bits.
int lowSurrogate = ((int) ch) & 0x03FF;
// put the middle 4 bits into the bottom of yyyyyy (byte 3)
yyyyyy = yyyyyy | ((lowSurrogate & 0x03C0) >> 6);
// bottom 6 bits.
int xxxxxx = (lowSurrogate & 0x003F);
int byte1 = 0xF0 | (uuuuu >> 2); // top 3 bits of uuuuu
int byte2 = 0x80 | (((uuuuu & 0x03) << 4) & 0x30) | zzzz;
int byte3 = 0x80 | yyyyyy;
int byte4 = 0x80 | xxxxxx;
accum('%');
accum(makeHHString(byte1));
accum('%');
accum(makeHHString(byte2));
accum('%');
accum(makeHHString(byte3));
accum('%');
accum(makeHHString(byte4));
}
else
{
int high = (ch >> 12) | 0xE0; // top 4 bits
int middle = ((ch & 0x0FC0) >> 6) | 0x80; // middle 6 bits
int low = (ch & 0x3F) | 0x80; // First 6 bits, + high bit
accum('%');
accum(makeHHString(high));
accum('%');
accum(makeHHString(middle));
accum('%');
accum(makeHHString(low));
}
}
else if (ch < m_maxCharacter)
{
accum(ch);
}
else
{
accum("&#");
accum(Integer.toString(ch));
accum(';');
}
}
else if('%' == ch)
{
// If the character is a '%' number number, try to avoid double-escaping.
// There is a question if this is legal behavior.
if(((i+2) < len) && isASCIIDigit(stringArray[i+1])
&& isASCIIDigit(stringArray[i+2]))
{
accum(ch);
}
else
{
if (doURLEscaping)
{
accum('%');
accum(makeHHString(ch));
}
else
accum(ch);
}
}
// Since http://www.ietf.org/rfc/rfc2396.txt refers to the URI grammar as
// not allowing quotes in the URI proper syntax, nor in the fragment
// identifier, we believe that it's OK to double escape quotes.
else if (ch == '"')
{
// Mike Kay encodes this as ", so he may know something I don't?
if (doURLEscaping)
accum("%22");
else
accum("""); // we have to escape this, I guess.
}
else
{
accum(ch);
}
}
}
/**
* Writes the specified <var>string</var> after substituting <VAR>specials</VAR>,
* and UTF-16 surrogates for character references <CODE>&#xnn</CODE>.
*
* @param string String to convert to XML format.
* @param encoding CURRENTLY NOT IMPLEMENTED.
*
* @throws org.xml.sax.SAXException
*/
public void writeAttrString(String string, String encoding)
throws org.xml.sax.SAXException
{
final char chars[] = string.toCharArray();
final int strLen = chars.length;
for (int i = 0; i < strLen; i++)
{
char ch = chars[i];
// System.out.println("SPECIALSSIZE: "+SPECIALSSIZE);
// System.out.println("ch: "+(int)ch);
// System.out.println("m_maxCharacter: "+(int)m_maxCharacter);
// System.out.println("m_attrCharsMap[ch]: "+(int)m_attrCharsMap[ch]);
if ((ch < m_maxCharacter) && (!m_charInfo.isSpecial(ch)))
{
accum(ch);
}
else if ('<' == ch || '>' == ch)
{
accum(ch); // no escaping in this case, as specified in 15.2
}
else if (('&' == ch) && ((i + 1) < strLen) && ('{' == chars[i + 1]))
{
accum(ch); // no escaping in this case, as specified in 15.2
}
else
{
int pos = accumDefaultEntity(ch, i, chars, strLen, false);
if (i != pos)
{
i = pos - 1;
}
else
{
if (isUTF16Surrogate(ch))
{
try
{
i = writeUTF16Surrogate(ch, chars, i, strLen);
}
catch(IOException ioe)
{
throw new SAXException(ioe);
}
}
// The next is kind of a hack to keep from escaping in the case
// of Shift_JIS and the like.
/*
else if ((ch < m_maxCharacter) && (m_maxCharacter == 0xFFFF)
&& (ch != 160))
{
accum(ch); // no escaping in this case
}
else
*/
String entityName = m_charInfo.getEntityNameForChar(ch);
if (null != entityName)
{
accum('&');
accum(entityName);
accum(';');
}
else if (ch < m_maxCharacter)
{
accum(ch); // no escaping in this case
}
else
{
if (ch < m_maxCharacter)
{
accum(ch); // no escaping in this case
}
else
{
accum("&#");
accum(Integer.toString(ch));
accum(';');
}
}
}
}
}
}
/**
* Copy an entity into the accumulation buffer.
*
* @param s The name of the entity.
* @param pos unused.
*
* @return The pos argument.
*
* @throws org.xml.sax.SAXException
*/
private int copyEntityIntoBuf(String s, int pos)
throws org.xml.sax.SAXException
{
int l = s.length();
accum('&');
for (int i = 0; i < l; i++)
{
accum(s.charAt(i));
}
accum(';');
return pos;
}
/**
* Receive notification of character data.
*
* <p>The Parser will call this method to report each chunk of
* character data. SAX parsers may return all contiguous character
* data in a single chunk, or they may split it into several
* chunks; however, all of the characters in any single event
* must come from the same external entity, so that the Locator
* provides useful information.</p>
*
* <p>The application must not attempt to read from the array
* outside of the specified range.</p>
*
* <p>Note that some parsers will report whitespace using the
* ignorableWhitespace() method rather than this one (validating
* parsers must do so).</p>
*
* @param chars The characters from the XML document.
* @param start The start position in the array.
* @param length The number of characters to read from the array.
* @throws org.xml.sax.SAXException Any SAX exception, possibly
* wrapping another exception.
* @see #ignorableWhitespace
* @see org.xml.sax.Locator
*
* @throws org.xml.sax.SAXException
*/
public void characters(char chars[], int start, int length)
throws org.xml.sax.SAXException
{
if (m_isRawStack.peekOrFalse())
{
try
{
writeParentTagEnd();
m_ispreserve = true;
if (shouldIndent())
indent(m_currentIndent);
// this.accum("<![CDATA[");
// this.accum(chars, start, length);
writeNormalizedChars(chars, start, length, false);
// this.accum("]]>");
return;
}
catch (IOException ioe)
{
throw new org.xml.sax.SAXException(
XSLMessages.createXPATHMessage(
XPATHErrorResources.ER_OIERROR, null), ioe); //"IO error", ioe);
}
}
else
{
super.characters(chars, start, length);
}
}
/**
* Receive notification of cdata.
*
* <p>The Parser will call this method to report each chunk of
* character data. SAX parsers may return all contiguous character
* data in a single chunk, or they may split it into several
* chunks; however, all of the characters in any single event
* must come from the same external entity, so that the Locator
* provides useful information.</p>
*
* <p>The application must not attempt to read from the array
* outside of the specified range.</p>
*
* <p>Note that some parsers will report whitespace using the
* ignorableWhitespace() method rather than this one (validating
* parsers must do so).</p>
*
* @param ch The characters from the XML document.
* @param start The start position in the array.
* @param length The number of characters to read from the array.
* @throws org.xml.sax.SAXException Any SAX exception, possibly
* wrapping another exception.
* @see #ignorableWhitespace
* @see org.xml.sax.Locator
*
* @throws org.xml.sax.SAXException
*/
public void cdata(char ch[], int start, int length)
throws org.xml.sax.SAXException
{
if ((null != m_currentElementName)
&& (m_currentElementName.equalsIgnoreCase("SCRIPT")
|| m_currentElementName.equalsIgnoreCase("STYLE")))
{
try
{
writeParentTagEnd();
m_ispreserve = true;
if (shouldIndent())
indent(m_currentIndent);
// this.accum(ch, start, length);
writeNormalizedChars(ch, start, length, true);
}
catch (IOException ioe)
{
throw new org.xml.sax.SAXException(
XSLMessages.createXPATHMessage(
XPATHErrorResources.ER_OIERROR, null), ioe); //"IO error", ioe);
}
}
/*
else if(m_stripCData) // should normally always be false
{
try
{
writeParentTagEnd();
m_ispreserve = true;
if (shouldIndent())
indent(m_currentIndent);
// this.accum("<![CDATA[");
this.accum(ch, start, length);
// this.accum("]]>");
}
catch(IOException ioe)
{
throw new org.xml.sax.SAXException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_OIERROR, null),ioe); //"IO error", ioe);
}
}
*/
else
{
super.cdata(ch, start, length);
}
}
/**
* Receive notification of a processing instruction.
*
* @param target The processing instruction target.
* @param data The processing instruction data, or null if
* none was supplied.
* @throws org.xml.sax.SAXException Any SAX exception, possibly
* wrapping another exception.
*
* @throws org.xml.sax.SAXException
*/
public void processingInstruction(String target, String data)
throws org.xml.sax.SAXException
{
// Use a fairly nasty hack to tell if the next node is supposed to be
// unescaped text.
if (target.equals(Result.PI_DISABLE_OUTPUT_ESCAPING))
{
startNonEscaping();
}
else if (target.equals(Result.PI_ENABLE_OUTPUT_ESCAPING))
{
endNonEscaping();
}
else
{
writeParentTagEnd();
if (shouldIndent())
indent(m_currentIndent);
this.accum("<?" + target);
if (data.length() > 0 &&!Character.isSpaceChar(data.charAt(0)))
this.accum(" ");
this.accum(data + ">"); // different from XML
// Always output a newline char if not inside of an
// element. The whitespace is not significant in that
// case.
if (m_elemStack.isEmpty())
outputLineSep();
m_startNewLine = true;
}
}
/**
* Receive notivication of a entityReference.
*
* @param name non-null reference to entity name string.
*
* @throws org.xml.sax.SAXException
*/
public void entityReference(String name) throws org.xml.sax.SAXException
{
this.accum("&");
this.accum(name);
this.accum(";");
}
}
1.1 xml-xalan/java/src/org/apache/xalan/serialize/SerializerToText.java
Index: SerializerToText.java
===================================================================
/*
* The Apache Software License, Version 1.1
*
*
* Copyright (c) 1999 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Xalan" and "Apache Software Foundation" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation and was
* originally based on software copyright (c) 1999, Lotus
* Development Corporation., http://www.lotus.com. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
package org.apache.xalan.serialize;
import org.xml.sax.*;
import java.util.*;
import java.io.*;
import org.apache.xpath.res.XPATHErrorResources;
import org.apache.xalan.res.XSLMessages;
import org.apache.xalan.templates.OutputProperties;
import javax.xml.transform.OutputKeys;
/**
* <meta name="usage" content="general"/>
* This class takes SAX events (in addition to some extra events
* that SAX doesn't handle yet) and produces simple text only.
*/
public class SerializerToText extends SerializerToXML
{
/**
* Default constructor.
*/
public SerializerToText()
{
super();
}
/**
* Receive an object for locating the origin of SAX document events.
*
* <p>SAX parsers are strongly encouraged (though not absolutely
* required) to supply a locator: if it does so, it must supply
* the locator to the application by invoking this method before
* invoking any of the other methods in the DocumentHandler
* interface.</p>
*
* <p>The locator allows the application to determine the end
* position of any document-related event, even if the parser is
* not reporting an error. Typically, the application will
* use this information for reporting its own errors (such as
* character content that does not match an application's
* business rules). The information returned by the locator
* is probably not sufficient for use with a search engine.</p>
*
* <p>Note that the locator will return correct information only
* during the invocation of the events in this interface. The
* application should not attempt to use it at any other time.</p>
*
* @param locator An object that can return the location of
* any SAX document event.
* @see org.xml.sax.Locator
*/
public void setDocumentLocator(Locator locator)
{
// No action for the moment.
}
/**
* Receive notification of the beginning of a document.
*
* <p>The SAX parser will invoke this method only once, before any
* other methods in this interface or in DTDHandler (except for
* setDocumentLocator).</p>
*
* @throws org.xml.sax.SAXException Any SAX exception, possibly
* wrapping another exception.
*
* @throws org.xml.sax.SAXException
*/
public void startDocument() throws org.xml.sax.SAXException
{
// No action for the moment.
}
/**
* Receive notification of the end of a document.
*
* <p>The SAX parser will invoke this method only once, and it will
* be the last method invoked during the parse. The parser shall
* not invoke this method until it has either abandoned parsing
* (because of an unrecoverable error) or reached the end of
* input.</p>
*
* @throws org.xml.sax.SAXException Any SAX exception, possibly
* wrapping another exception.
*
* @throws org.xml.sax.SAXException
*/
public void endDocument() throws org.xml.sax.SAXException
{
this.flush();
flushWriter();
}
/**
* Receive notification of the beginning of an element.
*
* <p>The Parser will invoke this method at the beginning of every
* element in the XML document; there will be a corresponding
* endElement() event for every startElement() event (even when the
* element is empty). All of the element's content will be
* reported, in order, before the corresponding endElement()
* event.</p>
*
* <p>If the element name has a namespace prefix, the prefix will
* still be attached. Note that the attribute list provided will
* contain only attributes with explicit values (specified or
* defaulted): #IMPLIED attributes will be omitted.</p>
*
*
* @param namespaceURI The Namespace URI, or the empty string if the
* element has no Namespace URI or if Namespace
* processing is not being performed.
* @param localName The local name (without prefix), or the
* empty string if Namespace processing is not being
* performed.
* @param name The qualified name (with prefix), or the
* empty string if qualified names are not available.
* @param atts The attributes attached to the element, if any.
* @throws org.xml.sax.SAXException Any SAX exception, possibly
* wrapping another exception.
* @see #endElement
* @see org.xml.sax.AttributeList
*
* @throws org.xml.sax.SAXException
*/
public void startElement(
String namespaceURI, String localName, String name, Attributes atts)
throws org.xml.sax.SAXException
{
// No action for the moment.
}
/**
* Receive notification of the end of an element.
*
* <p>The SAX parser will invoke this method at the end of every
* element in the XML document; there will be a corresponding
* startElement() event for every endElement() event (even when the
* element is empty).</p>
*
* <p>If the element name has a namespace prefix, the prefix will
* still be attached to the name.</p>
*
*
* @param namespaceURI The Namespace URI, or the empty string if the
* element has no Namespace URI or if Namespace
* processing is not being performed.
* @param localName The local name (without prefix), or the
* empty string if Namespace processing is not being
* performed.
* @param name The qualified name (with prefix), or the
* empty string if qualified names are not available.
* @param name The element type name
* @throws org.xml.sax.SAXException Any SAX exception, possibly
* wrapping another exception.
*
* @throws org.xml.sax.SAXException
*/
public void endElement(String namespaceURI, String localName, String name)
throws org.xml.sax.SAXException
{
// No action for the moment.
}
/**
* Receive notification of character data.
*
* <p>The Parser will call this method to report each chunk of
* character data. SAX parsers may return all contiguous character
* data in a single chunk, or they may split it into several
* chunks; however, all of the characters in any single event
* must come from the same external entity, so that the Locator
* provides useful information.</p>
*
* <p>The application must not attempt to read from the array
* outside of the specified range.</p>
*
* <p>Note that some parsers will report whitespace using the
* ignorableWhitespace() method rather than this one (validating
* parsers must do so).</p>
*
* @param ch The characters from the XML document.
* @param start The start position in the array.
* @param length The number of characters to read from the array.
* @throws org.xml.sax.SAXException Any SAX exception, possibly
* wrapping another exception.
* @see #ignorableWhitespace
* @see org.xml.sax.Locator
*/
public void characters(char ch[], int start, int length)
throws org.xml.sax.SAXException
{
// this.accum(ch, start, length);
try
{
writeNormalizedChars(ch, start, length, false);
}
catch(IOException ioe)
{
throw new SAXException(ioe);
}
this.flush();
// flushWriter();
}
/**
* If available, when the disable-output-escaping attribute is used,
* output raw text without escaping.
*
* @param ch The characters from the XML document.
* @param start The start position in the array.
* @param length The number of characters to read from the array.
*
* @throws org.xml.sax.SAXException Any SAX exception, possibly
* wrapping another exception.
*/
public void charactersRaw(char ch[], int start, int length)
throws org.xml.sax.SAXException
{
// accum(ch, start, length);
try
{
writeNormalizedChars(ch, start, length, false);
}
catch(IOException ioe)
{
throw new SAXException(ioe);
}
flush();
// flushWriter();
}
/**
* Receive notification of cdata.
*
* <p>The Parser will call this method to report each chunk of
* character data. SAX parsers may return all contiguous character
* data in a single chunk, or they may split it into several
* chunks; however, all of the characters in any single event
* must come from the same external entity, so that the Locator
* provides useful information.</p>
*
* <p>The application must not attempt to read from the array
* outside of the specified range.</p>
*
* <p>Note that some parsers will report whitespace using the
* ignorableWhitespace() method rather than this one (validating
* parsers must do so).</p>
*
* @param ch The characters from the XML document.
* @param start The start position in the array.
* @param length The number of characters to read from the array.
* @throws org.xml.sax.SAXException Any SAX exception, possibly
* wrapping another exception.
* @see #ignorableWhitespace
* @see org.xml.sax.Locator
*/
public void cdata(char ch[], int start, int length)
throws org.xml.sax.SAXException
{
// accum(ch, start, length);
try
{
writeNormalizedChars(ch, start, length, false);
}
catch(IOException ioe)
{
throw new SAXException(ioe);
}
flush();
// flushWriter();
}
/**
* Receive notification of ignorable whitespace in element content.
*
* <p>Validating Parsers must use this method to report each chunk
* of ignorable whitespace (see the W3C XML 1.0 recommendation,
* section 2.10): non-validating parsers may also use this method
* if they are capable of parsing and using content models.</p>
*
* <p>SAX parsers may return all contiguous whitespace in a single
* chunk, or they may split it into several chunks; however, all of
* the characters in any single event must come from the same
* external entity, so that the Locator provides useful
* information.</p>
*
* <p>The application must not attempt to read from the array
* outside of the specified range.</p>
*
* @param ch The characters from the XML document.
* @param start The start position in the array.
* @param length The number of characters to read from the array.
* @throws org.xml.sax.SAXException Any SAX exception, possibly
* wrapping another exception.
* @see #characters
*
* @throws org.xml.sax.SAXException
*/
public void ignorableWhitespace(char ch[], int start, int length)
throws org.xml.sax.SAXException
{
try
{
writeNormalizedChars(ch, start, length, false);
}
catch(IOException ioe)
{
throw new SAXException(ioe);
}
flush();
}
/**
* Receive notification of a processing instruction.
*
* <p>The Parser will invoke this method once for each processing
* instruction found: note that processing instructions may occur
* before or after the main document element.</p>
*
* <p>A SAX parser should never report an XML declaration (XML 1.0,
* section 2.8) or a text declaration (XML 1.0, section 4.3.1)
* using this method.</p>
*
* @param target The processing instruction target.
* @param data The processing instruction data, or null if
* none was supplied.
* @throws org.xml.sax.SAXException Any SAX exception, possibly
* wrapping another exception.
*
* @throws org.xml.sax.SAXException
*/
public void processingInstruction(String target, String data)
throws org.xml.sax.SAXException
{
// No action for the moment.
}
/**
* Called when a Comment is to be constructed.
* @param data The comment data.
* @throws org.xml.sax.SAXException Any SAX exception, possibly
* wrapping another exception.
*
* @throws org.xml.sax.SAXException
*/
public void comment(String data) throws org.xml.sax.SAXException
{
// No action for the moment.
}
/**
* Receive notivication of a entityReference.
*
* @param name non-null reference to the name of the entity.
*
* @throws org.xml.sax.SAXException
*/
public void entityReference(String name) throws org.xml.sax.SAXException
{
// No action for the moment.
}
}
1.1 xml-xalan/java/src/org/apache/xalan/serialize/SerializerToXML.java
Index: SerializerToXML.java
===================================================================
/*
* The Apache Software License, Version 1.1
*
*
* Copyright (c) 1999 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Xalan" and "Apache Software Foundation" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation and was
* originally based on software copyright (c) 1999, Lotus
* Development Corporation., http://www.lotus.com. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
package org.apache.xalan.serialize;
import java.io.Writer;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Stack;
import java.util.Vector;
import java.util.Hashtable;
import java.util.Properties;
import org.xml.sax.*;
import org.xml.sax.ext.LexicalHandler;
import org.w3c.dom.Node;
import org.apache.xalan.serialize.Serializer;
import org.apache.xalan.serialize.DOMSerializer;
import org.apache.xml.utils.QName;
import org.apache.xalan.templates.OutputProperties;
import org.apache.xml.utils.BoolStack;
import org.apache.xml.utils.TreeWalker;
import org.apache.xml.utils.WrappedRuntimeException;
import org.apache.xml.utils.SystemIDResolver;
import org.apache.xalan.res.XSLTErrorResources;
import org.apache.xalan.res.XSLMessages;
import org.apache.xpath.res.XPATHErrorResources;
import javax.xml.transform.Result;
import javax.xml.transform.OutputKeys;
/**
* <meta name="usage" content="general"/>
* SerializerToXML formats SAX-style events into XML.
*/
public class SerializerToXML
implements ContentHandler, LexicalHandler, Serializer, DOMSerializer
{
/**
* The writer where the XML will be written.
*/
protected Writer m_writer = null;
/** True if we control the buffer, and we should flush the output on endDocument. */
boolean m_shouldFlush = true;
/** The output stream where the result stream is written. */
protected OutputStream m_outputStream = System.out;
/** True if no encoding has to take place, if we're not writting to a Writer. */
private boolean m_bytesEqualChars = false;
/**
* The character encoding. Must match the encoding used for the printWriter.
*/
protected String m_encoding = null;
/**
* Assume java encoding names are the same as the ISO encoding names if this is true.
*/
static boolean javaEncodingIsISO = false;
/**
* Tells if we should write the XML declaration.
*/
public boolean m_shouldNotWriteXMLHeader = false;
/**
* Tells the XML version, for writing out to the XML decl.
*/
public String m_version = null;
/**
* A stack of Boolean objects that tell if the given element
* has children.
*/
protected BoolStack m_elemStack = new BoolStack();
/** Stack to keep track of disabling output escaping. */
protected BoolStack m_disableOutputEscapingStates = new BoolStack();
/** True will be pushed, if characters should be in CDATA section blocks. */
protected BoolStack m_cdataSectionStates = new BoolStack();
/** List of QNames obtained from the xsl:output properties. */
protected Vector m_cdataSectionNames = null;
/** True if the current characters should be in CDATA blocks. */
protected boolean m_inCData = false;
/**
* Tell if the character escaping should be disabled for the current state.
*
* @return true if the character escaping should be disabled.
*/
protected boolean isEscapingDisabled()
{
return m_disableOutputEscapingStates.peekOrFalse();
}
/**
* Tell if the characters in the current state should be put in
* cdata section blocks.
*
* @return true if the characters in the current state should be put in
* cdata section blocks.
*/
protected boolean isCDataSection()
{
return m_inCData || m_cdataSectionStates.peekOrFalse();
}
/**
* Use the system line seperator to write line breaks.
*/
protected final String m_lineSep = System.getProperty("line.separator");
/**
* The length of the line seperator, since the write is done
* one character at a time.
*/
protected final int m_lineSepLen = m_lineSep.length();
/**
* Output a system-dependent line break.
*
* @throws org.xml.sax.SAXException
*/
protected final void outputLineSep() throws org.xml.sax.SAXException
{
for (int z = 0; z < m_lineSepLen; z++)
{
accum(m_lineSep.charAt(z));
}
}
/**
* State flag to tell if preservation of whitespace
* is important.
*/
protected boolean m_ispreserve = false;
/**
* Stack to keep track of whether or not we need to
* preserve whitespace.
*/
protected BoolStack m_preserves = new BoolStack();
/**
* State flag that tells if the previous node processed
* was text, so we can tell if we should preserve whitespace.
*/
protected boolean m_isprevtext = false;
/**
* Flag to tell if indenting (pretty-printing) is on.
*/
protected boolean m_doIndent = false;
/**
* Flag to keep track of the indent amount.
*/
protected int m_currentIndent = 0;
/**
* Amount to indent.
*/
public int m_indentAmount = 0;
/**
* Current level of indent.
*/
protected int level = 0;
/**
* Flag to signal that a newline should be added.
*/
boolean m_startNewLine;
/**
* Flag to tell that we need to add the doctype decl,
* which we can't do until the first element is
* encountered.
*/
boolean m_needToOutputDocTypeDecl = true;
/**
* The System ID for the doc type.
*/
String m_doctypeSystem;
/**
* The public ID for the doc type.
*/
String m_doctypePublic;
/**
* The standalone value for the doctype.
*/
boolean m_standalone = false;
/**
* True if standalone was specified.
*/
boolean m_standaloneWasSpecified = false;
/**
* The mediatype. Not used right now.
*/
String m_mediatype;
/**
* Tells if we're in an EntityRef event.
*/
protected boolean m_inEntityRef = false;
/**
* Map that tells which XML characters should have special treatment, and it
* provides character to entity name lookup.
*/
protected static CharInfo m_xmlcharInfo =
new CharInfo(CharInfo.XML_ENTITIES_RESOURCE);
/**
* Map that tells which characters should have special treatment, and it
* provides character to entity name lookup.
*/
protected CharInfo m_charInfo;
/** Table of user-specified char infos. */
private static Hashtable m_charInfos = null;
/**
* Flag to quickly tell if the encoding is UTF8.
*/
boolean m_isUTF8;
/**
* The maximum character size before we have to resort
* to escaping.
*/
int m_maxCharacter = Encodings.getLastPrintable();
/**
* Add space before '/>' for XHTML.
*/
public boolean m_spaceBeforeClose = false;
/** The xsl:output properties. */
protected Properties m_format;
/** Indicate whether running in Debug mode */
private static final boolean DEBUG = false;
/**
* Default constructor.
*/
public SerializerToXML()
{
m_charInfo = m_xmlcharInfo;
}
/**
* Copy properties from another SerializerToXML.
*
* @param xmlListener non-null reference to a SerializerToXML object.
*/
public void CopyFrom(SerializerToXML xmlListener)
{
m_writer = xmlListener.m_writer;
m_outputStream = xmlListener.m_outputStream;
m_bytesEqualChars = xmlListener.m_bytesEqualChars;
m_encoding = xmlListener.m_encoding;
javaEncodingIsISO = xmlListener.javaEncodingIsISO;
m_shouldNotWriteXMLHeader = xmlListener.m_shouldNotWriteXMLHeader;
m_shouldNotWriteXMLHeader = xmlListener.m_shouldNotWriteXMLHeader;
m_elemStack = xmlListener.m_elemStack;
// m_lineSep = xmlListener.m_lineSep;
// m_lineSepLen = xmlListener.m_lineSepLen;
m_ispreserve = xmlListener.m_ispreserve;
m_preserves = xmlListener.m_preserves;
m_isprevtext = xmlListener.m_isprevtext;
m_doIndent = xmlListener.m_doIndent;
m_currentIndent = xmlListener.m_currentIndent;
m_indentAmount = xmlListener.m_indentAmount;
level = xmlListener.level;
m_startNewLine = xmlListener.m_startNewLine;
m_needToOutputDocTypeDecl = xmlListener.m_needToOutputDocTypeDecl;
m_doctypeSystem = xmlListener.m_doctypeSystem;
m_doctypePublic = xmlListener.m_doctypePublic;
m_standalone = xmlListener.m_standalone;
m_mediatype = xmlListener.m_mediatype;
m_maxCharacter = xmlListener.m_maxCharacter;
m_spaceBeforeClose = xmlListener.m_spaceBeforeClose;
m_inCData = xmlListener.m_inCData;
m_charBuf = xmlListener.m_charBuf;
m_byteBuf = xmlListener.m_byteBuf;
// m_pos = xmlListener.m_pos;
m_pos = 0;
}
/**
* Initialize the serializer with the specified writer and output format.
* Must be called before calling any of the serialize methods.
*
* @param writer The writer to use
* @param format The output format
*/
public synchronized void init(Writer writer, Properties format)
{
init(writer, format, false);
}
/**
* Initialize the serializer with the specified writer and output format.
* Must be called before calling any of the serialize methods.
*
* @param writer The writer to use
* @param format The output format
* @param shouldFlush True if the writer should be flushed at EndDocument.
*/
private synchronized void init(Writer writer, Properties format,
boolean shouldFlush)
{
m_shouldFlush = shouldFlush;
m_writer = writer;
m_format = format;
m_cdataSectionNames =
OutputProperties.getQNameProperties(OutputKeys.CDATA_SECTION_ELEMENTS,
format);
m_indentAmount =
OutputProperties.getIntProperty(OutputProperties.S_KEY_INDENT_AMOUNT,
format);
m_doIndent = OutputProperties.getBooleanProperty(OutputKeys.INDENT,
format);
m_shouldNotWriteXMLHeader =
OutputProperties.getBooleanProperty(OutputKeys.OMIT_XML_DECLARATION,
format);
m_doctypeSystem = format.getProperty(OutputKeys.DOCTYPE_SYSTEM);
m_doctypePublic = format.getProperty(OutputKeys.DOCTYPE_PUBLIC);
m_standaloneWasSpecified = (null != format.get(OutputKeys.STANDALONE));
m_standalone = OutputProperties.getBooleanProperty(OutputKeys.STANDALONE,
format);
m_mediatype = format.getProperty(OutputKeys.MEDIA_TYPE);
if (null != m_doctypePublic)
{
if (m_doctypePublic.startsWith("-//W3C//DTD XHTML"))
m_spaceBeforeClose = true;
}
// initCharsMap();
if (null == m_encoding)
m_encoding =
Encodings.getMimeEncoding(format.getProperty(OutputKeys.ENCODING));
m_isUTF8 = m_encoding.equals(Encodings.DEFAULT_MIME_ENCODING);
m_maxCharacter = Encodings.getLastPrintable(m_encoding);
// Access this only from the Hashtable level... we don't want to
// get default properties.
String entitiesFileName =
(String) format.get(OutputProperties.S_KEY_ENTITIES);
if (null != entitiesFileName)
{
try
{
m_charInfo = null;
if (null == m_charInfos)
{
synchronized (m_xmlcharInfo)
{
if (null == m_charInfos) // secondary check
m_charInfos = new Hashtable();
}
}
else
{
m_charInfo = (CharInfo) m_charInfos.get(entitiesFileName);
}
if (null == m_charInfo)
{
String absoluteEntitiesFileName;
if (entitiesFileName.indexOf(':') < 0)
{
absoluteEntitiesFileName =
SystemIDResolver.getAbsoluteURIFromRelative(entitiesFileName);
}
else
{
absoluteEntitiesFileName =
SystemIDResolver.getAbsoluteURI(entitiesFileName, null);
}
m_charInfo = new CharInfo(absoluteEntitiesFileName);
m_charInfos.put(entitiesFileName, m_charInfo);
}
}
catch (javax.xml.transform.TransformerException te)
{
throw new org.apache.xml.utils.WrappedRuntimeException(te);
}
}
}
/**
* Initialize the serializer with the specified output stream and output format.
* Must be called before calling any of the serialize methods.
*
* @param output The output stream to use
* @param format The output format
* @throws UnsupportedEncodingException The encoding specified
* in the output format is not supported
*/
public synchronized void init(OutputStream output, Properties format)
throws UnsupportedEncodingException
{
if (null == format)
{
OutputProperties op = new OutputProperties(Method.XML);
format = op.getProperties();
}
m_encoding =
Encodings.getMimeEncoding(format.getProperty(OutputKeys.ENCODING));
if (m_encoding.equals("WINDOWS-1250") || m_encoding.equals("US-ASCII")
|| m_encoding.equals("ASCII"))
{
m_bytesEqualChars = true;
m_outputStream = output;
init((Writer) null, format, true);
}
else
{
Writer osw;
try
{
osw = Encodings.getWriter(output, m_encoding);
}
catch (UnsupportedEncodingException uee)
{
System.out.println("Warning: encoding \"" + m_encoding
+ "\" not supported" + ", using "
+ Encodings.DEFAULT_MIME_ENCODING);
m_encoding = Encodings.DEFAULT_MIME_ENCODING;
osw = Encodings.getWriter(output, m_encoding);
}
m_maxCharacter = Encodings.getLastPrintable(m_encoding);
init(osw, format, true);
}
}
/**
* Receive an object for locating the origin of SAX document events.
*
* @param locator An object that can return the location of
* any SAX document event.
* @see org.xml.sax.Locator
*/
public void setDocumentLocator(Locator locator)
{
// I don't do anything with this yet.
}
/**
* Output the doc type declaration.
*
* @param name non-null reference to document type name.
*
* @throws org.xml.sax.SAXException
*/
void outputDocTypeDecl(String name) throws org.xml.sax.SAXException
{
accum("<!DOCTYPE ");
accum(name);
if (null != m_doctypePublic)
{
accum(" PUBLIC \"");
accum(m_doctypePublic);
accum("\"");
}
if (null == m_doctypePublic)
accum(" SYSTEM \"");
else
accum(" \"");
accum(m_doctypeSystem);
accum("\">");
outputLineSep();
}
/**
* Receive notification of the beginning of a document.
*
* @throws org.xml.sax.SAXException Any SAX exception, possibly
* wrapping another exception.
*
* @throws org.xml.sax.SAXException
*/
public void startDocument() throws org.xml.sax.SAXException
{
if (m_inEntityRef)
return;
m_needToOutputDocTypeDecl = true;
m_startNewLine = false;
if (m_shouldNotWriteXMLHeader == false)
{
String encoding = Encodings.getMimeEncoding(m_encoding);
String version = (null == m_version) ? "1.0" : m_version;
String standalone;
if (m_standaloneWasSpecified)
{
standalone = " standalone=\"" + (m_standalone ? "yes" : "no") + "\"";
}
else
{
standalone = "";
}
accum("<?xml version=\"" + version + "\" encoding=\"" + encoding + "\""
+ standalone + "?>");
outputLineSep();
}
}
/**
* Receive notification of the end of a document.
*
* @throws org.xml.sax.SAXException Any SAX exception, possibly
* wrapping another exception.
*
* @throws org.xml.sax.SAXException
*/
public void endDocument() throws org.xml.sax.SAXException
{
if (m_doIndent &&!m_isprevtext)
{
outputLineSep();
}
flush();
flushWriter();
}
/**
* Report the start of DTD declarations, if any.
*
* Any declarations are assumed to be in the internal subset
* unless otherwise indicated.
*
* @param name The document type name.
* @param publicId The declared public identifier for the
* external DTD subset, or null if none was declared.
* @param systemId The declared system identifier for the
* external DTD subset, or null if none was declared.
* @throws org.xml.sax.SAXException The application may raise an
* exception.
* @see #endDTD
* @see #startEntity
*/
public void startDTD(String name, String publicId, String systemId)
throws org.xml.sax.SAXException
{
// Do nothing for now.
}
/**
* Report the end of DTD declarations.
*
* @throws org.xml.sax.SAXException The application may raise an exception.
* @see #startDTD
*/
public void endDTD() throws org.xml.sax.SAXException
{
// Do nothing for now.
}
/**
* Begin the scope of a prefix-URI Namespace mapping.
* @see org.xml.sax.ContentHandler#startPrefixMapping
*
* @param prefix The Namespace prefix being declared.
* @param uri The Namespace URI the prefix is mapped to.
* @throws org.xml.sax.SAXException The client may throw
* an exception during processing.
*/
public void startPrefixMapping(String prefix, String uri)
throws org.xml.sax.SAXException{}
/**
* End the scope of a prefix-URI Namespace mapping.
* @see org.xml.sax.ContentHandler#endPrefixMapping
*
* @param prefix The prefix that was being mapping.
* @throws org.xml.sax.SAXException The client may throw
* an exception during processing.
*/
public void endPrefixMapping(String prefix)
throws org.xml.sax.SAXException{}
/**
* Tell if two strings are equal, without worry if the first string is null.
*
* @param p String reference, which may be null.
* @param t String reference, which may be null.
*
* @return true if strings are equal.
*/
protected static final boolean subPartMatch(String p, String t)
{
return (p == t) || ((null != p) && (p.equals(t)));
}
/**
* Push a boolean state based on if the name of the element
* is found in the list of qnames. A state is always pushed,
* one way or the other.
*
* @param namespaceURI Should be a non-null reference to the namespace URL
* of the element that owns the state, or empty string.
* @param localName Should be a non-null reference to the local name
* of the element that owns the state.
* @param qnames Vector of qualified names of elements, or null.
* @param state The stack where the state should be pushed.
*/
protected void pushState(String namespaceURI, String localName,
Vector qnames, BoolStack state)
{
boolean b;
if (null != qnames)
{
b = false;
if ((null != namespaceURI) && namespaceURI.length() == 0)
namespaceURI = null;
int nElems = qnames.size();
for (int i = 0; i < nElems; i++)
{
QName q = (QName) qnames.elementAt(i);
if (q.getLocalName().equals(localName)
&& subPartMatch(namespaceURI, q.getNamespaceURI()))
{
b = true;
break;
}
}
}
else
{
b = state.peekOrFalse();
}
state.push(b);
}
/**
* Receive notification of the beginning of an element.
*
*
* @param namespaceURI The Namespace URI, or the empty string if the
* element has no Namespace URI or if Namespace
* processing is not being performed.
* @param localName The local name (without prefix), or the
* empty string if Namespace processing is not being
* performed.
* @param name The element type name.
* @param atts The attributes attached to the element, if any.
* @throws org.xml.sax.SAXException Any SAX exception, possibly
* wrapping another exception.
* @see org.xml.sax.ContentHandler#startElement
* @see org.xml.sax.ContentHandler#endElement
* @see org.xml.sax.AttributeList
*
* @throws org.xml.sax.SAXException
*/
public void startElement(
String namespaceURI, String localName, String name, Attributes atts)
throws org.xml.sax.SAXException
{
if(DEBUG)
{
System.out.println("SerializerToXML - startElement: "+namespaceURI+", "+localName);
int n = atts.getLength();
for (int i = 0; i < n; i++)
{
System.out.println("atts["+i+"]: "+atts.getQName(i)+" = "+atts.getValue(i));
}
if(null == namespaceURI)
{
(new RuntimeException(localName+" has a null namespace!")).printStackTrace();
}
}
if (m_inEntityRef)
return;
if ((true == m_needToOutputDocTypeDecl) && (null != m_doctypeSystem))
{
outputDocTypeDecl(name);
}
m_needToOutputDocTypeDecl = false;
writeParentTagEnd();
pushState(namespaceURI, localName, m_cdataSectionNames,
m_cdataSectionStates);
// pushState(namespaceURI, localName, m_format.getNonEscapingElements(),
// m_disableOutputEscapingStates);
m_ispreserve = false;
// System.out.println(name+": m_doIndent = "+m_doIndent+", m_ispreserve = "+m_ispreserve+", m_isprevtext = "+m_isprevtext);
if (shouldIndent() && m_startNewLine)
{
indent(m_currentIndent);
}
m_startNewLine = true;
accum('<');
accum(name);
int nAttrs = atts.getLength();
for (int i = 0; i < nAttrs; i++)
{
processAttribute(atts.getQName(i), atts.getValue(i));
}
// Flag the current element as not yet having any children.
openElementForChildren();
m_currentIndent += m_indentAmount;
m_isprevtext = false;
}
/**
* Check to see if a parent's ">" has been written, and, if
* it has not, write it.
*
* @throws org.xml.sax.SAXException
*/
protected void writeParentTagEnd() throws org.xml.sax.SAXException
{
if (!m_elemStack.isEmpty())
{
// See if the parent element has already been flagged as having children.
if ((false == m_elemStack.peek()))
{
accum('>');
m_isprevtext = false;
m_elemStack.pop();
m_elemStack.push(true);
m_preserves.push(m_ispreserve);
}
}
}
/**
* Flag the current element as not yet having any
* children.
*/
protected void openElementForChildren()
{
// Flag the current element as not yet having any children.
m_elemStack.push(false);
}
/**
* Tell if child nodes have been added to the current
* element. Must be called in balance with openElementForChildren().
*
* @return true if child nodes were added.
*/
protected boolean childNodesWereAdded()
{
return m_elemStack.isEmpty() ? false : m_elemStack.pop();
}
/**
* Receive notification of the end of an element.
*
*
* @param namespaceURI The Namespace URI, or the empty string if the
* element has no Namespace URI or if Namespace
* processing is not being performed.
* @param localName The local name (without prefix), or the
* empty string if Namespace processing is not being
* performed.
* @param name The element type name
* @throws org.xml.sax.SAXException Any SAX exception, possibly
* wrapping another exception.
*
* @throws org.xml.sax.SAXException
*/
public void endElement(String namespaceURI, String localName, String name)
throws org.xml.sax.SAXException
{
if (m_inEntityRef)
return;
m_currentIndent -= m_indentAmount;
boolean hasChildNodes = childNodesWereAdded();
if (hasChildNodes)
{
if (shouldIndent())
indent(m_currentIndent);
accum('<');
accum('/');
accum(name);
accum('>');
}
else
{
if (m_spaceBeforeClose)
accum(" />");
else
accum("/>");
}
if (hasChildNodes)
{
m_ispreserve = m_preserves.isEmpty() ? false : m_preserves.pop();
}
m_isprevtext = false;
// m_disableOutputEscapingStates.pop();
m_cdataSectionStates.pop();
}
/**
* Process an attribute.
* @param name The name of the attribute.
* @param value The value of the attribute.
*
* @throws org.xml.sax.SAXException
*/
protected void processAttribute(String name, String value)
throws org.xml.sax.SAXException
{
accum(' ');
accum(name);
accum("=\"");
writeAttrString(value, m_encoding);
accum('\"');
}
/**
* Starts an un-escaping section. All characters printed within an
* un-escaping section are printed as is, without escaping special
* characters into entity references. Only XML and HTML serializers
* need to support this method.
* <p>
* The contents of the un-escaping section will be delivered through
* the regular <tt>characters</tt> event.
*
* @throws org.xml.sax.SAXException
*/
public void startNonEscaping() throws org.xml.sax.SAXException
{
m_disableOutputEscapingStates.push(true);
}
/**
* Ends an un-escaping section.
*
* @see #startNonEscaping
*
* @throws org.xml.sax.SAXException
*/
public void endNonEscaping() throws org.xml.sax.SAXException
{
m_disableOutputEscapingStates.pop();
}
/**
* Starts a whitespace preserving section. All characters printed
* within a preserving section are printed without indentation and
* without consolidating multiple spaces. This is equivalent to
* the <tt>xml:space="preserve"</tt> attribute. Only XML
* and HTML serializers need to support this method.
* <p>
* The contents of the whitespace preserving section will be delivered
* through the regular <tt>characters</tt> event.
*
* @throws org.xml.sax.SAXException
*/
public void startPreserving() throws org.xml.sax.SAXException
{
// Not sure this is really what we want. -sb
m_preserves.push(true);
m_ispreserve = true;
}
/**
* Ends a whitespace preserving section.
*
* @see #startPreserving
*
* @throws org.xml.sax.SAXException
*/
public void endPreserving() throws org.xml.sax.SAXException
{
// Not sure this is really what we want. -sb
m_ispreserve = m_preserves.isEmpty() ? false : m_preserves.pop();
}
/**
* Receive notification of a processing instruction.
*
* @param target The processing instruction target.
* @param data The processing instruction data, or null if
* none was supplied.
* @throws org.xml.sax.SAXException Any SAX exception, possibly
* wrapping another exception.
*
* @throws org.xml.sax.SAXException
*/
public void processingInstruction(String target, String data)
throws org.xml.sax.SAXException
{
if (m_inEntityRef)
return;
if (target.equals(Result.PI_DISABLE_OUTPUT_ESCAPING))
{
startNonEscaping();
}
else if (target.equals(Result.PI_ENABLE_OUTPUT_ESCAPING))
{
endNonEscaping();
}
else
{
writeParentTagEnd();
if (shouldIndent())
indent(m_currentIndent);
accum('<');
accum('?');
accum(target);
if (data.length() > 0 &&!Character.isSpaceChar(data.charAt(0)))
accum(' ');
int indexOfQLT = data.indexOf("?>");
if(indexOfQLT >= 0)
{
// See XSLT spec on error recovery of "?>" in PIs.
if(indexOfQLT > 0)
{
accum(data.substring(0, indexOfQLT));
}
accum("? >"); // add space between.
if((indexOfQLT+2) < data.length())
{
accum(data.substring(indexOfQLT+2));
}
}
else
{
accum(data);
}
accum('?');
accum('>');
// Always output a newline char if not inside of an
// element. The whitespace is not significant in that
// case.
if (m_elemStack.isEmpty())
outputLineSep();
m_startNewLine = true;
}
}
/**
* Report an XML comment anywhere in the document.
*
* This callback will be used for comments inside or outside the
* document element, including comments in the external DTD
* subset (if read).
*
* @param ch An array holding the characters in the comment.
* @param start The starting position in the array.
* @param length The number of characters to use from the array.
* @throws org.xml.sax.SAXException The application may raise an exception.
*/
public void comment(char ch[], int start, int length)
throws org.xml.sax.SAXException
{
if (m_inEntityRef)
return;
writeParentTagEnd();
if (shouldIndent())
indent(m_currentIndent);
accum("<!--");
accum(ch, start, length);
accum("-->");
m_startNewLine = true;
}
/**
* Report the start of a CDATA section.
*
* @throws org.xml.sax.SAXException The application may raise an exception.
* @see #endCDATA
*/
public void startCDATA() throws org.xml.sax.SAXException
{
m_inCData = true;
}
/**
* Report the end of a CDATA section.
*
* @throws org.xml.sax.SAXException The application may raise an exception.
* @see #startCDATA
*/
public void endCDATA() throws org.xml.sax.SAXException
{
m_inCData = false;
}
/**
* Receive notification of cdata.
*
* <p>The Parser will call this method to report each chunk of
* character data. SAX parsers may return all contiguous character
* data in a single chunk, or they may split it into several
* chunks; however, all of the characters in any single event
* must come from the same external entity, so that the Locator
* provides useful information.</p>
*
* <p>The application must not attempt to read from the array
* outside of the specified range.</p>
*
* <p>Note that some parsers will report whitespace using the
* ignorableWhitespace() method rather than this one (validating
* parsers must do so).</p>
*
* @param ch The characters from the XML document.
* @param start The start position in the array.
* @param length The number of characters to read from the array.
* @throws org.xml.sax.SAXException Any SAX exception, possibly
* wrapping another exception.
* @see #ignorableWhitespace
* @see org.xml.sax.Locator
*
* @throws org.xml.sax.SAXException
*/
public void cdata(char ch[], int start, int length)
throws org.xml.sax.SAXException
{
try
{
writeParentTagEnd();
m_ispreserve = true;
if (shouldIndent())
indent(m_currentIndent);
boolean writeCDataBrackets = (((length >= 1)
&& (ch[start] <= m_maxCharacter)));
if (writeCDataBrackets)
{
accum("<![CDATA[");
}
// accum(ch, start, length);
if (isEscapingDisabled())
{
charactersRaw(ch, start, length);
}
else
writeNormalizedChars(ch, start, length, true);
if (writeCDataBrackets)
{
accum("]]>");
}
}
catch (IOException ioe)
{
throw new org.xml.sax.SAXException(
XSLMessages.createXPATHMessage(XPATHErrorResources.ER_OIERROR, null),
ioe); //"IO error", ioe);
}
}
/** The maximum character buffer, set to 4K to match most servers. */
static final int MAXCHARBUF = (4 * 1024);
/**
* If a character event is greater than this number, don't bother with
* the local buffer.
*/
static final int NUMBERBYTESTOWRITEDIRECT = (1024);
/** Character buffer if characters need to be encoded. */
protected char[] m_charBuf = new char[MAXCHARBUF];
/** Byte buffer if characters do not need to be encoded. */
protected byte[] m_byteBuf = new byte[MAXCHARBUF];
/** The current position in the m_charBuf or m_byteBuf. */
protected int m_pos = 0;
/**
* Append a byte to the buffer.
*
* @param b Byte to be written.
*
* @throws org.xml.sax.SAXException
*/
protected final void accum(byte b) throws org.xml.sax.SAXException
{
if (m_bytesEqualChars)
{
m_byteBuf[m_pos++] = b;
if (m_pos >= MAXCHARBUF)
flushBytes();
}
else
{
m_charBuf[m_pos++] = (char) b;
if (m_pos >= MAXCHARBUF)
flushChars();
}
}
/**
* Append a character to the buffer.
*
* @param b byte to be written to result stream.
*
* @throws org.xml.sax.SAXException
*/
protected final void accum(char b) throws org.xml.sax.SAXException
{
if (m_bytesEqualChars)
{
m_byteBuf[m_pos++] = (byte) b;
if (m_pos >= MAXCHARBUF)
flushBytes();
}
else
{
m_charBuf[m_pos++] = b;
if (m_pos >= MAXCHARBUF)
flushChars();
}
}
/**
* Append a character to the buffer.
*
* @param chars non-null reference to character array.
* @param start Start of characters to be written.
* @param length Number of characters to be written.
*
* @throws org.xml.sax.SAXException
*/
protected final void accum(char chars[], int start, int length)
throws org.xml.sax.SAXException
{
int n = start + length;
if (m_bytesEqualChars)
{
for (int i = start; i < n; i++)
{
m_byteBuf[m_pos++] = (byte) chars[i];
if (m_pos >= MAXCHARBUF)
flushBytes();
}
}
else
{
if (length >= NUMBERBYTESTOWRITEDIRECT)
{
if (m_pos != 0)
flushChars();
try
{
m_writer.write(chars, start, length);
}
catch (IOException ioe)
{
throw new org.xml.sax.SAXException(ioe);
}
}
else
{
if ((m_pos + length) >= MAXCHARBUF)
flushChars();
// if(1 == length)
// m_charBuf[m_pos] = chars[start];
// else
System.arraycopy(chars, start, m_charBuf, m_pos, length);
m_pos += length;
}
}
}
/**
* Append a character to the buffer.
*
* @param s non-null reference to string to be written to the character buffer.
*
* @throws org.xml.sax.SAXException
*/
protected final void accum(String s) throws org.xml.sax.SAXException
{
int n = s.length();
if (m_bytesEqualChars)
{
char[] chars = s.toCharArray();
for (int i = 0; i < n; i++)
{
m_byteBuf[m_pos++] = (byte) chars[i];
;
if (m_pos >= MAXCHARBUF)
flushBytes();
}
}
else
{
if (n >= NUMBERBYTESTOWRITEDIRECT)
{
if (m_pos != 0)
flushChars();
try
{
m_writer.write(s);
}
catch (IOException ioe)
{
throw new org.xml.sax.SAXException(ioe);
}
}
else
{
for (int i = 0; i < n; i++)
{
m_charBuf[m_pos++] = s.charAt(i);
;
if (m_pos >= MAXCHARBUF)
flushChars();
}
}
}
}
/**
* Flush all accumulated bytes to the result stream, without encoding.
*
* @throws org.xml.sax.SAXException
*/
private final void flushBytes() throws org.xml.sax.SAXException
{
try
{
m_outputStream.write(m_byteBuf, 0, m_pos);
m_pos = 0;
}
catch (IOException ioe)
{
throw new org.xml.sax.SAXException(ioe);
}
}
/**
* Flush the formatter's result stream.
*
* @throws org.xml.sax.SAXException
*/
public final void flushWriter() throws org.xml.sax.SAXException
{
if (m_shouldFlush && (null != m_writer))
{
try
{
m_writer.flush();
}
catch (IOException ioe)
{
throw new org.xml.sax.SAXException(ioe);
}
}
}
/**
* Flush all accumulated characters to the result stream.
*
* @throws org.xml.sax.SAXException
*/
private final void flushChars() throws org.xml.sax.SAXException
{
try
{
m_writer.write(m_charBuf, 0, m_pos);
m_pos = 0;
}
catch (IOException ioe)
{
throw new org.xml.sax.SAXException(ioe);
}
}
/**
* Flush all accumulated characters or bytes to the result stream.
*
* @throws org.xml.sax.SAXException
*/
public final void flush() throws org.xml.sax.SAXException
{
if (m_bytesEqualChars)
{
flushBytes();
}
else
{
flushChars();
}
}
/**
* Receive notification of character data.
*
* <p>The Parser will call this method to report each chunk of
* character data. SAX parsers may return all contiguous character
* data in a single chunk, or they may split it into several
* chunks; however, all of the characters in any single event
* must come from the same external entity, so that the Locator
* provides useful information.</p>
*
* <p>The application must not attempt to read from the array
* outside of the specified range.</p>
*
* <p>Note that some parsers will report whitespace using the
* ignorableWhitespace() method rather than this one (validating
* parsers must do so).</p>
*
* @param chars The characters from the XML document.
* @param start The start position in the array.
* @param length The number of characters to read from the array.
* @throws org.xml.sax.SAXException Any SAX exception, possibly
* wrapping another exception.
* @see #ignorableWhitespace
* @see org.xml.sax.Locator
*
* @throws org.xml.sax.SAXException
*/
public void characters(char chars[], int start, int length)
throws org.xml.sax.SAXException
{
if (m_inEntityRef)
return;
if (0 == length)
return;
if (isCDataSection())
{
cdata(chars, start, length);
return;
}
if (isEscapingDisabled())
{
charactersRaw(chars, start, length);
return;
}
writeParentTagEnd();
int startClean = start;
int lengthClean = 0;
// int pos = 0;
int end = start + length;
boolean checkWhite = true;
for (int i = start; i < end; i++)
{
char ch = chars[i];
if (checkWhite)
{
if (!Character.isWhitespace(ch))
{
m_ispreserve = true;
checkWhite = false;
}
}
if ((ch < m_maxCharacter) && (!m_charInfo.isSpecial(ch)))
{
// accum(ch);
lengthClean++;
}
else if ('"' == ch)
{
lengthClean++; // don't escape quote here
}
else
{
if (lengthClean > 0)
{
accum(chars, startClean, lengthClean);
lengthClean = 0;
}
startClean = accumDefaultEscape(ch, i, chars, end, false);
i = startClean - 1;
}
}
if (lengthClean > 0)
{
accum(chars, startClean, lengthClean);
}
m_isprevtext = true;
}
/**
* If available, when the disable-output-escaping attribute is used,
* output raw text without escaping.
*
* @param ch The characters from the XML document.
* @param start The start position in the array.
* @param length The number of characters to read from the array.
*
* @throws org.xml.sax.SAXException
*/
public void charactersRaw(char ch[], int start, int length)
throws org.xml.sax.SAXException
{
if (m_inEntityRef)
return;
writeParentTagEnd();
m_ispreserve = true;
accum(ch, start, length);
}
/**
* Return true if the character is the high member of a surrogate pair.
*/
static final boolean isUTF16Surrogate(char c)
{
return (c & 0xFC00) == 0xD800;
}
/**
* Once a surrogate has been detected, get the pair as a single
* integer value.
*
* @param c the first part of the surrogate.
* @param ch Character array.
* @param i position Where the surrogate was detected.
* @param end The end index of the significant characters.
* @return i+1.
* @throws org.xml.sax.SAXException if invalid UTF-16 surrogate detected.
*/
int getURF16SurrogateValue(char c, char ch[], int i, int end)
throws org.xml.sax.SAXException
{
int next;
if (i + 1 >= end)
{
throw new org.xml.sax.SAXException(
XSLMessages.createXPATHMessage(
XPATHErrorResources.ER_INVALID_UTF16_SURROGATE,
new Object[]{ Integer.toHexString((int) c) })); //"Invalid UTF-16 surrogate detected: "
//+Integer.toHexString((int)c)+ " ?");
}
else
{
next = ch[++i];
if (!(0xdc00 <= next && next < 0xe000))
throw new org.xml.sax.SAXException(
XSLMessages.createXPATHMessage(
XPATHErrorResources.ER_INVALID_UTF16_SURROGATE,
new Object[]{
Integer.toHexString((int) c) + " "
+ Integer.toHexString(next) })); //"Invalid UTF-16 surrogate detected: "
//+Integer.toHexString((int)c)+" "+Integer.toHexString(next));
next = ((c - 0xd800) << 10) + next - 0xdc00 + 0x00010000;
}
return next;
}
/**
* Once a surrogate has been detected, write the pair as a single
* character reference.
*
* @param c the first part of the surrogate.
* @param ch Character array.
* @param i position Where the surrogate was detected.
* @param end The end index of the significant characters.
* @return i+1.
* @throws IOException
* @throws org.xml.sax.SAXException if invalid UTF-16 surrogate detected.
*/
protected int writeUTF16Surrogate(char c, char ch[], int i, int end)
throws IOException, org.xml.sax.SAXException
{
// UTF-16 surrogate
int surrogateValue = getURF16SurrogateValue(c, ch, i, end);
i++;
accum('&');
accum('#');
// accum('x');
accum(Integer.toString(surrogateValue));
accum(';');
return i;
}
/**
* Normalize the characters, but don't escape.
*
* @param ch The characters from the XML document.
* @param start The start position in the array.
* @param length The number of characters to read from the array.
* @param isCData true if a CDATA block should be built around the characters.
*
* @throws IOException
* @throws org.xml.sax.SAXException
*/
void writeNormalizedChars(char ch[], int start, int length, boolean isCData)
throws IOException, org.xml.sax.SAXException
{
int end = start + length;
for (int i = start; i < end; i++)
{
char c = ch[i];
if (CharInfo.S_LINEFEED == c)
{
outputLineSep();
}
else if (isCData && (c > m_maxCharacter))
{
if (i != 0)
accum("]]>");
// This needs to go into a function...
if (isUTF16Surrogate(c))
{
i = writeUTF16Surrogate(c, ch, i, end);
}
else
{
accum("&#");
String intStr = Integer.toString((int) c);
accum(intStr);
accum(';');
}
if ((i != 0) && (i < (end - 1)))
accum("<![CDATA[");
}
else if (isCData
&& ((i < (end - 2)) && (']' == c) && (']' == ch[i + 1])
&& ('>' == ch[i + 2])))
{
accum("]]]]><![CDATA[>");
i += 2;
}
else
{
if (c <= m_maxCharacter)
{
accum(c);
}
// This needs to go into a function...
else if (isUTF16Surrogate(c))
{
i = writeUTF16Surrogate(c, ch, i, end);
}
else
{
accum("&#");
String intStr = Integer.toString((int) c);
accum(intStr);
accum(';');
}
}
}
}
/**
* Receive notification of ignorable whitespace in element content.
*
* Not sure how to get this invoked quite yet.
*
* @param ch The characters from the XML document.
* @param start The start position in the array.
* @param length The number of characters to read from the array.
* @throws org.xml.sax.SAXException Any SAX exception, possibly
* wrapping another exception.
* @see #characters
*
* @throws org.xml.sax.SAXException
*/
public void ignorableWhitespace(char ch[], int start, int length)
throws org.xml.sax.SAXException
{
if (0 == length)
return;
characters(ch, start, length);
}
/**
* Receive notification of a skipped entity.
* @see org.xml.sax.ContentHandler#skippedEntity
*
* @param name The name of the skipped entity. If it is a
* parameter entity, the name will begin with '%', and if
* it is the external DTD subset, it will be the string
* "[dtd]".
* @throws org.xml.sax.SAXException Any SAX exception, possibly
* wrapping another exception.
*/
public void skippedEntity(String name) throws org.xml.sax.SAXException
{
// TODO: Should handle
}
/**
* Report the beginning of an entity.
*
* The start and end of the document entity are not reported.
* The start and end of the external DTD subset are reported
* using the pseudo-name "[dtd]". All other events must be
* properly nested within start/end entity events.
*
* @param name The name of the entity. If it is a parameter
* entity, the name will begin with '%'.
* @throws org.xml.sax.SAXException The application may raise an exception.
* @see #endEntity
* @see org.xml.sax.ext.DeclHandler#internalEntityDecl
* @see org.xml.sax.ext.DeclHandler#externalEntityDecl
*/
public void startEntity(String name) throws org.xml.sax.SAXException
{
entityReference(name);
m_inEntityRef = true;
}
/**
* Report the end of an entity.
*
* @param name The name of the entity that is ending.
* @throws org.xml.sax.SAXException The application may raise an exception.
* @see #startEntity
*/
public void endEntity(String name) throws org.xml.sax.SAXException
{
m_inEntityRef = false;
}
/**
* Receive notivication of a entityReference.
*
* @param name The name of the entity.
*
* @throws org.xml.sax.SAXException
*/
public void entityReference(String name) throws org.xml.sax.SAXException
{
writeParentTagEnd();
if (shouldIndent())
indent(m_currentIndent);
accum("&");
accum(name);
accum(";");
}
/**
* Handle one of the default entities, return false if it
* is not a default entity.
*
* @param ch character to be escaped.
* @param i index into character array.
* @param chars non-null reference to character array.
* @param len length of chars.
* @param escLF true if the linefeed should be escaped.
*
* @return i+1 if the character was written, else i.
*
* @throws org.xml.sax.SAXException
*/
final int accumDefaultEntity(
char ch, int i, char[] chars, int len, boolean escLF)
throws org.xml.sax.SAXException
{
if (!escLF && CharInfo.S_LINEFEED == ch)
{
outputLineSep();
}
else
{
if (m_charInfo.isSpecial(ch))
{
String entityRef = m_charInfo.getEntityNameForChar(ch);
if (null != entityRef)
{
accum('&');
accum(entityRef);
accum(';');
}
else
return i;
}
else
return i;
}
return i + 1;
}
/**
* Escape and accum a character.
*
* @param ch character to be escaped.
* @param i index into character array.
* @param chars non-null reference to character array.
* @param len length of chars.
* @param escLF true if the linefeed should be escaped.
*
* @return i+1 if the character was written, else i.
*
* @throws org.xml.sax.SAXException
*/
final int accumDefaultEscape(
char ch, int i, char[] chars, int len, boolean escLF)
throws org.xml.sax.SAXException
{
int pos = accumDefaultEntity(ch, i, chars, len, escLF);
if (i == pos)
{
pos++;
if (0xd800 <= ch && ch < 0xdc00)
{
// UTF-16 surrogate
int next;
if (i + 1 >= len)
{
throw new org.xml.sax.SAXException(
XSLMessages.createXPATHMessage(
XPATHErrorResources.ER_INVALID_UTF16_SURROGATE,
new Object[]{ Integer.toHexString(ch) })); //"Invalid UTF-16 surrogate detected: "
//+Integer.toHexString(ch)+ " ?");
}
else
{
next = chars[++i];
if (!(0xdc00 <= next && next < 0xe000))
throw new org.xml.sax.SAXException(
XSLMessages.createXPATHMessage(
XPATHErrorResources.ER_INVALID_UTF16_SURROGATE,
new Object[]{
Integer.toHexString(ch) + " "
+ Integer.toHexString(next) })); //"Invalid UTF-16 surrogate detected: "
//+Integer.toHexString(ch)+" "+Integer.toHexString(next));
next = ((ch - 0xd800) << 10) + next - 0xdc00 + 0x00010000;
}
accum("&#");
accum(Integer.toString(next));
accum(";");
/*} else if (null != ctbc && !ctbc.canConvert(ch)) {
sb.append("&#x");
sb.append(Integer.toString((int)ch, 16));
sb.append(";");*/
}
else
{
if (ch > m_maxCharacter || (m_charInfo.isSpecial(ch)))
{
accum("&#");
accum(Integer.toString(ch));
accum(";");
}
else
{
accum(ch);
}
}
}
return pos;
}
/**
* Returns the specified <var>string</var> after substituting <VAR>specials</VAR>,
* and UTF-16 surrogates for chracter references <CODE>&#xnn</CODE>.
*
* @param string String to convert to XML format.
* @param encoding CURRENTLY NOT IMPLEMENTED.
*
* @throws org.xml.sax.SAXException
*/
public void writeAttrString(String string, String encoding)
throws org.xml.sax.SAXException
{
char[] stringChars = string.toCharArray();
int len = stringChars.length;
for (int i = 0; i < len; i++)
{
char ch = stringChars[i];
if ((ch < m_maxCharacter) && (!m_charInfo.isSpecial(ch)))
{
accum(ch);
}
else
{
// I guess the parser doesn't normalize cr/lf in attributes. -sb
if((CharInfo.S_CARRIAGERETURN == ch) && ((i+1) < len)
&& (CharInfo.S_LINEFEED == stringChars[i+1]))
{
i++;
ch = CharInfo.S_LINEFEED;
}
accumDefaultEscape(ch, i, stringChars, len, true);
}
}
}
/**
* Tell if, based on space preservation constraints and the doIndent property,
* if an indent should occur.
*
* @return True if an indent should occur.
*/
protected boolean shouldIndent()
{
return m_doIndent && (!m_ispreserve &&!m_isprevtext);
}
/**
* Prints <var>n</var> spaces.
* @param pw The character output stream to use.
* @param n Number of spaces to print.
*
* @throws org.xml.sax.SAXException if an error occurs when writing.
*/
public void printSpace(int n) throws org.xml.sax.SAXException
{
for (int i = 0; i < n; i++)
{
accum(' ');
}
}
/**
* Prints a newline character and <var>n</var> spaces.
* @param pw The character output stream to use.
* @param n Number of spaces to print.
*
* @throws org.xml.sax.SAXException if an error occurs during writing.
*/
public void indent(int n) throws org.xml.sax.SAXException
{
if (m_startNewLine)
outputLineSep();
if (m_doIndent)
{
printSpace(n);
}
}
/**
* Specifies an output stream to which the document should be
* serialized. This method should not be called while the
* serializer is in the process of serializing a document.
* <p>
* The encoding specified in the output properties is used, or
* if no encoding was specified, the default for the selected
* output method.
*
* @param output The output stream
*/
public void setOutputStream(OutputStream output)
{
try
{
init(output, m_format);
}
catch (UnsupportedEncodingException uee)
{
// Should have been warned in init, I guess...
}
}
/**
* Get the output stream where the events will be serialized to.
*
* @return reference to the result stream, or null of only a writer was
* set.
*/
public OutputStream getOutputStream()
{
return m_outputStream;
}
/**
* Specifies a writer to which the document should be serialized.
* This method should not be called while the serializer is in
* the process of serializing a document.
*
* @param writer The output writer stream
*/
public void setWriter(Writer writer)
{
m_writer = writer;
}
/**
* Get the character stream where the events will be serialized to.
*
* @return Reference to the result Writer, or null.
*/
public Writer getWriter()
{
return m_writer;
}
/**
* Specifies an output format for this serializer. It the
* serializer has already been associated with an output format,
* it will switch to the new format. This method should not be
* called while the serializer is in the process of serializing
* a document.
*
* @param format The output format to use
*/
public void setOutputFormat(Properties format)
{
boolean shouldFlush = m_shouldFlush;
init(m_writer, format, false);
m_shouldFlush = shouldFlush;
}
/**
* Returns the output format for this serializer.
*
* @return The output format in use
*/
public Properties getOutputFormat()
{
return m_format;
}
/**
* Return a {@link ContentHandler} interface into this serializer.
* If the serializer does not support the {@link ContentHandler}
* interface, it should return null.
*
* @return A {@link ContentHandler} interface into this serializer,
* or null if the serializer is not SAX 2 capable
* @throws IOException An I/O exception occured
*/
public ContentHandler asContentHandler() throws IOException
{
return this;
}
/**
* Return a {@link DOMSerializer} interface into this serializer.
* If the serializer does not support the {@link DOMSerializer}
* interface, it should return null.
*
* @return A {@link DOMSerializer} interface into this serializer,
* or null if the serializer is not DOM capable
* @throws IOException An I/O exception occured
*/
public DOMSerializer asDOMSerializer() throws IOException
{
return this; // for now
}
/**
* Resets the serializer. If this method returns true, the
* serializer may be used for subsequent serialization of new
* documents. It is possible to change the output format and
* output stream prior to serializing, or to use the existing
* output format and output stream.
*
* @return True if serializer has been reset and can be reused
*/
public boolean reset()
{
return false;
}
/**
* Serializes the DOM node. Throws an exception only if an I/O
* exception occured while serializing.
*
* @param elem The element to serialize
*
* @param node Node to serialize.
* @throws IOException An I/O exception occured while serializing
*/
public void serialize(Node node) throws IOException
{
try
{
TreeWalker walker = new TreeWalker(this);
walker.traverse(node);
}
catch (org.xml.sax.SAXException se)
{
throw new WrappedRuntimeException(se);
}
}
} //ToXMLStringVisitor