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