changeset 42805:857b5e6eef37

8087303: LSSerializer pretty print does not work anymore 8114834: LSSerializerImpl always serializes an entity reference node to" &entityName;" even if "entities" property is false Reviewed-by: joehw, clanger
author fyuan
date Mon, 19 Dec 2016 11:13:32 +0800
parents 0bdf34ac888c
children 35843e3d5ef1
files jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/AbstractTranslet.java jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerImpl.java jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/SerializerBase.java jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/ToHTMLStream.java jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/ToStream.java jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/ToXMLStream.java jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/dom3/DOM3TreeWalker.java jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/output_html.properties jaxp/test/javax/xml/jaxp/functional/javax/xml/transform/xmlfiles/out/saxtf001GF.out jaxp/test/javax/xml/jaxp/functional/javax/xml/transform/xmlfiles/out/saxtf002GF.out jaxp/test/javax/xml/jaxp/functional/javax/xml/transform/xmlfiles/out/saxtf003GF.out jaxp/test/javax/xml/jaxp/functional/javax/xml/transform/xmlfiles/out/saxtf005GF.out jaxp/test/javax/xml/jaxp/functional/javax/xml/transform/xmlfiles/out/saxtf006GF.out jaxp/test/javax/xml/jaxp/functional/javax/xml/transform/xmlfiles/out/saxtf009GF.out jaxp/test/javax/xml/jaxp/functional/test/astro/AstroTest.java jaxp/test/javax/xml/jaxp/functional/test/astro/xmlfiles/gold/query1.out jaxp/test/javax/xml/jaxp/functional/test/astro/xmlfiles/gold/query2.out jaxp/test/javax/xml/jaxp/functional/test/astro/xmlfiles/gold/query3.out jaxp/test/javax/xml/jaxp/functional/test/astro/xmlfiles/gold/query4.out jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/PrettyPrintTest.java jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/htmltest1.out jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/htmltest1.xml jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/htmltest2.out jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/htmltest2.xml jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/htmltest3.out jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/htmltest3.xml jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/htmltest4.out jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/htmltest4.xml jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/htmltest5.out jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/htmltest5.xml jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/htmltest6.out jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/htmltest6.xml jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/nodetest1.out jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/nodetest1.txt jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/nodetest2.out jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest1.out jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest1.xml jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest2.out jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest2.xml jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest3.out jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest3.xml jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest4.out jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest4.xml jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest5.out jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest5.xml jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest6.out jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest6.xml jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest7.out jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest7.xml jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest8.out jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest8.xml jaxp/test/javax/xml/jaxp/unittest/dom/ls/LSSerializerTest.java
diffstat 52 files changed, 1379 insertions(+), 443 deletions(-) [+]
line wrap: on
line diff
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/AbstractTranslet.java	Fri Dec 16 08:18:05 2016 +0000
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/AbstractTranslet.java	Mon Dec 19 11:13:32 2016 +0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved.
  */
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
@@ -17,9 +17,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-/*
- * $Id: AbstractTranslet.java,v 1.6 2006/06/19 19:49:03 spericas Exp $
- */
 
 package com.sun.org.apache.xalan.internal.xsltc.runtime;
 
@@ -685,7 +682,8 @@
                     handler.setVersion(_version);
                 }
                 handler.setIndent(_indent);
-                handler.setIndentAmount(_indentamount);
+                if (_indentamount >= 0)
+                    handler.setIndentAmount(_indentamount);
                 if (_doctypeSystem != null) {
                     handler.setDoctype(_doctypeSystem, _doctypePublic);
                 }
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerImpl.java	Fri Dec 16 08:18:05 2016 +0000
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerImpl.java	Mon Dec 19 11:13:32 2016 +0800
@@ -17,9 +17,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-/*
- * $Id: TransformerImpl.java,v 1.10 2007/06/13 01:57:09 joehw Exp $
- */
 
 package com.sun.org.apache.xalan.internal.xsltc.trax;
 
@@ -160,7 +157,7 @@
     /**
      * Number of indent spaces to add when indentation is on.
      */
-    private int _indentNumber;
+    private int _indentNumber = -1;
 
     /**
      * A reference to the transformer factory that this templates
@@ -1462,7 +1459,7 @@
         _uriResolver = null;
         _dom = null;
         _parameters = null;
-        _indentNumber = 0;
+        _indentNumber = -1;
         setOutputProperties (null);
         _tohFactory = null;
         _ostream = null;
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/SerializerBase.java	Fri Dec 16 08:18:05 2016 +0000
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/SerializerBase.java	Mon Dec 19 11:13:32 2016 +0800
@@ -93,9 +93,11 @@
     protected AttributesImplSerializer m_attributes = new AttributesImplSerializer();
 
     /**
-     * Tells if we're in an EntityRef event.
+     * Tells if we're in an EntityRef event, true if it's greater than 0. Use
+     * integer type to handle nested entity reference, increase m_inEntityRef in
+     * startEntity, decrease m_inEntityRef in endEntity.
      */
-    protected boolean m_inEntityRef = false;
+    protected int m_inEntityRef = 0;
 
     /** This flag is set while receiving events from the external DTD */
     protected boolean m_inExternalDTD = false;
@@ -144,7 +146,7 @@
     /**
      * Amount to indent.
      */
-    protected int m_indentAmount = 0;
+    protected int m_indentAmount = 4;
 
     /**
      * Tells the XML version, for writing out to the XML decl.
@@ -444,13 +446,24 @@
     public void endEntity(String name) throws org.xml.sax.SAXException {
         if (name.equals("[dtd]"))
             m_inExternalDTD = false;
-        m_inEntityRef = false;
+
+        if (!m_inExternalDTD)
+            m_inEntityRef--;
 
         if (m_tracer != null)
             this.fireEndEntity(name);
     }
 
     /**
+     * This method checks if current node is in entity reference.
+     *
+     * @return True if current node is in entity reference.
+     */
+    protected boolean isInEntityRef() {
+        return m_inEntityRef > 0;
+    }
+
+    /**
      * Flush and close the underlying java.io.Writer. This method applies to
      * ToStream serializers, not ToSAXHandler serializers.
      * @see ToStream
@@ -1139,8 +1152,8 @@
         this.m_doctypePublic = null;
         this.m_doctypeSystem = null;
         this.m_doIndent = false;
-        this.m_indentAmount = 0;
-        this.m_inEntityRef = false;
+        this.m_indentAmount = 4;
+        this.m_inEntityRef = 0;
         this.m_inExternalDTD = false;
         this.m_mediatype = null;
         this.m_needToCallStartDocument = true;
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/ToHTMLStream.java	Fri Dec 16 08:18:05 2016 +0000
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/ToHTMLStream.java	Mon Dec 19 11:13:32 2016 +0800
@@ -1,17 +1,15 @@
 /*
- * reserved comment block
- * DO NOT REMOVE OR ALTER!
+ * 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
+ * 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
+ *      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,
@@ -19,22 +17,19 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-/*
- * $Id: ToHTMLStream.java,v 1.2.4.1 2005/09/15 08:15:26 suresh_emailid Exp $
- */
+
 package com.sun.org.apache.xml.internal.serializer;
 
 import java.io.IOException;
-import java.io.OutputStream;
-import java.io.UnsupportedEncodingException;
 import java.util.Properties;
 
 import javax.xml.transform.Result;
 
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
 import com.sun.org.apache.xml.internal.serializer.utils.MsgKey;
 import com.sun.org.apache.xml.internal.serializer.utils.Utils;
-import org.xml.sax.Attributes;
-import org.xml.sax.SAXException;
 
 /**
  * This serializer takes a series of SAX or
@@ -52,9 +47,8 @@
     /** This flag is set while receiving events from the DTD */
     protected boolean m_inDTD = false;
 
-    /** True if the current element is a block element.  (seems like
-     *  this needs to be a stack. -sb). */
-    private boolean m_inBlockElem = false;
+    /** True if the previous element is a block element. */
+    private boolean m_isprevblock = false;
 
     /**
      * Map that tells which XML characters should have special treatment, and it
@@ -723,7 +717,7 @@
      */
     public final void endDocument() throws org.xml.sax.SAXException
     {
-
+        flushCharactersBuffer();
         flushPending();
         if (m_doIndent && !m_isprevtext)
         {
@@ -743,26 +737,48 @@
     }
 
     /**
-     *  Receive notification of the beginning of an element.
+     * If the previous is an inline element, won't insert a new line before the
+     * text.
      *
+     */
+    protected boolean shouldIndentForText() {
+        return super.shouldIndentForText() && m_isprevblock;
+    }
+
+    /**
+     * Only check m_doIndent, disregard m_ispreserveSpace.
      *
-     *  @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
+     * @return True if the content should be formatted.
+     */
+    protected boolean shouldFormatOutput() {
+        return m_doIndent;
+    }
+
+    /**
+     * 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
+        throws SAXException
     {
-
+        // will add extra one if having namespace but no matter
+        m_childNodeNum++;
+        flushCharactersBuffer();
         ElemContext elemContext = m_elemContext;
 
         // clean up any pending things first
@@ -800,22 +816,18 @@
             // deal with indentation issues first
             if (m_doIndent)
             {
-
                 boolean isBlockElement = (elemFlags & ElemDesc.BLOCK) != 0;
-                if (m_ispreserve)
-                    m_ispreserve = false;
-                else if (
-                    (null != elemContext.m_elementName)
-                    && (!m_inBlockElem
-                        || isBlockElement) /* && !isWhiteSpaceSensitive */
-                    )
+                if ((elemContext.m_elementName != null)
+                        // If this element is a block element,
+                        // or if this is not a block element, then if the
+                        // previous is neither a text nor an inline
+                        && (isBlockElement || (!(m_isprevtext || !m_isprevblock))))
                 {
                     m_startNewLine = true;
 
                     indent();
-
                 }
-                m_inBlockElem = !isBlockElement;
+                m_isprevblock = isBlockElement;
             }
 
             // save any attributes for later processing
@@ -827,7 +839,8 @@
             writer.write('<');
             writer.write(name);
 
-
+            m_childNodeNumStack.push(m_childNodeNum);
+            m_childNodeNum = 0;
 
             if (m_tracer != null)
                 firePseudoAttributes();
@@ -850,6 +863,15 @@
                 m_elemContext = elemContext;
                 elemContext.m_elementDesc = elemDesc;
                 elemContext.m_isRaw = (elemFlags & ElemDesc.RAW) != 0;
+
+                // set m_startNewLine for the next element
+                if (m_doIndent) {
+                    // elemFlags is equivalent to m_elemContext.m_elementDesc.getFlags(),
+                    // in this branch m_elemContext.m_elementName is not null
+                    boolean isBlockElement = (elemFlags & ElemDesc.BLOCK) != 0;
+                    if (isBlockElement)
+                        m_startNewLine = true;
+                }
             }
 
 
@@ -893,6 +915,7 @@
         final String name)
         throws org.xml.sax.SAXException
     {
+        flushCharactersBuffer();
         // deal with any pending issues
         if (m_cdataTagOpen)
             closeCDATA();
@@ -919,18 +942,18 @@
                 final boolean isBlockElement = (elemFlags&ElemDesc.BLOCK) != 0;
                 boolean shouldIndent = false;
 
-                if (m_ispreserve)
-                {
-                    m_ispreserve = false;
-                }
-                else if (m_doIndent && (!m_inBlockElem || isBlockElement))
+                // If this element is a block element,
+                // or if this is not a block element, then if the previous is
+                // neither a text nor an inline
+                if (isBlockElement || (!(m_isprevtext || !m_isprevblock)))
                 {
                     m_startNewLine = true;
                     shouldIndent = true;
                 }
-                if (!elemContext.m_startTagOpen && shouldIndent)
+                if (!elemContext.m_startTagOpen && shouldIndent && (m_childNodeNum > 1 || !m_isprevtext))
                     indent(elemContext.m_currentElemDepth - 1);
-                m_inBlockElem = !isBlockElement;
+
+                m_isprevblock = isBlockElement;
             }
 
             final java.io.Writer writer = m_writer;
