286N/A/*
286N/A * reserved comment block
286N/A * DO NOT REMOVE OR ALTER!
286N/A */
286N/A/*
286N/A * Copyright 2001-2004 The Apache Software Foundation.
286N/A *
286N/A * Licensed under the Apache License, Version 2.0 (the "License");
286N/A * you may not use this file except in compliance with the License.
286N/A * You may obtain a copy of the License at
286N/A *
286N/A * http://www.apache.org/licenses/LICENSE-2.0
286N/A *
286N/A * Unless required by applicable law or agreed to in writing, software
286N/A * distributed under the License is distributed on an "AS IS" BASIS,
286N/A * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
286N/A * See the License for the specific language governing permissions and
286N/A * limitations under the License.
286N/A */
286N/A/*
286N/A * $Id: ToXMLStream.java,v 1.2.4.2 2005/09/15 12:01:25 suresh_emailid Exp $
286N/A */
286N/A package com.sun.org.apache.xml.internal.serializer;
286N/A
286N/Aimport java.io.IOException;
286N/A
286N/Aimport javax.xml.transform.ErrorListener;
286N/Aimport javax.xml.transform.Result;
286N/Aimport javax.xml.transform.Transformer;
286N/Aimport javax.xml.transform.TransformerException;
286N/A
286N/Aimport com.sun.org.apache.xml.internal.serializer.utils.MsgKey;
286N/Aimport com.sun.org.apache.xml.internal.serializer.utils.Utils;
286N/Aimport org.xml.sax.SAXException;
286N/A
286N/A/**
286N/A * This class converts SAX or SAX-like calls to a
286N/A * serialized xml document. The xsl:output method is "xml".
286N/A *
286N/A * This class is used explicitly in code generated by XSLTC,
286N/A * so it is "public", but it should
286N/A * be viewed as internal or package private, this is not an API.
286N/A *
286N/A * @xsl.usage internal
286N/A */
286N/Apublic final class ToXMLStream extends ToStream
286N/A{
286N/A
286N/A /**
286N/A * remembers if we need to write out "]]>" to close the CDATA
286N/A */
286N/A boolean m_cdataTagOpen = false;
286N/A
286N/A
286N/A /**
286N/A * Map that tells which XML characters should have special treatment, and it
286N/A * provides character to entity name lookup.
286N/A */
358N/A private static CharInfo m_xmlcharInfo =
286N/A// new CharInfo(CharInfo.XML_ENTITIES_RESOURCE);
286N/A CharInfo.getCharInfo(CharInfo.XML_ENTITIES_RESOURCE, Method.XML);
286N/A
286N/A /**
286N/A * Default constructor.
286N/A */
286N/A public ToXMLStream()
286N/A {
286N/A m_charInfo = m_xmlcharInfo;
286N/A
286N/A initCDATA();
286N/A // initialize namespaces
286N/A m_prefixMap = new NamespaceMappings();
286N/A
286N/A }
286N/A
286N/A /**
286N/A * Copy properties from another SerializerToXML.
286N/A *
286N/A * @param xmlListener non-null reference to a SerializerToXML object.
286N/A */
286N/A public void CopyFrom(ToXMLStream xmlListener)
286N/A {
286N/A
286N/A m_writer = xmlListener.m_writer;
286N/A
286N/A
286N/A // m_outputStream = xmlListener.m_outputStream;
286N/A String encoding = xmlListener.getEncoding();
286N/A setEncoding(encoding);
286N/A
286N/A setOmitXMLDeclaration(xmlListener.getOmitXMLDeclaration());
286N/A
286N/A m_ispreserve = xmlListener.m_ispreserve;
286N/A m_preserves = xmlListener.m_preserves;
286N/A m_isprevtext = xmlListener.m_isprevtext;
286N/A m_doIndent = xmlListener.m_doIndent;
286N/A setIndentAmount(xmlListener.getIndentAmount());
286N/A m_startNewLine = xmlListener.m_startNewLine;
286N/A m_needToOutputDocTypeDecl = xmlListener.m_needToOutputDocTypeDecl;
286N/A setDoctypeSystem(xmlListener.getDoctypeSystem());
286N/A setDoctypePublic(xmlListener.getDoctypePublic());
286N/A setStandalone(xmlListener.getStandalone());
286N/A setMediaType(xmlListener.getMediaType());
286N/A m_maxCharacter = xmlListener.m_maxCharacter;
286N/A m_encodingInfo = xmlListener.m_encodingInfo;
286N/A m_spaceBeforeClose = xmlListener.m_spaceBeforeClose;
286N/A m_cdataStartCalled = xmlListener.m_cdataStartCalled;
286N/A
286N/A }
286N/A
286N/A /**
286N/A * Receive notification of the beginning of a document.
286N/A *
286N/A * @throws org.xml.sax.SAXException Any SAX exception, possibly
286N/A * wrapping another exception.
286N/A *
286N/A * @throws org.xml.sax.SAXException
286N/A */
286N/A public void startDocumentInternal() throws org.xml.sax.SAXException
286N/A {
286N/A
286N/A if (m_needToCallStartDocument)
286N/A {
286N/A super.startDocumentInternal();
286N/A m_needToCallStartDocument = false;
286N/A
286N/A if (m_inEntityRef)
286N/A return;
286N/A
286N/A m_needToOutputDocTypeDecl = true;
286N/A m_startNewLine = false;
286N/A /* The call to getXMLVersion() might emit an error message
286N/A * and we should emit this message regardless of if we are
286N/A * writing out an XML header or not.
286N/A */
286N/A if (getOmitXMLDeclaration() == false)
286N/A {
286N/A String encoding = Encodings.getMimeEncoding(getEncoding());
286N/A String version = getVersion();
286N/A if (version == null)
286N/A version = "1.0";
286N/A String standalone;
286N/A
286N/A if (m_standaloneWasSpecified)
286N/A {
286N/A standalone = " standalone=\"" + getStandalone() + "\"";
286N/A }
286N/A else
286N/A {
286N/A standalone = "";
286N/A }
286N/A
286N/A try
286N/A {
286N/A final java.io.Writer writer = m_writer;
286N/A writer.write("<?xml version=\"");
286N/A writer.write(version);
286N/A writer.write("\" encoding=\"");
286N/A writer.write(encoding);
286N/A writer.write('\"');
286N/A writer.write(standalone);
286N/A writer.write("?>");
293N/A if (m_doIndent) {
293N/A if (m_standaloneWasSpecified
293N/A || getDoctypePublic() != null
331N/A || getDoctypeSystem() != null
331N/A || m_isStandalone) {
293N/A // We almost never put a newline after the XML
293N/A // header because this XML could be used as
293N/A // an extenal general parsed entity
293N/A // and we don't know the context into which it
293N/A // will be used in the future. Only when
293N/A // standalone, or a doctype system or public is
293N/A // specified are we free to insert a new line
293N/A // after the header. Is it even worth bothering
293N/A // in these rare cases?
293N/A writer.write(m_lineSep, 0, m_lineSepLen);
293N/A }
293N/A }
286N/A }
286N/A catch(IOException e)
286N/A {
286N/A throw new SAXException(e);
286N/A }
286N/A
286N/A }
286N/A }
286N/A }
286N/A
286N/A /**
286N/A * Receive notification of the end of a document.
286N/A *
286N/A * @throws org.xml.sax.SAXException Any SAX exception, possibly
286N/A * wrapping another exception.
286N/A *
286N/A * @throws org.xml.sax.SAXException
286N/A */
286N/A public void endDocument() throws org.xml.sax.SAXException
286N/A {
286N/A flushPending();
286N/A if (m_doIndent && !m_isprevtext)
286N/A {
286N/A try
286N/A {
286N/A outputLineSep();
286N/A }
286N/A catch(IOException e)
286N/A {
286N/A throw new SAXException(e);
286N/A }
286N/A }
286N/A
286N/A flushWriter();
286N/A
286N/A if (m_tracer != null)
286N/A super.fireEndDoc();
286N/A }
286N/A
286N/A /**
286N/A * Starts a whitespace preserving section. All characters printed
286N/A * within a preserving section are printed without indentation and
286N/A * without consolidating multiple spaces. This is equivalent to
286N/A * the <tt>xml:space=&quot;preserve&quot;</tt> attribute. Only XML
286N/A * and HTML serializers need to support this method.
286N/A * <p>
286N/A * The contents of the whitespace preserving section will be delivered
286N/A * through the regular <tt>characters</tt> event.
286N/A *
286N/A * @throws org.xml.sax.SAXException
286N/A */
286N/A public void startPreserving() throws org.xml.sax.SAXException
286N/A {
286N/A
286N/A // Not sure this is really what we want. -sb
286N/A m_preserves.push(true);
286N/A
286N/A m_ispreserve = true;
286N/A }
286N/A
286N/A /**
286N/A * Ends a whitespace preserving section.
286N/A *
286N/A * @see #startPreserving
286N/A *
286N/A * @throws org.xml.sax.SAXException
286N/A */
286N/A public void endPreserving() throws org.xml.sax.SAXException
286N/A {
286N/A
286N/A // Not sure this is really what we want. -sb
286N/A m_ispreserve = m_preserves.isEmpty() ? false : m_preserves.pop();
286N/A }
286N/A
286N/A /**
286N/A * Receive notification of a processing instruction.
286N/A *
286N/A * @param target The processing instruction target.
286N/A * @param data The processing instruction data, or null if
286N/A * none was supplied.
286N/A * @throws org.xml.sax.SAXException Any SAX exception, possibly
286N/A * wrapping another exception.
286N/A *
286N/A * @throws org.xml.sax.SAXException
286N/A */
286N/A public void processingInstruction(String target, String data)
286N/A throws org.xml.sax.SAXException
286N/A {
286N/A if (m_inEntityRef)
286N/A return;
286N/A
286N/A flushPending();
286N/A
286N/A if (target.equals(Result.PI_DISABLE_OUTPUT_ESCAPING))
286N/A {
286N/A startNonEscaping();
286N/A }
286N/A else if (target.equals(Result.PI_ENABLE_OUTPUT_ESCAPING))
286N/A {
286N/A endNonEscaping();
286N/A }
286N/A else
286N/A {
286N/A try
286N/A {
286N/A if (m_elemContext.m_startTagOpen)
286N/A {
286N/A closeStartTag();
286N/A m_elemContext.m_startTagOpen = false;
286N/A }
286N/A else if (m_needToCallStartDocument)
286N/A startDocumentInternal();
286N/A
286N/A if (shouldIndent())
286N/A indent();
286N/A
286N/A final java.io.Writer writer = m_writer;
286N/A writer.write("<?");
286N/A writer.write(target);
286N/A
286N/A if (data.length() > 0
286N/A && !Character.isSpaceChar(data.charAt(0)))
286N/A writer.write(' ');
286N/A
286N/A int indexOfQLT = data.indexOf("?>");
286N/A
286N/A if (indexOfQLT >= 0)
286N/A {
286N/A
286N/A // See XSLT spec on error recovery of "?>" in PIs.
286N/A if (indexOfQLT > 0)
286N/A {
286N/A writer.write(data.substring(0, indexOfQLT));
286N/A }
286N/A
286N/A writer.write("? >"); // add space between.
286N/A
286N/A if ((indexOfQLT + 2) < data.length())
286N/A {
286N/A writer.write(data.substring(indexOfQLT + 2));
286N/A }
286N/A }
286N/A else
286N/A {
286N/A writer.write(data);
286N/A }
286N/A
286N/A writer.write('?');
286N/A writer.write('>');
286N/A
331N/A /**
331N/A * Before Xalan 1497, a newline char was printed out if not inside of an
358N/A * element. The whitespace is not significant is the output is standalone
331N/A */
331N/A if (m_elemContext.m_currentElemDepth <= 0 && m_isStandalone)
331N/A writer.write(m_lineSep, 0, m_lineSepLen);
331N/A
358N/A
293N/A /*
293N/A * Don't write out any indentation whitespace now,
293N/A * because there may be non-whitespace text after this.
293N/A *
293N/A * Simply mark that at this point if we do decide
293N/A * to indent that we should
293N/A * add a newline on the end of the current line before
293N/A * the indentation at the start of the next line.
293N/A */
286N/A m_startNewLine = true;
286N/A }
286N/A catch(IOException e)
286N/A {
286N/A throw new SAXException(e);
286N/A }
286N/A }
286N/A
286N/A if (m_tracer != null)
286N/A super.fireEscapingEvent(target, data);
286N/A }
286N/A
286N/A /**
286N/A * Receive notivication of a entityReference.
286N/A *
286N/A * @param name The name of the entity.
286N/A *
286N/A * @throws org.xml.sax.SAXException
286N/A */
286N/A public void entityReference(String name) throws org.xml.sax.SAXException
286N/A {
286N/A if (m_elemContext.m_startTagOpen)
286N/A {
286N/A closeStartTag();
286N/A m_elemContext.m_startTagOpen = false;
286N/A }
286N/A
286N/A try
286N/A {
286N/A if (shouldIndent())
286N/A indent();
286N/A
286N/A final java.io.Writer writer = m_writer;
286N/A writer.write('&');
286N/A writer.write(name);
286N/A writer.write(';');
286N/A }
286N/A catch(IOException e)
286N/A {
286N/A throw new SAXException(e);
286N/A }
286N/A
286N/A if (m_tracer != null)
286N/A super.fireEntityReference(name);
286N/A }
286N/A
286N/A /**
286N/A * This method is used to add an attribute to the currently open element.
286N/A * The caller has guaranted that this attribute is unique, which means that it
286N/A * not been seen before and will not be seen again.
286N/A *
286N/A * @param name the qualified name of the attribute
286N/A * @param value the value of the attribute which can contain only
286N/A * ASCII printable characters characters in the range 32 to 127 inclusive.
286N/A * @param flags the bit values of this integer give optimization information.
286N/A */
286N/A public void addUniqueAttribute(String name, String value, int flags)
286N/A throws SAXException
286N/A {
286N/A if (m_elemContext.m_startTagOpen)
286N/A {
286N/A
286N/A try
286N/A {
286N/A final String patchedName = patchName(name);
286N/A final java.io.Writer writer = m_writer;
286N/A if ((flags & NO_BAD_CHARS) > 0 && m_xmlcharInfo.onlyQuotAmpLtGt)
286N/A {
286N/A // "flags" has indicated that the characters
286N/A // '>' '<' '&' and '"' are not in the value and
286N/A // m_htmlcharInfo has recorded that there are no other
286N/A // entities in the range 32 to 127 so we write out the
286N/A // value directly
286N/A
286N/A writer.write(' ');
286N/A writer.write(patchedName);
286N/A writer.write("=\"");
286N/A writer.write(value);
286N/A writer.write('"');
286N/A }
286N/A else
286N/A {
286N/A writer.write(' ');
286N/A writer.write(patchedName);
286N/A writer.write("=\"");
286N/A writeAttrString(writer, value, this.getEncoding());
286N/A writer.write('"');
286N/A }
286N/A } catch (IOException e) {
286N/A throw new SAXException(e);
286N/A }
286N/A }
286N/A }
286N/A
286N/A /**
286N/A * Add an attribute to the current element.
286N/A * @param uri the URI associated with the element name
286N/A * @param localName local part of the attribute name
286N/A * @param rawName prefix:localName
286N/A * @param type
286N/A * @param value the value of the attribute
286N/A * @param xslAttribute true if this attribute is from an xsl:attribute,
286N/A * false if declared within the elements opening tag.
286N/A * @throws SAXException
286N/A */
286N/A public void addAttribute(
286N/A String uri,
286N/A String localName,
286N/A String rawName,
286N/A String type,
286N/A String value,
286N/A boolean xslAttribute)
286N/A throws SAXException
286N/A {
286N/A if (m_elemContext.m_startTagOpen)
286N/A {
286N/A boolean was_added = addAttributeAlways(uri, localName, rawName, type, value, xslAttribute);
286N/A
286N/A
286N/A /*
286N/A * We don't run this block of code if:
286N/A * 1. The attribute value was only replaced (was_added is false).
286N/A * 2. The attribute is from an xsl:attribute element (that is handled
286N/A * in the addAttributeAlways() call just above.
286N/A * 3. The name starts with "xmlns", i.e. it is a namespace declaration.
286N/A */
286N/A if (was_added && !xslAttribute && !rawName.startsWith("xmlns"))
286N/A {
286N/A String prefixUsed =
286N/A ensureAttributesNamespaceIsDeclared(
286N/A uri,
286N/A localName,
286N/A rawName);
286N/A if (prefixUsed != null
286N/A && rawName != null
286N/A && !rawName.startsWith(prefixUsed))
286N/A {
286N/A // use a different raw name, with the prefix used in the
286N/A // generated namespace declaration
286N/A rawName = prefixUsed + ":" + localName;
286N/A
286N/A }
286N/A }
286N/A addAttributeAlways(uri, localName, rawName, type, value, xslAttribute);
286N/A }
286N/A else
286N/A {
286N/A /*
286N/A * The startTag is closed, yet we are adding an attribute?
286N/A *
286N/A * Section: 7.1.3 Creating Attributes Adding an attribute to an
286N/A * element after a PI (for example) has been added to it is an
286N/A * error. The attributes can be ignored. The spec doesn't explicitly
286N/A * say this is disallowed, as it does for child elements, but it
286N/A * makes sense to have the same treatment.
286N/A *
286N/A * We choose to ignore the attribute which is added too late.
286N/A */
286N/A // Generate a warning of the ignored attributes
286N/A
286N/A // Create the warning message
286N/A String msg = Utils.messages.createMessage(
286N/A MsgKey.ER_ILLEGAL_ATTRIBUTE_POSITION,new Object[]{ localName });
286N/A
286N/A try {
286N/A // Prepare to issue the warning message
286N/A Transformer tran = super.getTransformer();
286N/A ErrorListener errHandler = tran.getErrorListener();
286N/A
286N/A
286N/A // Issue the warning message
286N/A if (null != errHandler && m_sourceLocator != null)
286N/A errHandler.warning(new TransformerException(msg, m_sourceLocator));
286N/A else
286N/A System.out.println(msg);
286N/A }
286N/A catch (Exception e){}
286N/A }
286N/A }
286N/A
286N/A /**
286N/A * @see ExtendedContentHandler#endElement(String)
286N/A */
286N/A public void endElement(String elemName) throws SAXException
286N/A {
286N/A endElement(null, null, elemName);
286N/A }
286N/A
286N/A /**
286N/A * This method is used to notify the serializer of a namespace mapping (or node)
286N/A * that applies to the current element whose startElement() call has already been seen.
286N/A * The official SAX startPrefixMapping(prefix,uri) is to define a mapping for a child
286N/A * element that is soon to be seen with a startElement() call. The official SAX call
286N/A * does not apply to the current element, hence the reason for this method.
286N/A */
286N/A public void namespaceAfterStartElement(
286N/A final String prefix,
286N/A final String uri)
286N/A throws SAXException
286N/A {
286N/A
286N/A // hack for XSLTC with finding URI for default namespace
286N/A if (m_elemContext.m_elementURI == null)
286N/A {
286N/A String prefix1 = getPrefixPart(m_elemContext.m_elementName);
286N/A if (prefix1 == null && EMPTYSTRING.equals(prefix))
286N/A {
286N/A // the elements URI is not known yet, and it
286N/A // doesn't have a prefix, and we are currently
286N/A // setting the uri for prefix "", so we have
286N/A // the uri for the element... lets remember it
286N/A m_elemContext.m_elementURI = uri;
286N/A }
286N/A }
286N/A startPrefixMapping(prefix,uri,false);
286N/A return;
286N/A
286N/A }
286N/A
286N/A /**
286N/A * From XSLTC
286N/A * Declare a prefix to point to a namespace URI. Inform SAX handler
286N/A * if this is a new prefix mapping.
286N/A */
286N/A protected boolean pushNamespace(String prefix, String uri)
286N/A {
286N/A try
286N/A {
286N/A if (m_prefixMap.pushNamespace(
286N/A prefix, uri, m_elemContext.m_currentElemDepth))
286N/A {
286N/A startPrefixMapping(prefix, uri);
286N/A return true;
286N/A }
286N/A }
286N/A catch (SAXException e)
286N/A {
286N/A // falls through
286N/A }
286N/A return false;
286N/A }
286N/A /**
286N/A * Try's to reset the super class and reset this class for
286N/A * re-use, so that you don't need to create a new serializer
286N/A * (mostly for performance reasons).
286N/A *
286N/A * @return true if the class was successfuly reset.
286N/A */
286N/A public boolean reset()
286N/A {
286N/A boolean wasReset = false;
286N/A if (super.reset())
286N/A {
286N/A resetToXMLStream();
286N/A wasReset = true;
286N/A }
286N/A return wasReset;
286N/A }
286N/A
286N/A /**
286N/A * Reset all of the fields owned by ToStream class
286N/A *
286N/A */
286N/A private void resetToXMLStream()
286N/A {
286N/A this.m_cdataTagOpen = false;
286N/A
286N/A }
286N/A
286N/A /**
286N/A * This method checks for the XML version of output document.
286N/A * If XML version of output document is not specified, then output
286N/A * document is of version XML 1.0.
286N/A * If XML version of output doucment is specified, but it is not either
286N/A * XML 1.0 or XML 1.1, a warning message is generated, the XML Version of
286N/A * output document is set to XML 1.0 and processing continues.
286N/A * @return string (XML version)
286N/A */
286N/A private String getXMLVersion()
286N/A {
286N/A String xmlVersion = getVersion();
286N/A if(xmlVersion == null || xmlVersion.equals(XMLVERSION10))
286N/A {
286N/A xmlVersion = XMLVERSION10;
286N/A }
286N/A else if(xmlVersion.equals(XMLVERSION11))
286N/A {
286N/A xmlVersion = XMLVERSION11;
286N/A }
286N/A else
286N/A {
286N/A String msg = Utils.messages.createMessage(
286N/A MsgKey.ER_XML_VERSION_NOT_SUPPORTED,new Object[]{ xmlVersion });
286N/A try
286N/A {
286N/A // Prepare to issue the warning message
286N/A Transformer tran = super.getTransformer();
286N/A ErrorListener errHandler = tran.getErrorListener();
286N/A // Issue the warning message
286N/A if (null != errHandler && m_sourceLocator != null)
286N/A errHandler.warning(new TransformerException(msg, m_sourceLocator));
286N/A else
286N/A System.out.println(msg);
286N/A }
286N/A catch (Exception e){}
286N/A xmlVersion = XMLVERSION10;
286N/A }
286N/A return xmlVersion;
286N/A }
286N/A}