@@ -974,6 +997,7 @@
                 }
             }
 
+            m_childNodeNum = m_childNodeNumStack.pop();
             // clean up because the element has ended
             if ((elemFlags & ElemDesc.WHITESPACESENSITIVE) != 0)
                 m_ispreserve = true;
@@ -1511,7 +1535,7 @@
                 // writer.write("<![CDATA[");
                 // writer.write(chars, start, length);
                 writeNormalizedChars(chars, start, length, false, m_lineSepUse);
-
+                m_isprevtext = true;
                 // writer.write("]]>");
 
                 // time to generate characters event
@@ -1566,7 +1590,6 @@
     public final void cdata(char ch[], int start, int length)
         throws org.xml.sax.SAXException
     {
-
         if ((null != m_elemContext.m_elementName)
             && (m_elemContext.m_elementName.equalsIgnoreCase("SCRIPT")
                 || m_elemContext.m_elementName.equalsIgnoreCase("STYLE")))
@@ -1617,7 +1640,8 @@
     public void processingInstruction(String target, String data)
         throws org.xml.sax.SAXException
     {
-
+        m_childNodeNum++;
+        flushCharactersBuffer();
         // Process any pending starDocument and startElement first.
         flushPending();
 
@@ -1945,10 +1969,8 @@
 
     private void initToHTMLStream()
     {
-//        m_elementDesc = null;
-        m_inBlockElem = false;
+        m_isprevblock = false;
         m_inDTD = false;
-//        m_isRawStack.clear();
         m_omitMetaTag = false;
         m_specialEscapeURLs = true;
     }
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/ToStream.java	Fri Dec 16 08:18:05 2016 +0000
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/ToStream.java	Mon Dec 19 11:13:32 2016 +0800
@@ -29,12 +29,16 @@
 import java.io.OutputStreamWriter;
 import java.io.UnsupportedEncodingException;
 import java.io.Writer;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Deque;
+import java.util.EmptyStackException;
 import java.util.Enumeration;
-import java.util.Iterator;
 import java.util.Properties;
+import java.util.Queue;
 import java.util.Set;
 import java.util.StringTokenizer;
-import java.util.ArrayList;
 import javax.xml.transform.ErrorListener;
 import javax.xml.transform.OutputKeys;
 import javax.xml.transform.Transformer;
@@ -89,6 +93,29 @@
     Object m_charToByteConverter = null;
 
     /**
+     * Used to buffer the text nodes and the entity reference nodes if
+     * indentation is on.
+     */
+    protected CharacterBuffer m_charactersBuffer = new CharacterBuffer();
+
+    /**
+     * Used to decide if a text node is pretty-printed with indentation.
+     * If m_childNodeNum > 1, the text node will be indented.
+     *
+     */
+    protected Deque<Integer> m_childNodeNumStack = new ArrayDeque<>();
+
+    protected int m_childNodeNum = 0;
+
+    /**
+     * Used to handle xml:space attribute
+     *
+     */
+    protected BoolStack m_preserveSpaces = new BoolStack();
+
+    protected boolean m_ispreserveSpace = false;
+
+    /**
      * Stack to keep track of whether or not we need to
      * preserve whitespace.
      *
@@ -767,12 +794,10 @@
 
         if (m_startNewLine)
             outputLineSep();
-        /* For m_indentAmount > 0 this extra test might be slower
-         * but Xalan's default value is 0, so this extra test
-         * will run faster in that situation.
+        /*
+         * Default value is 4, so printSpace directly.
          */
-        if (m_indentAmount > 0)
-            printSpace(depth * m_indentAmount);
+        printSpace(depth * m_indentAmount);
 
     }
 
@@ -1234,7 +1259,6 @@
     protected void cdata(char ch[], int start, final int length)
         throws org.xml.sax.SAXException
     {
-
         try
         {
             final int old_start = start;
@@ -1323,7 +1347,7 @@
         throws org.xml.sax.SAXException
     {
 
-        if (m_inEntityRef)
+        if (isInEntityRef())
             return;
         try
         {
@@ -1378,9 +1402,11 @@
         // characters to read from array is 0.
         // Section 7.6.1 of XSLT 1.0 (http://www.w3.org/TR/xslt#value-of) suggest no text node
         // is created if string is empty.
-        if (length == 0 || (m_inEntityRef && !m_expandDTDEntities))
+        if (length == 0 || (isInEntityRef()))
             return;
-        if (m_elemContext.m_startTagOpen)
+
+        final boolean shouldFormat = shouldFormatOutput();
+        if (m_elemContext.m_startTagOpen && !shouldFormat)
         {
             closeStartTag();
             m_elemContext.m_startTagOpen = false;
@@ -1407,7 +1433,7 @@
         if (m_disableOutputEscapingStates.peekOrFalse() || (!m_escaping))
         {
             charactersRaw(chars, start, length);
-
+            m_isprevtext = true;
             // time to fire off characters generation event
             if (m_tracer != null)
                 super.fireCharEvent(chars, start, length);
@@ -1415,13 +1441,41 @@
             return;
         }
 
-        if (m_elemContext.m_startTagOpen)
+        if (m_elemContext.m_startTagOpen && !shouldFormat)
         {
             closeStartTag();
             m_elemContext.m_startTagOpen = false;
         }
 
-
+        if (shouldFormat) {
+            m_charactersBuffer.addText(chars, start, length);
+        } else {
+            outputCharacters(chars, start, length);
+        }
+
+        // time to fire off characters generation event
+        if (m_tracer != null)
+            super.fireCharEvent(chars, start, length);
+    }
+
+
+    /**
+     * This method checks if the content in current element should be formatted.
+     *
+     * @return True if the content should be formatted.
+     */
+    protected boolean shouldFormatOutput() {
+        return !m_ispreserveSpace && m_doIndent;
+    }
+
+    /**
+     * Write out the characters.
+     *
+     * @param chars The characters of the text.
+     * @param start The start position in the char array.
+     * @param length The number of characters from the char array.
+     */
+    private void outputCharacters(final char chars[], final int start, final int length) throws SAXException {
         try
         {
             int i;
@@ -1459,8 +1513,8 @@
                 m_ispreserve = true;
 
 
-//            int lengthClean;    // number of clean characters in a row
-//            final boolean[] isAsciiClean = m_charInfo.getASCIIClean();
+//          int lengthClean;    // number of clean characters in a row
+//          final boolean[] isAsciiClean = m_charInfo.getASCIIClean();
 
             final boolean isXML10 = XMLVERSION10.equals(getVersion());
             // we've skipped the leading whitespace, now deal with the rest
@@ -1514,11 +1568,54 @@
         {
             throw new SAXException(e);
         }
-
-        // time to fire off characters generation event
-        if (m_tracer != null)
-            super.fireCharEvent(chars, start, length);
     }
+
+    /**
+     * Used to flush the buffered characters when indentation is on, this method
+     * will be called when the next node is traversed.
+     *
+     */
+    final protected void flushCharactersBuffer() throws SAXException {
+        try {
+            if (shouldFormatOutput() && m_charactersBuffer.hasContent()) {
+                if (m_elemContext.m_startTagOpen) {
+                    closeStartTag();
+                    m_elemContext.m_startTagOpen = false;
+                }
+
+                if (m_elemContext.m_isCdataSection) {
+                    /*
+                     * due to cdata-section-elements atribute, we need this as
+                     * cdata
+                     */
+                    char[] chars = m_charactersBuffer.toChars();
+                    cdata(chars, 0, chars.length);
+                    return;
+                }
+
+                m_childNodeNum++;
+                if (shouldIndentForText()) {
+                    indent();
+                    m_startNewLine = true;
+                }
+                m_charactersBuffer.flush();
+            }
+        } catch (IOException e) {
+            throw new SAXException(e);
+        } finally {
+            m_charactersBuffer.clear();
+        }
+    }
+
+    /**
+     * True if should indent in flushCharactersBuffer method.
+     * This method may be overridden in sub-class.
+     *
+     */
+    protected boolean shouldIndentForText() {
+        return (shouldIndent() && m_childNodeNum > 1);
+    }
+
     /**
      * This method checks if a given character is between C0 or C1 range
      * of Control characters.
@@ -1610,7 +1707,7 @@
      */
     public void characters(String s) throws org.xml.sax.SAXException
     {
-        if (m_inEntityRef && !m_expandDTDEntities)
+        if (isInEntityRef())
             return;
         final int length = s.length();
         if (length > m_charsBuff.length)
@@ -1758,9 +1855,12 @@
         Attributes atts)
         throws org.xml.sax.SAXException
     {
-        if (m_inEntityRef)
+        if (isInEntityRef())
             return;
 
+        m_childNodeNum++;
+        flushCharactersBuffer();
+
         if (m_needToCallStartDocument)
         {
             startDocumentInternal();
@@ -1812,6 +1912,12 @@
         if (atts != null)
             addAttributes(atts);
 
+        m_ispreserveSpace = m_preserveSpaces.peekOrFalse();
+        m_preserveSpaces.push(m_ispreserveSpace);
+
+        m_childNodeNumStack.push(m_childNodeNum);
+        m_childNodeNum = 0;
+
         m_elemContext = m_elemContext.push(namespaceURI,localName,name);
         m_isprevtext = false;
 
@@ -2019,9 +2125,10 @@
         throws org.xml.sax.SAXException
     {
 
-        if (m_inEntityRef)
+        if (isInEntityRef())
             return;
 
+        flushCharactersBuffer();
         // namespaces declared at the current depth are no longer valid
         // so get rid of them
         m_prefixMap.popNamespaces(m_elemContext.m_currentElemDepth, null);
@@ -2055,7 +2162,7 @@
                 if (m_cdataTagOpen)
                     closeCDATA();
 
-                if (shouldIndent())
+                if (shouldIndent() && (m_childNodeNum > 1 || !m_isprevtext))
                     indent(m_elemContext.m_currentElemDepth - 1);
                 writer.write('<');
                 writer.write('/');
@@ -2073,6 +2180,9 @@
             m_ispreserve = m_preserves.isEmpty() ? false : m_preserves.pop();
         }
 
+        m_ispreserveSpace = m_preserveSpaces.popAndTop();
+        m_childNodeNum = m_childNodeNumStack.pop();
+
         m_isprevtext = false;
 
         // fire off the end element event
@@ -2208,8 +2318,10 @@
     {
 
         int start_old = start;
-        if (m_inEntityRef)
+        if (isInEntityRef())
             return;
+        m_childNodeNum++;
+        flushCharactersBuffer();
         if (m_elemContext.m_startTagOpen)
         {
             closeStartTag();
@@ -2389,6 +2501,9 @@
      */
     public void startCDATA() throws org.xml.sax.SAXException
     {
+        m_childNodeNum++;
+        flushCharactersBuffer();
+
         m_cdataStartCalled = true;
     }
 
@@ -2412,17 +2527,30 @@
         if (name.equals("[dtd]"))
             m_inExternalDTD = true;
 
-        if (!m_expandDTDEntities && !m_inExternalDTD) {
-            /* Only leave the entity as-is if
-             * we've been told not to expand them
-             * and this is not the magic [dtd] name.
-             */
-            startNonEscaping();
-            characters("&" + name + ';');
-            endNonEscaping();
+        // if this is not the magic [dtd] name
+        if (!m_inExternalDTD) {
+            // if it's not in nested entity reference
+            if (!isInEntityRef()) {
+                if (shouldFormatOutput()) {
+                    m_charactersBuffer.addEntityReference(name);
+                } else {
+                    outputEntityReference(name);
+                }
+            }
+            m_inEntityRef++;
         }
-
-        m_inEntityRef = true;
+    }
+
+    /**
+     * Write out the entity reference with the form as "&amp;entityName;".
+     *
+     * @param name The name of the entity.
+     */
+    private void outputEntityReference(String name) throws SAXException {
+        startNonEscaping();
+        characters("&" + name + ';');
+        endNonEscaping();
+        m_isprevtext = true;
     }
 
     /**
@@ -2523,7 +2651,7 @@
      */
     protected boolean shouldIndent()
     {
-        return m_doIndent && (!m_ispreserve && !m_isprevtext) && (m_elemContext.m_currentElemDepth > 0 || m_isStandalone);
+        return shouldFormatOutput() && (m_elemContext.m_currentElemDepth > 0 || m_isStandalone);
     }
 
     /**
@@ -2815,10 +2943,37 @@
         String value,
         boolean xslAttribute)
     {
+        if (m_charactersBuffer.isAnyCharactersBuffered()) {
+            /*
+             * If stylesheet includes xsl:copy-of an attribute node, XSLTC will
+             * fire an addAttribute event. When a text node is handling in
+             * ToStream, addAttribute has no effect. But closeStartTag call is
+             * delayed to flushCharactersBuffer() method if the text node is
+             * buffered, so here we ignore the attribute to avoid corrupting the
+             * start tag content.
+             *
+             */
+            return m_attributes.getIndex(rawName) < 0;
+        } else {
+            return doAddAttributeAlways(uri, localName, rawName, type, value, xslAttribute);
+        }
+    }
+
+    /**
+     * Does really add the attribute to the set of attributes.
+     */
+    private boolean doAddAttributeAlways(
+        String uri,
+        String localName,
+        String rawName,
+        String type,
+        String value,
+        boolean xslAttribute)
+    {
         boolean was_added;
         int index;
         //if (uri == null || localName == null || uri.length() == 0)
-            index = m_attributes.getIndex(rawName);
+        index = m_attributes.getIndex(rawName);
         // Don't use 'localName' as it gives incorrect value, rely only on 'rawName'
         /*else {
             index = m_attributes.getIndex(uri, localName);
@@ -2923,12 +3078,26 @@
                     e.printStackTrace();
                 }
             }
+
             m_attributes.addAttribute(uri, localName, rawName, type, value);
             was_added = true;
             if (m_tracer != null){
                 firePseudoAttributes();
             }
         }
+
+        if (rawName.equals("xml:space")) {
+            if (value.equals("preserve")) {
+                m_ispreserveSpace = true;
+                if (m_preserveSpaces.size() > 0)
+                    m_preserveSpaces.setTop(m_ispreserveSpace);
+            } else if (value.equals("default")) {
+                m_ispreserveSpace = false;
+                if (m_preserveSpaces.size() > 0)
+                    m_preserveSpaces.setTop(m_ispreserveSpace);
+            }
+        }
+
         return was_added;
     }
 
@@ -3059,10 +3228,14 @@
          // this.m_format = null;
          this.m_inDoctype = false;
          this.m_ispreserve = false;
-         this.m_ispreserve = false;
+         this.m_preserves.clear();
+         this.m_ispreserveSpace = false;
+         this.m_preserveSpaces.clear();
+         this.m_childNodeNum = 0;
+         this.m_childNodeNumStack.clear();
+         this.m_charactersBuffer.clear();
          this.m_isprevtext = false;
          this.m_isUTF8 = false; //  ?? used anywhere ??
-         this.m_preserves.clear();
          this.m_shouldFlush = true;
          this.m_spaceBeforeClose = false;
          this.m_startNewLine = false;
@@ -3238,6 +3411,129 @@
         }
     }
 
+    /**
+     * This inner class is used to buffer the text nodes and the entity
+     * reference nodes if indentation is on. There is only one CharacterBuffer
+     * instance in ToStream, it contains a queue of GenericCharacters,
+     * GenericCharacters can be a text node or an entity reference node. The
+     * text nodes and entity reference nodes are joined together and then are
+     * flushed.
+     */
+    private class CharacterBuffer {
+        /**
+         * GenericCharacters is immutable.
+         */
+        private abstract class GenericCharacters {
+            /**
+             * @return True if having any character other than whitespace or
+             *         line feed.
+             */
+            abstract boolean hasContent();
+
+            abstract void flush() throws SAXException;
+
+            /**
+             * Converts this GenericCharacters to a new character array.
+             */
+            abstract char[] toChars();
+        }
+
+        private Queue<GenericCharacters> bufferedCharacters = new ArrayDeque<>();
+
+        /**
+         * Append a text node to the buffer.
+         */
+        public void addText(final char chars[], final int start, final int length) {
+            bufferedCharacters.add(new GenericCharacters() {
+                char[] text;
+
+                {
+                    text = Arrays.copyOfRange(chars, start, start + length);
+                }
+
+                boolean hasContent() {
+                    for (int i = 0; i < text.length; i++) {
+                        if (!isWhiteSpace(text[i])) {
+                            return true;
+                        }
+                    }
+                    return false;
+                }
+
+                void flush() throws SAXException {
+                    outputCharacters(text, 0, text.length);
+                }
+
+                char[] toChars() {
+                    return text;
+                }
+
+                boolean isWhiteSpace(char ch) {
+                    return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r';
+                }
+
+            });
+        }
+
+        /**
+         * Append an entity reference to the buffer.
+         */
+        public void addEntityReference(String entityName) {
+            bufferedCharacters.add(new GenericCharacters() {
+                boolean hasContent() {
+                    return true;
+                }
+
+                void flush() throws SAXException {
+                    outputEntityReference(entityName);
+                }
+
+                char[] toChars() {
+                    return ("&" + entityName + ";").toCharArray();
+                }
+            });
+        }
+
+        /**
+         * @return True if any GenericCharacters is already buffered.
+         */
+        public boolean isAnyCharactersBuffered() {
+            return !bufferedCharacters.isEmpty();
+        }
+
+        /**
+         * @return True if any buffered GenericCharacters has content.
+         */
+        public boolean hasContent() {
+            return bufferedCharacters.stream().anyMatch(GenericCharacters::hasContent);
+        }
+
+        /**
+         * Flush all buffered GenericCharacters.
+         */
+        public void flush() throws SAXException {
+            GenericCharacters element;
+            while ((element = bufferedCharacters.poll()) != null)
+                element.flush();
+        }
+
+        /**
+         * Converts all buffered GenericCharacters to a new character array.
+         */
+        public char[] toChars() {
+            return bufferedCharacters.stream().map(GenericCharacters::toChars)
+                    .collect(StringBuilder::new, StringBuilder::append, StringBuilder::append).toString()
+                    .toCharArray();
+        }
+
+        /**
+         * Clear the buffer.
+         */
+        public void clear() {
+            bufferedCharacters.clear();
+        }
+    }
+
     // Implement DTDHandler
     /**
      * If this method is called, the serializer is used as a
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/ToXMLStream.java	Fri Dec 16 08:18:05 2016 +0000
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/ToXMLStream.java	Mon Dec 19 11:13:32 2016 +0800
@@ -1,15 +1,15 @@
 /*
- * reserved comment block
- * DO NOT REMOVE OR ALTER!
+ * Copyright (c) 2014, 2016 Oracle and/or its affiliates. All rights reserved.
  */
 /*
- * Copyright 2001-2004 The Apache Software Foundation.
+ * 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
  *
- * Licensed 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
+ *      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,
@@ -17,9 +17,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-/*
- * $Id: ToXMLStream.java,v 1.2.4.2 2005/09/15 12:01:25 suresh_emailid Exp $
- */
+
  package com.sun.org.apache.xml.internal.serializer;
 
 import java.io.IOException;
@@ -92,6 +90,12 @@
 
         m_ispreserve = xmlListener.m_ispreserve;
         m_preserves = xmlListener.m_preserves;
+        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());
@@ -124,7 +128,7 @@
             super.startDocumentInternal();
             m_needToCallStartDocument = false;
 
-            if (m_inEntityRef)
+            if (isInEntityRef())
                 return;
 
             m_needToOutputDocTypeDecl = true;
@@ -197,6 +201,7 @@
      */
     public void endDocument() throws org.xml.sax.SAXException
     {
+        flushCharactersBuffer();
         flushPending();
         if (m_doIndent && !m_isprevtext)
         {
@@ -265,9 +270,11 @@
     public void processingInstruction(String target, String data)
         throws org.xml.sax.SAXException
     {
-        if (m_inEntityRef)
+        if (isInEntityRef())
             return;
 
+        m_childNodeNum++;
+        flushCharactersBuffer();
         flushPending();
 
         if (target.equals(Result.PI_DISABLE_OUTPUT_ESCAPING))
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/dom3/DOM3TreeWalker.java	Fri Dec 16 08:18:05 2016 +0000
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/dom3/DOM3TreeWalker.java	Mon Dec 19 11:13:32 2016 +0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016 Oracle and/or its affiliates. All rights reserved.
  */
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
@@ -368,8 +368,6 @@
     private final void dispatachChars(Node node)
         throws org.xml.sax.SAXException {
         if (fSerializer != null) {
-            this.fSerializer.characters(node);
-        } else {
             String data = ((Text) node).getData();
             this.fSerializer.characters(data.toCharArray(), 0, data.length());
         }
@@ -1066,7 +1064,9 @@
                 // should we pass entity reference nodes to the filter???
             }
 
-            if (fLexicalHandler != null) {
+            // if "entities" is true, or EntityReference node has no children,
+            // it will be serialized as the form "&entityName;" in the output.
+            if (fLexicalHandler != null && ((fFeatures & ENTITIES) != 0 || !node.hasChildNodes())) {
 
                 // startEntity outputs only Text but not Element, Attr, Comment
                 // and PI child nodes.  It does so by setting the m_inEntityRef
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/output_html.properties	Fri Dec 16 08:18:05 2016 +0000
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/output_html.properties	Mon Dec 19 11:13:32 2016 +0800
@@ -1,11 +1,12 @@
 ###########################################################################
-# reserved comment block
-# DO NOT REMOVE OR ALTER!
+# Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
 ###########################################################################
-###########################################################################
-# Copyright 2003-2004 The Apache Software Foundation.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
+##
+# 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
 #
@@ -16,11 +17,9 @@
 # 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.
-##########################################################################
+##
 #
-# $Id: output_html.properties,v 1.2.4.1 2005/09/15 08:15:32 suresh_emailid Exp $
-#
-# Specify defaults when method="html".  These defaults use output_xml.properties 
+# Specify defaults when method="html".  These defaults use output_xml.properties
 # as a base.
 #
 
@@ -39,7 +38,7 @@
 #              xalan:content-handler="MyContentHandler"/>
 #  ...
 # Note that the colon after the protocol needs to be escaped.
-{http\u003a//xml.apache.org/xalan}indent-amount=0
+{http\u003a//xml.apache.org/xalan}indent-amount=4
 {http\u003a//xml.apache.org/xalan}content-handler=com.sun.org.apache.xml.internal.serializer.ToHTMLStream
 {http\u003a//xml.apache.org/xalan}entities=com/sun/org/apache/xml/internal/serializer/HTMLEntities
 {http\u003a//xml.apache.org/xalan}use-url-escaping=yes
--- a/jaxp/test/javax/xml/jaxp/functional/javax/xml/transform/xmlfiles/out/saxtf001GF.out	Fri Dec 16 08:18:05 2016 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/javax/xml/transform/xmlfiles/out/saxtf001GF.out	Mon Dec 19 11:13:32 2016 +0800
@@ -1,17 +1,17 @@
 <?xml version="1.0" encoding="UTF-8"?><countries>
-<country name="France">
-<city>Paris</city>
-<city>Nice</city>
-<city>Lyon</city>
-</country>
-<country name="Italia">
-<city>Roma</city>
-<city>Milano</city>
-<city>Firenze</city>
-<city>Napoli</city>
-</country>
-<country name="Espana">
-<city>Madrid</city>
-<city>Barcelona</city>
-</country>
+    <country name="France">
+        <city>Paris</city>
+        <city>Nice</city>
+        <city>Lyon</city>
+    </country>
+    <country name="Italia">
+        <city>Roma</city>
+        <city>Milano</city>
+        <city>Firenze</city>
+        <city>Napoli</city>
+    </country>
+    <country name="Espana">
+        <city>Madrid</city>
+        <city>Barcelona</city>
+    </country>
 </countries>
--- a/jaxp/test/javax/xml/jaxp/functional/javax/xml/transform/xmlfiles/out/saxtf002GF.out	Fri Dec 16 08:18:05 2016 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/javax/xml/transform/xmlfiles/out/saxtf002GF.out	Mon Dec 19 11:13:32 2016 +0800
@@ -1,17 +1,17 @@
 <?xml version="1.0" encoding="UTF-8"?><countries>
-<country name="France">
-<city>Paris</city>
-<city>Nice</city>
-<city>Lyon</city>
-</country>
-<country name="Italia">
-<city>Roma</city>
-<city>Milano</city>
-<city>Firenze</city>
-<city>Napoli</city>
-</country>
-<country name="Espana">
-<city>Madrid</city>
-<city>Barcelona</city>
-</country>
+    <country name="France">
+        <city>Paris</city>
+        <city>Nice</city>
+        <city>Lyon</city>
+    </country>
+    <country name="Italia">
+        <city>Roma</city>
+        <city>Milano</city>
+        <city>Firenze</city>
+        <city>Napoli</city>
+    </country>
+    <country name="Espana">
+        <city>Madrid</city>
+        <city>Barcelona</city>
+    </country>
 </countries>
--- a/jaxp/test/javax/xml/jaxp/functional/javax/xml/transform/xmlfiles/out/saxtf003GF.out	Fri Dec 16 08:18:05 2016 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/javax/xml/transform/xmlfiles/out/saxtf003GF.out	Mon Dec 19 11:13:32 2016 +0800
@@ -1,17 +1,17 @@
 <?xml version="1.0" encoding="UTF-8"?><countries>
-<country name="France">
-<city>Paris</city>
-<city>Nice</city>
-<city>Lyon</city>
-</country>
-<country name="Italia">
-<city>Roma</city>
-<city>Milano</city>
-<city>Firenze</city>
-<city>Napoli</city>
-</country>
-<country name="Espana">
-<city>Madrid</city>
-<city>Barcelona</city>
-</country>
+    <country name="France">
+        <city>Paris</city>
+        <city>Nice</city>
+        <city>Lyon</city>
+    </country>
+    <country name="Italia">
+        <city>Roma</city>
+        <city>Milano</city>
+        <city>Firenze</city>
+        <city>Napoli</city>
+    </country>
+    <country name="Espana">
+        <city>Madrid</city>
+        <city>Barcelona</city>
+    </country>
 </countries>
--- a/jaxp/test/javax/xml/jaxp/functional/javax/xml/transform/xmlfiles/out/saxtf005GF.out	Fri Dec 16 08:18:05 2016 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/javax/xml/transform/xmlfiles/out/saxtf005GF.out	Mon Dec 19 11:13:32 2016 +0800
@@ -1,17 +1,17 @@
 <?xml version="1.0" encoding="UTF-8"?><countries>
-<country name="France">
-<city>Paris</city>
-<city>Nice</city>
-<city>Lyon</city>
-</country>
-<country name="Italia">
-<city>Roma</city>
-<city>Milano</city>
-<city>Firenze</city>
-<city>Napoli</city>
-</country>
-<country name="Espana">
-<city>Madrid</city>
-<city>Barcelona</city>
-</country>
+    <country name="France">
+        <city>Paris</city>
+        <city>Nice</city>
+        <city>Lyon</city>
+    </country>
+    <country name="Italia">
+        <city>Roma</city>
+        <city>Milano</city>
+        <city>Firenze</city>
+        <city>Napoli</city>
+    </country>
+    <country name="Espana">
+        <city>Madrid</city>
+        <city>Barcelona</city>
+    </country>
 </countries>
--- a/jaxp/test/javax/xml/jaxp/functional/javax/xml/transform/xmlfiles/out/saxtf006GF.out	Fri Dec 16 08:18:05 2016 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/javax/xml/transform/xmlfiles/out/saxtf006GF.out	Mon Dec 19 11:13:32 2016 +0800
@@ -1,17 +1,17 @@
 <?xml version="1.0" encoding="UTF-8"?><countries>
-<country name="France">
-<city>Paris</city>
-<city>Nice</city>
-<city>Lyon</city>
-</country>
-<country name="Italia">
-<city>Roma</city>
-<city>Milano</city>
-<city>Firenze</city>
-<city>Napoli</city>
-</country>
-<country name="Espana">
-<city>Madrid</city>
-<city>Barcelona</city>
-</country>
+    <country name="France">
+        <city>Paris</city>
+        <city>Nice</city>
+        <city>Lyon</city>
+    </country>
+    <country name="Italia">
+        <city>Roma</city>
+        <city>Milano</city>
+        <city>Firenze</city>
+        <city>Napoli</city>
+    </country>
+    <country name="Espana">
+        <city>Madrid</city>
+        <city>Barcelona</city>
+    </country>
 </countries>
--- a/jaxp/test/javax/xml/jaxp/functional/javax/xml/transform/xmlfiles/out/saxtf009GF.out	Fri Dec 16 08:18:05 2016 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/javax/xml/transform/xmlfiles/out/saxtf009GF.out	Mon Dec 19 11:13:32 2016 +0800
@@ -1,17 +1,17 @@
 <?xml version="1.0" encoding="UTF-8"?><countries>
-<country name="France">
-<city>Paris</city>
-<city>Nice</city>
-<city>Lyon</city>
-</country>
-<country name="Italia">
-<city>Roma</city>
-<city>Milano</city>
-<city>Firenze</city>
-<city>Napoli</city>
-</country>
-<country name="Espana">
-<city>Madrid</city>
-<city>Barcelona</city>
-</country>
+    <country name="France">
+        <city>Paris</city>
+        <city>Nice</city>
+        <city>Lyon</city>
+    </country>
+    <country name="Italia">
+        <city>Roma</city>
+        <city>Milano</city>
+        <city>Firenze</city>
+        <city>Napoli</city>
+    </country>
+    <country name="Espana">
+        <city>Madrid</city>
+        <city>Barcelona</city>
+    </country>
 </countries>
--- a/jaxp/test/javax/xml/jaxp/functional/test/astro/AstroTest.java	Fri Dec 16 08:18:05 2016 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/test/astro/AstroTest.java	Mon Dec 19 11:13:32 2016 +0800
@@ -25,14 +25,13 @@
 
 import static java.lang.String.valueOf;
 import static jaxp.library.JAXPTestUtilities.USER_DIR;
-import static org.testng.Assert.assertEquals;
+import static jaxp.library.JAXPTestUtilities.compareWithGold;
+import static org.testng.Assert.assertTrue;
 import static test.astro.AstroConstants.ASTROCAT;
 import static test.astro.AstroConstants.GOLDEN_DIR;
 
-import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Paths;
-import java.util.List;
 
 import javax.xml.transform.sax.TransformerHandler;
 
@@ -77,10 +76,10 @@
     @BeforeClass
     public void setup() throws Exception {
         data = new FiltersAndGolden[4];
-        data[0] = new FiltersAndGolden(getGoldenFileContent(1), astro -> astro.getRAFilter(0.106, 0.108));
-        data[1] = new FiltersAndGolden(getGoldenFileContent(2), astro -> astro.getStellarTypeFilter("K0IIIbCN-0.5"));
-        data[2] = new FiltersAndGolden(getGoldenFileContent(3), astro -> astro.getStellarTypeFilter("G"), astro -> astro.getDecFilter(-5.0, 60.0));
-        data[3] = new FiltersAndGolden(getGoldenFileContent(4), astro -> astro.getRADECFilter(0.084, 0.096, -5.75, 14.0));
+        data[0] = new FiltersAndGolden(getGoldenFileName(1), astro -> astro.getRAFilter(0.106, 0.108));
+        data[1] = new FiltersAndGolden(getGoldenFileName(2), astro -> astro.getStellarTypeFilter("K0IIIbCN-0.5"));
+        data[2] = new FiltersAndGolden(getGoldenFileName(3), astro -> astro.getStellarTypeFilter("G"), astro -> astro.getDecFilter(-5.0, 60.0));
+        data[3] = new FiltersAndGolden(getGoldenFileName(4), astro -> astro.getRADECFilter(0.084, 0.096, -5.75, 14.0));
     }
 
     /*
@@ -102,11 +101,11 @@
         AstroProcessor astro = new AstroProcessor(fFactClass, ASTROCAT, isFactClass);
 
         for (int i = 0; i < data.length; i++) {
-            runProcess(astro, valueOf(i + 1), data[i].getGolden(), data[i].getFilters());
+            runProcess(astro, valueOf(i + 1), data[i].getGoldenFileName(), data[i].getFilters());
         }
     }
 
-    private void runProcess(AstroProcessor astro, String processNum, List<String> goldenfileContent, FilterCreator... filterCreators) throws Exception {
+    private void runProcess(AstroProcessor astro, String processNum, String goldenFileName, FilterCreator... filterCreators) throws Exception {
         System.out.println("run process " + processNum);
         TransformerHandler[] filters = new TransformerHandler[filterCreators.length];
         for (int i = 0; i < filterCreators.length; i++)
@@ -115,11 +114,11 @@
         String outputfile = Files.createTempFile(Paths.get(USER_DIR), "query" + processNum + ".out.", null).toString();
         System.out.println("output file: " + outputfile);
         astro.process(outputfile, filters);
-        assertEquals(Files.readAllLines(Paths.get(outputfile)), goldenfileContent);
+        assertTrue(compareWithGold(goldenFileName, outputfile));
     }
 
-    private List<String>  getGoldenFileContent(int num) throws IOException {
-        return Files.readAllLines(Paths.get(GOLDEN_DIR + "query" + num + ".out"));
+    private String getGoldenFileName(int num) {
+        return GOLDEN_DIR + "query" + num + ".out";
     }
 
     @FunctionalInterface
@@ -129,19 +128,19 @@
 
     private static class FiltersAndGolden {
         private FilterCreator[] filters;
-        private List<String> golden;
+        private String goldenFileName;
 
-        FiltersAndGolden(List<String> golden, FilterCreator... filters) {
+        FiltersAndGolden(String goldenFileName, FilterCreator... filters) {
             this.filters = filters;
-            this.golden = golden;
+            this.goldenFileName = goldenFileName;
         }
 
         FilterCreator[] getFilters() {
             return filters;
         }
 
-        List<String> getGolden() {
-            return golden;
+        String getGoldenFileName() {
+            return goldenFileName;
         }
     }
 }
--- a/jaxp/test/javax/xml/jaxp/functional/test/astro/xmlfiles/gold/query1.out	Fri Dec 16 08:18:05 2016 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/test/astro/xmlfiles/gold/query1.out	Mon Dec 19 11:13:32 2016 +0800
@@ -1,15 +1,24 @@
 <html xmlns:astro="http://www.astro.com/astro">
-<h1>Bright Star Catalog Extract</h1>
-<body>
-<b>Star Id: </b>7<br>
-<b>Constellation: </b>Cas<br>
-<b>Description: </b>10    Cas<br>
-<b>RA J2000: </b>00:06:26.5<br>
-<b>DEC J2000: </b>64:11:46<br>
-<b>Visual Magnitude: </b>5.59<br>
-<b>Spectral Type: </b>B9III<br>
-<b>Galactic Longitude: </b>118.06<br>
-<b>Galactic Latitude: </b>1.75<br>
-<hr>
-</body>
+    <h1>Bright Star Catalog Extract</h1>
+    <body>
+        <b>Star Id: </b>7
+        <br>
+        <b>Constellation: </b>Cas
+        <br>
+        <b>Description: </b>10    Cas
+        <br>
+        <b>RA J2000: </b>00:06:26.5
+        <br>
+        <b>DEC J2000: </b>64:11:46
+        <br>
+        <b>Visual Magnitude: </b>5.59
+        <br>
+        <b>Spectral Type: </b>B9III
+        <br>
+        <b>Galactic Longitude: </b>118.06
+        <br>
+        <b>Galactic Latitude: </b>1.75
+        <br>
+        <hr>
+    </body>
 </html>
--- a/jaxp/test/javax/xml/jaxp/functional/test/astro/xmlfiles/gold/query2.out	Fri Dec 16 08:18:05 2016 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/test/astro/xmlfiles/gold/query2.out	Mon Dec 19 11:13:32 2016 +0800
@@ -1,15 +1,24 @@
 <html xmlns:astro="http://www.astro.com/astro">
-<h1>Bright Star Catalog Extract</h1>
-<body>
-<b>Star Id: </b>3<br>
-<b>Constellation: </b>Psc<br>
-<b>Description: </b>33    Psc<br>
-<b>RA J2000: </b>00:05:20.1<br>
-<b>DEC J2000: </b>05:42:27<br>
-<b>Visual Magnitude: </b>4.61<br>
-<b>Spectral Type: </b>K0IIIbCN-0.5<br>
-<b>Galactic Longitude: </b>93.75<br>
-<b>Galactic Latitude: </b>-65.93<br>
-<hr>
-</body>
+    <h1>Bright Star Catalog Extract</h1>
+    <body>
+        <b>Star Id: </b>3
+        <br>
+        <b>Constellation: </b>Psc
+        <br>
+        <b>Description: </b>33    Psc
+        <br>
+        <b>RA J2000: </b>00:05:20.1
+        <br>
+        <b>DEC J2000: </b>05:42:27
+        <br>
+        <b>Visual Magnitude: </b>4.61
+        <br>
+        <b>Spectral Type: </b>K0IIIbCN-0.5
+        <br>
+        <b>Galactic Longitude: </b>93.75
+        <br>
+        <b>Galactic Latitude: </b>-65.93
+        <br>
+        <hr>
+    </body>
 </html>
--- a/jaxp/test/javax/xml/jaxp/functional/test/astro/xmlfiles/gold/query3.out	Fri Dec 16 08:18:05 2016 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/test/astro/xmlfiles/gold/query3.out	Mon Dec 19 11:13:32 2016 +0800
@@ -1,39 +1,62 @@
 <html xmlns:astro="http://www.astro.com/astro">
-<h1>Bright Star Catalog Extract</h1>
-<body>
-<b>Star Id: </b>2<br>
-<b>Constellation: </b>
-<br>
-<b>Description: </b>
-<br>
-<b>RA J2000: </b>00:05:03.8<br>
-<b>DEC J2000: </b>00:30:11<br>
-<b>Visual Magnitude: </b>6.29<br>
-<b>Spectral Type: </b>gG9<br>
-<b>Galactic Longitude: </b>98.33<br>
-<b>Galactic Latitude: </b>-61.14<br>
-<hr>
-<b>Star Id: </b>4<br>
-<b>Constellation: </b>Peg<br>
-<b>Description: </b>86    Peg<br>
-<b>RA J2000: </b>00:05:42.0<br>
-<b>DEC J2000: </b>13:23:46<br>
-<b>Visual Magnitude: </b>5.51<br>
-<b>Spectral Type: </b>G5III<br>
-<b>Galactic Longitude: </b>106.19<br>
-<b>Galactic Latitude: </b>-47.98<br>
-<hr>
-<b>Star Id: </b>5<br>
-<b>Constellation: </b>
-<br>
-<b>Description: </b>
-<br>
-<b>RA J2000: </b>00:06:16.0<br>
-<b>DEC J2000: </b>58:26:12<br>
-<b>Visual Magnitude: </b>5.96<br>
-<b>Spectral Type: </b>G5V<br>
-<b>Galactic Longitude: </b>117.03<br>
-<b>Galactic Latitude: </b>-03.92<br>
-<hr>
-</body>
+    <h1>Bright Star Catalog Extract</h1>
+    <body>
+        <b>Star Id: </b>2
+        <br>
+        <b>Constellation: </b>
+        <br>
+        <b>Description: </b>
+        <br>
+        <b>RA J2000: </b>00:05:03.8
+        <br>
+        <b>DEC J2000: </b>00:30:11
+        <br>
+        <b>Visual Magnitude: </b>6.29
+        <br>
+        <b>Spectral Type: </b>gG9
+        <br>
+        <b>Galactic Longitude: </b>98.33
+        <br>
+        <b>Galactic Latitude: </b>-61.14
+        <br>
+        <hr>
+        <b>Star Id: </b>4
+        <br>
+        <b>Constellation: </b>Peg
+        <br>
+        <b>Description: </b>86    Peg
+        <br>
+        <b>RA J2000: </b>00:05:42.0
+        <br>
+        <b>DEC J2000: </b>13:23:46
+        <br>
+        <b>Visual Magnitude: </b>5.51
+        <br>
+        <b>Spectral Type: </b>G5III
+        <br>
+        <b>Galactic Longitude: </b>106.19
+        <br>
+        <b>Galactic Latitude: </b>-47.98
+        <br>
+        <hr>
+        <b>Star Id: </b>5
+        <br>
+        <b>Constellation: </b>
+        <br>
+        <b>Description: </b>
+        <br>
+        <b>RA J2000: </b>00:06:16.0
+        <br>
+        <b>DEC J2000: </b>58:26:12
+        <br>
+        <b>Visual Magnitude: </b>5.96
+        <br>
+        <b>Spectral Type: </b>G5V
+        <br>
+        <b>Galactic Longitude: </b>117.03
+        <br>
+        <b>Galactic Latitude: </b>-03.92
+        <br>
+        <hr>
+    </body>
 </html>
--- a/jaxp/test/javax/xml/jaxp/functional/test/astro/xmlfiles/gold/query4.out	Fri Dec 16 08:18:05 2016 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/test/astro/xmlfiles/gold/query4.out	Mon Dec 19 11:13:32 2016 +0800
@@ -1,37 +1,62 @@
 <html xmlns:astro="http://www.astro.com/astro">
-<h1>Bright Star Catalog Extract</h1>
-<body>
-<b>Star Id: </b>2<br>
-<b>Constellation: </b>
-<br>
-<b>Description: </b>
-<br>
-<b>RA J2000: </b>00:05:03.8<br>
-<b>DEC J2000: </b>00:30:11<br>
-<b>Visual Magnitude: </b>6.29<br>
-<b>Spectral Type: </b>gG9<br>
-<b>Galactic Longitude: </b>98.33<br>
-<b>Galactic Latitude: </b>-61.14<br>
-<hr>
-<b>Star Id: </b>3<br>
-<b>Constellation: </b>Psc<br>
-<b>Description: </b>33    Psc<br>
-<b>RA J2000: </b>00:05:20.1<br>
-<b>DEC J2000: </b>05:42:27<br>
-<b>Visual Magnitude: </b>4.61<br>
-<b>Spectral Type: </b>K0IIIbCN-0.5<br>
-<b>Galactic Longitude: </b>93.75<br>
-<b>Galactic Latitude: </b>-65.93<br>
-<hr>
-<b>Star Id: </b>4<br>
-<b>Constellation: </b>Peg<br>
-<b>Description: </b>86    Peg<br>
-<b>RA J2000: </b>00:05:42.0<br>
-<b>DEC J2000: </b>13:23:46<br>
-<b>Visual Magnitude: </b>5.51<br>
-<b>Spectral Type: </b>G5III<br>
-<b>Galactic Longitude: </b>106.19<br>
-<b>Galactic Latitude: </b>-47.98<br>
-<hr>
-</body>
+    <h1>Bright Star Catalog Extract</h1>
+    <body>
+        <b>Star Id: </b>2
+        <br>
+        <b>Constellation: </b>
+        <br>
+        <b>Description: </b>
+        <br>
+        <b>RA J2000: </b>00:05:03.8
+        <br>
+        <b>DEC J2000: </b>00:30:11
+        <br>
+        <b>Visual Magnitude: </b>6.29
+        <br>
+        <b>Spectral Type: </b>gG9
+        <br>
+        <b>Galactic Longitude: </b>98.33
+        <br>
+        <b>Galactic Latitude: </b>-61.14
+        <br>
+        <hr>
+        <b>Star Id: </b>3
+        <br>
+        <b>Constellation: </b>Psc
+        <br>
+        <b>Description: </b>33    Psc
+        <br>
+        <b>RA J2000: </b>00:05:20.1
+        <br>
+        <b>DEC J2000: </b>05:42:27
+        <br>
+        <b>Visual Magnitude: </b>4.61
+        <br>
+        <b>Spectral Type: </b>K0IIIbCN-0.5
+        <br>
+        <b>Galactic Longitude: </b>93.75
+        <br>
+        <b>Galactic Latitude: </b>-65.93
+        <br>
+        <hr>
+        <b>Star Id: </b>4
+        <br>
+        <b>Constellation: </b>Peg
+        <br>
+        <b>Description: </b>86    Peg
+        <br>
+        <b>RA J2000: </b>00:05:42.0
+        <br>
+        <b>DEC J2000: </b>13:23:46
+        <br>
+        <b>Visual Magnitude: </b>5.51
+        <br>
+        <b>Spectral Type: </b>G5III
+        <br>
+        <b>Galactic Longitude: </b>106.19
+        <br>
+        <b>Galactic Latitude: </b>-47.98
+        <br>
+        <hr>
+    </body>
 </html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/PrettyPrintTest.java	Mon Dec 19 11:13:32 2016 +0800
@@ -0,0 +1,366 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package common.prettyprint;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.StringReader;
+import java.io.StringWriter;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.stream.StreamSource;
+
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Listeners;
+import org.testng.annotations.Test;
+import org.w3c.dom.DOMConfiguration;
+import org.w3c.dom.DOMImplementation;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.Text;
+import org.w3c.dom.bootstrap.DOMImplementationRegistry;
+import org.w3c.dom.ls.DOMImplementationLS;
+import org.w3c.dom.ls.LSOutput;
+import org.w3c.dom.ls.LSSerializer;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+
+/*
+ * @test
+ * @bug 6439439 8087303
+ * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest
+ * @run testng/othervm -DrunSecMngr=true common.prettyprint.PrettyPrintTest
+ * @run testng/othervm common.prettyprint.PrettyPrintTest
+ * @summary Test serializing xml and html with indentation.
+ */
+@Listeners({jaxp.library.FilePolicy.class})
+public class PrettyPrintTest {
+    /*
+     * test CDATA, elements only, text and element, whitespace and element,
+     * xml:space property and nested xml:space property, mixed node types.
+     */
+    @DataProvider(name = "xml-data")
+    public Object[][] xmlData() throws Exception {
+        return new Object[][] {
+                { read("xmltest1.xml"), read("xmltest1.out") },
+                { read("xmltest2.xml"), read("xmltest2.out") },
+                { read("xmltest3.xml"), read("xmltest3.out") },
+                { read("xmltest4.xml"), read("xmltest4.out") },
+                { read("xmltest5.xml"), read("xmltest5.out") },
+                { read("xmltest6.xml"), read("xmltest6.out") },
+                { read("xmltest7.xml"), read("xmltest7.out") },
+                { read("xmltest8.xml"), read("xmltest8.out") } };
+    }
+
+    /*
+     * @bug 8087303
+     * Test the whitespace text nodes are serialized with pretty-print by LSSerializer and transformer correctly
+     *
+     */
+    @Test(dataProvider = "xml-data")
+    public void testXMLPrettyPrint(String source, String expected) throws Exception {
+        // test it's no change if no pretty-print
+        String result = serializerWrite(toXmlDocument(source), false);
+        assertTrue(toXmlDocument(source).isEqualNode(toXmlDocument(result)), "The actual is: " + result);
+        // test pretty-print
+        assertEquals(serializerWrite(toXmlDocument(source), true), expected);
+        // test it's no change if no pretty-print
+        result = transform(toXmlDocument(source), false);
+        assertTrue(toXmlDocument(source).isEqualNode(toXmlDocument(result)), "The actual is: " + result);
+        // test pretty-print
+        assertEquals(transform(toXmlDocument(source), true).replaceAll("\r\n", "\n"), expected);
+    }
+
+    /*
+     * test pure text content, and sequent Text nodes.
+     */
+    @DataProvider(name = "xml-node-data")
+    public Object[][] xmlNodeData() throws Exception {
+        return new Object[][] {
+                { newTextNode(read("nodetest1.txt")), read("nodetest1.out") },
+                { createDocWithSequentTextNodes(), read("nodetest2.out") } };
+    }
+
+    /*
+     * @bug 8087303
+     * Test the whitespace text nodes are serialized with pretty-print by LSSerializer and transformer correctly,
+     * doesn't compare with the source because the test data is Node object
+     *
+     */
+    @Test(dataProvider = "xml-node-data")
+    public void testXMLNodePrettyPrint(Node xml, String expected) throws Exception {
+        assertEquals(serializerWrite(xml, true), expected);
+        assertEquals(transform(xml, true).replaceAll("\r\n", "\n"), expected);
+    }
+
+    /*
+     * test block element, inline element, text, and mixed elements.
+     */
+    @DataProvider(name = "html-data")
+    public Object[][] htmlData() throws Exception {
+        return new Object[][] {
+            { read("htmltest1.xml"), read("htmltest1.out") },
+            { read("htmltest2.xml"), read("htmltest2.out") },
+            { read("htmltest3.xml"), read("htmltest3.out") },
+            { read("htmltest4.xml"), read("htmltest4.out") },
+            { read("htmltest5.xml"), read("htmltest5.out") },
+            { read("htmltest6.xml"), read("htmltest6.out") } };
+    }
+
+    /*
+     * @bug 8087303
+     * Transform to HTML, test Pretty Print for HTML.
+     *
+     */
+    @Test(dataProvider = "html-data")
+    public void testTransformToHTML(String source, String expected) throws Exception {
+        // test it's no change if no pretty-print
+        StringWriter writer = new StringWriter();
+        getTransformer(true, false).transform(new StreamSource(new StringReader(source)), new StreamResult(writer));
+        assertTrue(toXmlDocument(source).isEqualNode(toXmlDocument(writer.toString())), "The actual is: " + writer.toString());
+
+        // test pretty-print
+        writer = new StringWriter();
+        getTransformer(true, true).transform(new StreamSource(new StringReader(source)), new StreamResult(writer));
+        assertEquals(writer.toString().replaceAll("\r\n", "\n"), expected);
+    }
+
+    @Test
+    public void testLSSerializerFormatPrettyPrint() {
+
+        final String XML_DOCUMENT = "<?xml version=\"1.0\" encoding=\"UTF-16\"?>\n"
+                + "<hello>before child element<child><children/><children/></child>after child element</hello>";
+        /**JDK-8035467
+         * no newline in default output
+         */
+        final String XML_DOCUMENT_DEFAULT_PRINT =
+                "<?xml version=\"1.0\" encoding=\"UTF-16\"?>"
+                + "<hello>"
+                + "before child element"
+                + "<child><children/><children/></child>"
+                + "after child element</hello>";
+
+        final String XML_DOCUMENT_PRETTY_PRINT = "<?xml version=\"1.0\" encoding=\"UTF-16\"?><hello>\n" +
+                "    before child element\n" +
+                "    <child>\n" +
+                "        <children/>\n" +
+                "        <children/>\n" +
+                "    </child>\n" +
+                "    after child element\n" +
+                "</hello>\n";
+
+        // it all begins with a Document
+        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
+        DocumentBuilder documentBuilder = null;
+        try {
+            documentBuilder = documentBuilderFactory.newDocumentBuilder();
+        } catch (ParserConfigurationException parserConfigurationException) {
+            parserConfigurationException.printStackTrace();
+            Assert.fail(parserConfigurationException.toString());
+        }
+        Document document = null;
+
+        StringReader stringReader = new StringReader(XML_DOCUMENT);
+        InputSource inputSource = new InputSource(stringReader);
+        try {
+            document = documentBuilder.parse(inputSource);
+        } catch (SAXException saxException) {
+            saxException.printStackTrace();
+            Assert.fail(saxException.toString());
+        } catch (IOException ioException) {
+            ioException.printStackTrace();
+            Assert.fail(ioException.toString());
+        }
+
+        // query DOM Interfaces to get to a LSSerializer
+        DOMImplementation domImplementation = documentBuilder.getDOMImplementation();
+        DOMImplementationLS domImplementationLS = (DOMImplementationLS) domImplementation;
+        LSSerializer lsSerializer = domImplementationLS.createLSSerializer();
+
+        System.out.println("Serializer is: " + lsSerializer.getClass().getName() + " " + lsSerializer);
+
+        // get configuration
+        DOMConfiguration domConfiguration = lsSerializer.getDomConfig();
+
+        // query current configuration
+        Boolean defaultFormatPrettyPrint = (Boolean) domConfiguration.getParameter(DOM_FORMAT_PRETTY_PRINT);
+        Boolean canSetFormatPrettyPrintFalse = (Boolean) domConfiguration.canSetParameter(DOM_FORMAT_PRETTY_PRINT, Boolean.FALSE);
+        Boolean canSetFormatPrettyPrintTrue = (Boolean) domConfiguration.canSetParameter(DOM_FORMAT_PRETTY_PRINT, Boolean.TRUE);
+
+        System.out.println(DOM_FORMAT_PRETTY_PRINT + " default/can set false/can set true = " + defaultFormatPrettyPrint + "/"
+                + canSetFormatPrettyPrintFalse + "/" + canSetFormatPrettyPrintTrue);
+
+        // test values
+        assertEquals(defaultFormatPrettyPrint, Boolean.FALSE, "Default value of " + DOM_FORMAT_PRETTY_PRINT + " should be " + Boolean.FALSE);
+
+        assertEquals(canSetFormatPrettyPrintFalse, Boolean.TRUE, "Can set " + DOM_FORMAT_PRETTY_PRINT + " to " + Boolean.FALSE + " should be "
+                + Boolean.TRUE);
+
+        assertEquals(canSetFormatPrettyPrintTrue, Boolean.TRUE, "Can set " + DOM_FORMAT_PRETTY_PRINT + " to " + Boolean.TRUE + " should be "
+                + Boolean.TRUE);
+
+        // get default serialization
+        String prettyPrintDefault = lsSerializer.writeToString(document);
+        System.out.println("(default) " + DOM_FORMAT_PRETTY_PRINT + "==" + (Boolean) domConfiguration.getParameter(DOM_FORMAT_PRETTY_PRINT)
+                + ": \n\"" + prettyPrintDefault + "\"");
+
+        assertEquals(prettyPrintDefault, XML_DOCUMENT_DEFAULT_PRINT, "Invalid serialization with default value, " + DOM_FORMAT_PRETTY_PRINT + "=="
+                + (Boolean) domConfiguration.getParameter(DOM_FORMAT_PRETTY_PRINT));
+
+        // configure LSSerializer to not format-pretty-print
+        domConfiguration.setParameter(DOM_FORMAT_PRETTY_PRINT, Boolean.FALSE);
+        String prettyPrintFalse = lsSerializer.writeToString(document);
+        System.out.println("(FALSE) " + DOM_FORMAT_PRETTY_PRINT + "==" + (Boolean) domConfiguration.getParameter(DOM_FORMAT_PRETTY_PRINT)
+                + ": \n\"" + prettyPrintFalse + "\"");
+
+        assertEquals(prettyPrintFalse, XML_DOCUMENT_DEFAULT_PRINT, "Invalid serialization with FALSE value, " + DOM_FORMAT_PRETTY_PRINT + "=="
+                + (Boolean) domConfiguration.getParameter(DOM_FORMAT_PRETTY_PRINT));
+
+        // configure LSSerializer to format-pretty-print
+        domConfiguration.setParameter(DOM_FORMAT_PRETTY_PRINT, Boolean.TRUE);
+        String prettyPrintTrue = lsSerializer.writeToString(document);
+        System.out.println("(TRUE) " + DOM_FORMAT_PRETTY_PRINT + "==" + (Boolean) domConfiguration.getParameter(DOM_FORMAT_PRETTY_PRINT)
+                + ": \n\"" + prettyPrintTrue + "\"");
+
+        assertEquals(prettyPrintTrue, XML_DOCUMENT_PRETTY_PRINT, "Invalid serialization with TRUE value, " + DOM_FORMAT_PRETTY_PRINT + "=="
+                + (Boolean) domConfiguration.getParameter(DOM_FORMAT_PRETTY_PRINT));
+    }
+
+    private String serializerWrite(Node xml, boolean pretty) throws Exception {
+        DOMImplementationRegistry registry = DOMImplementationRegistry.newInstance();
+        DOMImplementationLS domImplementation = (DOMImplementationLS) registry.getDOMImplementation("LS");
+        StringWriter writer = new StringWriter();
+        LSOutput formattedOutput = domImplementation.createLSOutput();
+        formattedOutput.setCharacterStream(writer);
+        LSSerializer domSerializer = domImplementation.createLSSerializer();
+        domSerializer.getDomConfig().setParameter(DOM_FORMAT_PRETTY_PRINT, pretty);
+        domSerializer.getDomConfig().setParameter("xml-declaration", false);
+        domSerializer.write(xml, formattedOutput);
+        return writer.toString();
+    }
+
+    private String transform(Node xml, boolean pretty) throws Exception {
+        Transformer transformer = getTransformer(false, pretty);
+        StringWriter writer = new StringWriter();
+        transformer.transform(new DOMSource(xml), new StreamResult(writer));
+        return writer.toString();
+    }
+
+    private Document toXmlDocument(String xmlString) throws Exception {
+        InputSource xmlInputSource = new InputSource(new StringReader(xmlString));
+        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+        dbf.setValidating(true);
+        DocumentBuilder xmlDocumentBuilder = dbf.newDocumentBuilder();
+        Document node = xmlDocumentBuilder.parse(xmlInputSource);
+        return node;
+    }
+
+    private Text newTextNode(String text) throws Exception {
+        DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+        return db.newDocument().createTextNode(text);
+    }
+
+    private Document createDocWithSequentTextNodes() throws Exception {
+        DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+        Document doc = db.newDocument();
+        Node root = doc.createElement("root");
+        doc.appendChild(root);
+        root.appendChild(doc.createTextNode(" "));
+        root.appendChild(doc.createTextNode("t"));
+        root.appendChild(doc.createTextNode("\n"));
+        root.appendChild(doc.createTextNode("t"));
+        root.appendChild(doc.createTextNode("   "));
+        Node child1 = doc.createElement("child1");
+        root.appendChild(child1);
+        child1.appendChild(doc.createTextNode(" "));
+        child1.appendChild(doc.createTextNode("\n"));
+        root.appendChild(doc.createTextNode("t"));
+        Node child2 = doc.createElement("child2");
+        root.appendChild(child2);
+        child2.appendChild(doc.createTextNode(" "));
+        root.appendChild(doc.createTextNode(" "));
+        Node child3 = doc.createElement("child3");
+        root.appendChild(child3);
+        child3.appendChild(doc.createTextNode(" "));
+        root.appendChild(doc.createTextNode(" "));
+        Node child4 = doc.createElement("child4");
+        root.appendChild(child4);
+        child4.appendChild(doc.createTextNode(" "));
+
+        root.appendChild(doc.createTextNode(" "));
+        Node child5 = doc.createElement("child5");
+        root.appendChild(child5);
+        child5.appendChild(doc.createTextNode("t"));
+
+        Node child51 = doc.createElement("child51");
+        child5.appendChild(child51);
+        child51.appendChild(doc.createTextNode(" "));
+        Node child511 = doc.createElement("child511");
+        child51.appendChild(child511);
+        child511.appendChild(doc.createTextNode("t"));
+        child51.appendChild(doc.createTextNode(" "));
+        child5.appendChild(doc.createTextNode("t"));
+
+        root.appendChild(doc.createTextNode(" "));
+        root.appendChild(doc.createComment(" test comment "));
+        root.appendChild(doc.createTextNode(" \n"));
+        root.appendChild(doc.createComment(" "));
+        root.appendChild(doc.createTextNode("\n"));
+        root.appendChild(doc.createProcessingInstruction("target1", "test"));
+        root.appendChild(doc.createTextNode(" "));
+        root.appendChild(doc.createTextNode(" "));
+        return doc;
+    }
+
+    private Transformer getTransformer(boolean html, boolean pretty) throws Exception {
+        Transformer transformer = TransformerFactory.newInstance().newTransformer();
+        transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
+        transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
+        if (html)
+            transformer.setOutputProperty(OutputKeys.METHOD, "html");
+        transformer.setOutputProperty(OutputKeys.INDENT, pretty ? "yes" : "no");
+        return transformer;
+    }
+
+
+    private String read(String filename) throws Exception {
+        try (InputStream in = PrettyPrintTest.class.getResourceAsStream(filename)) {
+            return new String(in.readAllBytes());
+        }
+    }
+
+    private static final String DOM_FORMAT_PRETTY_PRINT = "format-pretty-print";
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/htmltest1.out	Mon Dec 19 11:13:32 2016 +0800
@@ -0,0 +1,6 @@
+<rss version="2.0">
+    <channel xml:space="preserve">
+        <title>Java Tutorials and Examples 1</title>
+        <language>en-us</language>
+    </channel>
+</rss>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/htmltest1.xml	Mon Dec 19 11:13:32 2016 +0800
@@ -0,0 +1,1 @@
+<rss version="2.0"><channel xml:space="preserve"><title>Java Tutorials and Examples 1</title> <language>en-us</language></channel></rss>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/htmltest2.out	Mon Dec 19 11:13:32 2016 +0800
@@ -0,0 +1,3 @@
+<html>
+    <code>Java</code><b><sup>TM</sup></b>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/htmltest2.xml	Mon Dec 19 11:13:32 2016 +0800
@@ -0,0 +1,1 @@
+<html><code>Java</code><b><sup>TM</sup></b></html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/htmltest3.out	Mon Dec 19 11:13:32 2016 +0800
@@ -0,0 +1,3 @@
+<p>
+    this is <a href="test.html">a <strong>test</strong></a> page
+</p>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/htmltest3.xml	Mon Dec 19 11:13:32 2016 +0800
@@ -0,0 +1,1 @@
+<p>this is <a href="test.html">a <strong>test</strong></a> page</p>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/htmltest4.out	Mon Dec 19 11:13:32 2016 +0800
@@ -0,0 +1,10 @@
+<html>
+    <body>
+        <h1>A heading</h1>
+        <p>
+            new paragraph
+            <form>an empty form</form>
+            <a href="test.html">test</a>
+        </p>
+    </body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/htmltest4.xml	Mon Dec 19 11:13:32 2016 +0800
@@ -0,0 +1,1 @@
+<html><body><h1>A heading</h1><p>new paragraph<form>an empty form</form><a href="test.html">test</a></p></body></html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/htmltest5.out	Mon Dec 19 11:13:32 2016 +0800
@@ -0,0 +1,7 @@
+<html>
+    <p>
+        this is a mixed test <a href="test.html">click
+            <p>to the test</p>
+            page</a>link end
+    </p>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/htmltest5.xml	Mon Dec 19 11:13:32 2016 +0800
@@ -0,0 +1,1 @@
+<html><p>this is a mixed test <a href="test.html">click<p>to the test</p>page</a>link end</p></html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/htmltest6.out	Mon Dec 19 11:13:32 2016 +0800
@@ -0,0 +1,6 @@
+<p>
+    <a href="test.html">text
+        <table></table>
+    </a> another
+    <form></form>
+</p>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/htmltest6.xml	Mon Dec 19 11:13:32 2016 +0800
@@ -0,0 +1,1 @@
+<p><a href="test.html">text<table/></a> another<form/></p>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/nodetest1.out	Mon Dec 19 11:13:32 2016 +0800
@@ -0,0 +1,4 @@
+  abc def 
+line2 &amp;a 
+ test
+ 
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/nodetest1.txt	Mon Dec 19 11:13:32 2016 +0800
@@ -0,0 +1,4 @@
+  abc def 
+line2 &a 
+ test
+ 
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/nodetest2.out	Mon Dec 19 11:13:32 2016 +0800
@@ -0,0 +1,19 @@
+<root>
+     t
+t   
+    <child1/>
+    t
+    <child2/>
+    <child3/>
+    <child4/>
+    <child5>
+        t
+        <child51>
+            <child511>t</child511>
+        </child51>
+        t
+    </child5>
+    <!-- test comment -->
+    <!-- -->
+    <?target1 test?>
+</root>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest1.out	Mon Dec 19 11:13:32 2016 +0800
@@ -0,0 +1,3 @@
+<a>
+    <![CDATA[ ]]>
+</a>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest1.xml	Mon Dec 19 11:13:32 2016 +0800
@@ -0,0 +1,1 @@
+<a><![CDATA[ ]]></a>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest2.out	Mon Dec 19 11:13:32 2016 +0800
@@ -0,0 +1,5 @@
+<a>
+    <![CDATA[  abc def 
+line2 &a 
+ test]]>
+</a>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest2.xml	Mon Dec 19 11:13:32 2016 +0800
@@ -0,0 +1,3 @@
+<a><![CDATA[  abc def 
+line2 &a 
+ test]]></a>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest3.out	Mon Dec 19 11:13:32 2016 +0800
@@ -0,0 +1,5 @@
+<rss version="2.0">
+    <ns:test id="i001">
+        <ns:child/>
+    </ns:test>
+</rss>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest3.xml	Mon Dec 19 11:13:32 2016 +0800
@@ -0,0 +1,1 @@
+<rss version="2.0"><ns:test id='i001'><ns:child></ns:child></ns:test></rss>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest4.out	Mon Dec 19 11:13:32 2016 +0800
@@ -0,0 +1,6 @@
+<rss version="2.0">
+    <ns:test id="i001">
+        <ns:child>child1</ns:child>
+        <test att1="v1">  abc test</test>
+    </ns:test>
+</rss>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest4.xml	Mon Dec 19 11:13:32 2016 +0800
@@ -0,0 +1,1 @@
+<rss version="2.0"><ns:test id='i001'><ns:child>child1</ns:child><test att1='v1'>  abc test</test></ns:test></rss>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest5.out	Mon Dec 19 11:13:32 2016 +0800
@@ -0,0 +1,10 @@
+<rss version="2.0">
+    <channel>
+        <title>Java Tutorials and Examples 1</title>
+        <language>en-us</language>
+    </channel>
+    <a>
+        <b/>
+    </a>
+    <c/>
+</rss>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest5.xml	Mon Dec 19 11:13:32 2016 +0800
@@ -0,0 +1,3 @@
+<rss version="2.0"><channel> <title>Java Tutorials and Examples 1</title> <language>en-us</language></channel><a><b> </b></a> <c>
+ 
+</c></rss>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest6.out	Mon Dec 19 11:13:32 2016 +0800
@@ -0,0 +1,3 @@
+<rss version="2.0">
+    <channel xml:space="preserve"> <title>Java Tutorials and Examples 1</title> <language>en-us</language></channel>
+</rss>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest6.xml	Mon Dec 19 11:13:32 2016 +0800
@@ -0,0 +1,1 @@
+<rss version="2.0"><channel xml:space="preserve"> <title>Java Tutorials and Examples 1</title> <language>en-us</language></channel></rss>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest7.out	Mon Dec 19 11:13:32 2016 +0800
@@ -0,0 +1,10 @@
+<rss>
+    <layer1 xml:space="preserve"> <title>Java </title> <layer2 xml:space="asfsa"> <layer3> <layer4 xml:space="default">
+                    <l5>5</l5>
+                </layer4> </layer3> </layer2> <layer2 xml:space="default">
+            <layer3>
+                <l4/>
+            </layer3>
+            <layer3 xml:space="preserve"> <l4> </l4> </layer3>
+        </layer2> </layer1>
+</rss>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest7.xml	Mon Dec 19 11:13:32 2016 +0800
@@ -0,0 +1,2 @@
+<rss><layer1 xml:space="preserve"> <title>Java </title> <layer2 xml:space="asfsa"> <layer3> <layer4 xml:space="default"> <l5>5</l5> 
+ </layer4> </layer3> </layer2> <layer2 xml:space="default"> <layer3> <l4> </l4> </layer3> <layer3 xml:space="preserve"> <l4> </l4> </layer3></layer2> </layer1></rss>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest8.out	Mon Dec 19 11:13:32 2016 +0800
@@ -0,0 +1,25 @@
+<root>
+    
+     t
+    <![CDATA[ ]]>
+    
+t   
+    
+    <child1/>
+    
+    t
+    <!-- test comment -->
+    <child2/>
+    <child5>
+        
+        t
+        <?target1 test?>
+        <child51>
+            <child511>t</child511>
+        </child51>
+        <?target1 test?>
+        
+        t
+    
+    </child5>
+</root>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/unittest/common/prettyprint/xmltest8.xml	Mon Dec 19 11:13:32 2016 +0800
@@ -0,0 +1,15 @@
+<root>
+     t<![CDATA[ ]]>
+t   
+    <child1/>
+    t<!-- test comment -->
+    <child2/>
+    <child5>
+        t<?target1 test?>
+        <child51>
+            <child511>t</child511>
+        </child51><?target1 test?>
+        t
+    </child5>
+    
+</root> 
--- a/jaxp/test/javax/xml/jaxp/unittest/dom/ls/LSSerializerTest.java	Fri Dec 16 08:18:05 2016 +0000
+++ b/jaxp/test/javax/xml/jaxp/unittest/dom/ls/LSSerializerTest.java	Mon Dec 19 11:13:32 2016 +0800
@@ -23,6 +23,8 @@
 
 package dom.ls;
 
+import static org.w3c.dom.ls.DOMImplementationLS.MODE_SYNCHRONOUS;
+
 import java.io.IOException;
 import java.io.OutputStream;
 import java.io.StringReader;
@@ -35,22 +37,22 @@
 import org.testng.Assert;
 import org.testng.annotations.Listeners;
 import org.testng.annotations.Test;
-import org.w3c.dom.DOMConfiguration;
 import org.w3c.dom.DOMError;
 import org.w3c.dom.DOMErrorHandler;
 import org.w3c.dom.DOMImplementation;
 import org.w3c.dom.Document;
 import org.w3c.dom.ls.DOMImplementationLS;
 import org.w3c.dom.ls.LSException;
+import org.w3c.dom.ls.LSInput;
 import org.w3c.dom.ls.LSOutput;
+import org.w3c.dom.ls.LSParser;
 import org.w3c.dom.ls.LSSerializer;
 import org.xml.sax.InputSource;
 import org.xml.sax.SAXException;
 
-
 /*
  * @test
- * @bug 6439439 8080906
+ * @bug 8080906 8114834
  * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest
  * @run testng/othervm -DrunSecMngr=true dom.ls.LSSerializerTest
  * @run testng/othervm dom.ls.LSSerializerTest
@@ -58,7 +60,6 @@
  */
 @Listeners({jaxp.library.BasePolicy.class})
 public class LSSerializerTest {
-    private static final String DOM_FORMAT_PRETTY_PRINT = "format-pretty-print";
 
     class DOMErrorHandlerImpl implements DOMErrorHandler {
 
@@ -167,101 +168,6 @@
     }
 
     @Test
-    public void testFormatPrettyPrint() {
-
-        final String XML_DOCUMENT = "<?xml version=\"1.0\" encoding=\"UTF-16\"?>\n" + "<hello>" + "world" + "<child><children/><children/></child>"
-                + "</hello>";
-        /**JDK-8035467
-         * no newline in default output
-         */
-        final String XML_DOCUMENT_DEFAULT_PRINT =
-                "<?xml version=\"1.0\" encoding=\"UTF-16\"?>"
-                + "<hello>"
-                + "world"
-                + "<child><children/><children/></child>"
-                + "</hello>";
-
-        final String XML_DOCUMENT_PRETTY_PRINT = "<?xml version=\"1.0\" encoding=\"UTF-16\"?>" + "<hello>" + "world" + "<child>" + "\n" + "        "
-                + "<children/>" + "\n" + "        " + "<children/>" + "\n" + "    " + "</child>" + "\n" + "</hello>" + "\n";
-
-        // it all begins with a Document
-        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
-        DocumentBuilder documentBuilder = null;
-        try {
-            documentBuilder = documentBuilderFactory.newDocumentBuilder();
-        } catch (ParserConfigurationException parserConfigurationException) {
-            parserConfigurationException.printStackTrace();
-            Assert.fail(parserConfigurationException.toString());
-        }
-        Document document = null;
-
-        StringReader stringReader = new StringReader(XML_DOCUMENT);
-        InputSource inputSource = new InputSource(stringReader);
-        try {
-            document = documentBuilder.parse(inputSource);
-        } catch (SAXException saxException) {
-            saxException.printStackTrace();
-            Assert.fail(saxException.toString());
-        } catch (IOException ioException) {
-            ioException.printStackTrace();
-            Assert.fail(ioException.toString());
-        }
-
-        // query DOM Interfaces to get to a LSSerializer
-        DOMImplementation domImplementation = documentBuilder.getDOMImplementation();
-        DOMImplementationLS domImplementationLS = (DOMImplementationLS) domImplementation;
-        LSSerializer lsSerializer = domImplementationLS.createLSSerializer();
-
-        System.out.println("Serializer is: " + lsSerializer.getClass().getName() + " " + lsSerializer);
-
-        // get configuration
-        DOMConfiguration domConfiguration = lsSerializer.getDomConfig();
-
-        // query current configuration
-        Boolean defaultFormatPrettyPrint = (Boolean) domConfiguration.getParameter(DOM_FORMAT_PRETTY_PRINT);
-        Boolean canSetFormatPrettyPrintFalse = (Boolean) domConfiguration.canSetParameter(DOM_FORMAT_PRETTY_PRINT, Boolean.FALSE);
-        Boolean canSetFormatPrettyPrintTrue = (Boolean) domConfiguration.canSetParameter(DOM_FORMAT_PRETTY_PRINT, Boolean.TRUE);
-
-        System.out.println(DOM_FORMAT_PRETTY_PRINT + " default/can set false/can set true = " + defaultFormatPrettyPrint + "/"
-                + canSetFormatPrettyPrintFalse + "/" + canSetFormatPrettyPrintTrue);
-
-        // test values
-        Assert.assertEquals(defaultFormatPrettyPrint, Boolean.FALSE, "Default value of " + DOM_FORMAT_PRETTY_PRINT + " should be " + Boolean.FALSE);
-
-        Assert.assertEquals(canSetFormatPrettyPrintFalse, Boolean.TRUE, "Can set " + DOM_FORMAT_PRETTY_PRINT + " to " + Boolean.FALSE + " should be "
-                + Boolean.TRUE);
-
-        Assert.assertEquals(canSetFormatPrettyPrintTrue, Boolean.TRUE, "Can set " + DOM_FORMAT_PRETTY_PRINT + " to " + Boolean.TRUE + " should be "
-                + Boolean.TRUE);
-
-        // get default serialization
-        String prettyPrintDefault = lsSerializer.writeToString(document);
-        System.out.println("(default) " + DOM_FORMAT_PRETTY_PRINT + "==" + (Boolean) domConfiguration.getParameter(DOM_FORMAT_PRETTY_PRINT)
-                + ": \n\"" + prettyPrintDefault + "\"");
-
-        Assert.assertEquals(XML_DOCUMENT_DEFAULT_PRINT, prettyPrintDefault, "Invalid serialization with default value, " + DOM_FORMAT_PRETTY_PRINT + "=="
-                + (Boolean) domConfiguration.getParameter(DOM_FORMAT_PRETTY_PRINT));
-
-        // configure LSSerializer to not format-pretty-print
-        domConfiguration.setParameter(DOM_FORMAT_PRETTY_PRINT, Boolean.FALSE);
-        String prettyPrintFalse = lsSerializer.writeToString(document);
-        System.out.println("(FALSE) " + DOM_FORMAT_PRETTY_PRINT + "==" + (Boolean) domConfiguration.getParameter(DOM_FORMAT_PRETTY_PRINT)
-                + ": \n\"" + prettyPrintFalse + "\"");
-
-        Assert.assertEquals(XML_DOCUMENT_DEFAULT_PRINT, prettyPrintFalse, "Invalid serialization with FALSE value, " + DOM_FORMAT_PRETTY_PRINT + "=="
-                + (Boolean) domConfiguration.getParameter(DOM_FORMAT_PRETTY_PRINT));
-
-        // configure LSSerializer to format-pretty-print
-        domConfiguration.setParameter(DOM_FORMAT_PRETTY_PRINT, Boolean.TRUE);
-        String prettyPrintTrue = lsSerializer.writeToString(document);
-        System.out.println("(TRUE) " + DOM_FORMAT_PRETTY_PRINT + "==" + (Boolean) domConfiguration.getParameter(DOM_FORMAT_PRETTY_PRINT)
-                + ": \n\"" + prettyPrintTrue + "\"");
-
-        Assert.assertEquals(XML_DOCUMENT_PRETTY_PRINT, prettyPrintTrue, "Invalid serialization with TRUE value, " + DOM_FORMAT_PRETTY_PRINT + "=="
-                + (Boolean) domConfiguration.getParameter(DOM_FORMAT_PRETTY_PRINT));
-    }
-
-    @Test
     public void testXML11() {
 
         /**
@@ -318,4 +224,109 @@
         // output should == input
         Assert.assertEquals(XML11_DOCUMENT_OUTPUT, defaultSerialization, "Invalid serialization of XML 1.1 document: ");
     }
+
+    /*
+     * @bug 8114834 test entity reference, nested entity reference when entities
+     * is true and false
+     */
+    @Test
+    public void testEntityReference() throws Exception {
+        final String XML_DOCUMENT = "<?xml version=\"1.1\" encoding=\"UTF-16\"?>\n" +
+                "<!DOCTYPE author [\n" +
+                " <!ENTITY name \"Jo Smith\">" +
+                " <!ENTITY name1 \"&name;\">" +
+                " <!ENTITY name2 \"&name1;\">" +
+                "<!ENTITY ele \"<aa><bb>text</bb></aa>\">" +
+                " <!ENTITY ele1 \"&ele;\">" +
+                " <!ENTITY ele2 \"&ele1;\">" +
+                " ]>" +
+                " <author><a>&name1;</a>" +
+                "<b>b &name2; &name1; b</b>" +
+                "<c> &name; </c>" +
+                "<d>&ele1;d</d>" +
+                "<e> &ele2;eee </e>" +
+                "<f>&lt;att&gt;</f>" +
+                "<g> &ele; g</g>" +
+                "<h>&ele2;</h></author>" ;
+
+
+        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
+        DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
+
+        DOMImplementation domImplementation = documentBuilder.getDOMImplementation();
+        DOMImplementationLS domImplementationLS = (DOMImplementationLS) domImplementation;
+
+        LSParser domParser = domImplementationLS.createLSParser(MODE_SYNCHRONOUS, null);
+        domParser.getDomConfig().setParameter("entities", Boolean.TRUE);
+
+        LSInput src = domImplementationLS.createLSInput();
+        src.setStringData(XML_DOCUMENT);
+        Document document = domParser.parse(src);
+
+        LSSerializer lsSerializer = domImplementationLS.createLSSerializer();
+
+        lsSerializer.getDomConfig().setParameter("format-pretty-print", true);
+        System.out.println("test with default entities is " + lsSerializer.getDomConfig().getParameter("entities"));
+        Assert.assertEquals(lsSerializer.writeToString(document),
+                "<?xml version=\"1.1\" encoding=\"UTF-16\"?><!DOCTYPE author [ \n" +
+                "<!ENTITY name 'Jo Smith'>\n" +
+                "<!ENTITY name1 '&name;'>\n" +
+                "<!ENTITY name2 '&name1;'>\n" +
+                "<!ENTITY ele '<aa><bb>text</bb></aa>'>\n" +
+                "<!ENTITY ele1 '&ele;'>\n" +
+                "<!ENTITY ele2 '&ele1;'>\n" +
+                "]>\n" +
+                "<author>\n" +
+                "    <a>&name1;Jo Smith</a>\n" +
+                "    <b>b &name2;Jo Smith &name1;Jo Smith b</b>\n" +
+                "    <c> &name;Jo Smith </c>\n" +
+                "    <d>&ele1;d</d>\n" +
+                "    <e> &ele2;eee </e>\n" +
+                "    <f>&lt;att&gt;</f>\n" +
+                "    <g> &ele; g</g>\n" +
+                "    <h>&ele2;</h>\n" +
+                "</author>\n");
+
+        lsSerializer.getDomConfig().setParameter("entities", Boolean.FALSE);
+        System.out.println("test with entities is false");
+        Assert.assertEquals(lsSerializer.writeToString(document),
+                "<?xml version=\"1.1\" encoding=\"UTF-16\"?><!DOCTYPE author [ \n" +
+                "<!ENTITY name 'Jo Smith'>\n" +
+                "<!ENTITY name1 '&name;'>\n" +
+                "<!ENTITY name2 '&name1;'>\n" +
+                "<!ENTITY ele '<aa><bb>text</bb></aa>'>\n" +
+                "<!ENTITY ele1 '&ele;'>\n" +
+                "<!ENTITY ele2 '&ele1;'>\n" +
+                "]>\n" +
+                "<author>\n" +
+                "    <a>&name;Jo Smith</a>\n" +
+                "    <b>b &name;Jo Smith &name;Jo Smith b</b>\n" +
+                "    <c> &name;Jo Smith </c>\n" +
+                "    <d>\n" +
+                "        <aa>\n" +
+                "            <bb>text</bb>\n" +
+                "        </aa>\n" +
+                "        d\n" +
+                "    </d>\n" +
+                "    <e>\n" +
+                "        <aa>\n" +
+                "            <bb>text</bb>\n" +
+                "        </aa>\n" +
+                "        eee \n" +
+                "    </e>\n" +
+                "    <f>&lt;att&gt;</f>\n" +
+                "    <g>\n" +
+                "        <aa>\n" +
+                "            <bb>text</bb>\n" +
+                "        </aa>\n" +
+                "         g\n" +
+                "    </g>\n" +
+                "    <h>\n" +
+                "        <aa>\n" +
+                "            <bb>text</bb>\n" +
+                "        </aa>\n" +
+                "    </h>\n" +
+                "</author>\n");
+
+    }
 }