mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			855 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			855 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			Java
		
	
	
	
/* StreamSerializer.java --
 | 
						|
   Copyright (C) 2004,2006 Free Software Foundation, Inc.
 | 
						|
 | 
						|
This file is part of GNU Classpath.
 | 
						|
 | 
						|
GNU Classpath is free software; you can redistribute it and/or modify
 | 
						|
it under the terms of the GNU General Public License as published by
 | 
						|
the Free Software Foundation; either version 2, or (at your option)
 | 
						|
any later version.
 | 
						|
 | 
						|
GNU Classpath 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 for more details.
 | 
						|
 | 
						|
You should have received a copy of the GNU General Public License
 | 
						|
along with GNU Classpath; see the file COPYING.  If not, write to the
 | 
						|
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 | 
						|
02110-1301 USA.
 | 
						|
 | 
						|
Linking this library statically or dynamically with other modules is
 | 
						|
making a combined work based on this library.  Thus, the terms and
 | 
						|
conditions of the GNU General Public License cover the whole
 | 
						|
combination.
 | 
						|
 | 
						|
As a special exception, the copyright holders of this library give you
 | 
						|
permission to link this library with independent modules to produce an
 | 
						|
executable, regardless of the license terms of these independent
 | 
						|
modules, and to copy and distribute the resulting executable under
 | 
						|
terms of your choice, provided that you also meet, for each linked
 | 
						|
independent module, the terms and conditions of the license of that
 | 
						|
module.  An independent module is a module which is not derived from
 | 
						|
or based on this library.  If you modify this library, you may extend
 | 
						|
this exception to your version of the library, but you are not
 | 
						|
obligated to do so.  If you do not wish to do so, delete this
 | 
						|
exception statement from your version. */
 | 
						|
 | 
						|
package gnu.xml.transform;
 | 
						|
 | 
						|
import gnu.java.lang.CPStringBuilder;
 | 
						|
 | 
						|
import java.io.ByteArrayOutputStream;
 | 
						|
import java.io.IOException;
 | 
						|
import java.io.OutputStream;
 | 
						|
import java.nio.ByteBuffer;
 | 
						|
import java.nio.CharBuffer;
 | 
						|
import java.nio.charset.Charset;
 | 
						|
import java.nio.charset.CharsetEncoder;
 | 
						|
import java.util.Collection;
 | 
						|
import java.util.Collections;
 | 
						|
import java.util.HashMap;
 | 
						|
import java.util.HashSet;
 | 
						|
import java.util.Iterator;
 | 
						|
import java.util.LinkedList;
 | 
						|
import java.util.Map;
 | 
						|
import javax.xml.XMLConstants;
 | 
						|
import org.w3c.dom.Attr;
 | 
						|
import org.w3c.dom.Document;
 | 
						|
import org.w3c.dom.DocumentType;
 | 
						|
import org.w3c.dom.NamedNodeMap;
 | 
						|
import org.w3c.dom.Node;
 | 
						|
 | 
						|
/**
 | 
						|
 * Serializes a DOM node to an output stream.
 | 
						|
 *
 | 
						|
 * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
 | 
						|
 */
 | 
						|
public class StreamSerializer
 | 
						|
{
 | 
						|
 | 
						|
  static final int SPACE = 0x20;
 | 
						|
  static final int BANG = 0x21; // !
 | 
						|
  static final int APOS = 0x27; // '
 | 
						|
  static final int SLASH = 0x2f; // /
 | 
						|
  static final int BRA = 0x3c; // <
 | 
						|
  static final int KET = 0x3e; // >
 | 
						|
  static final int EQ = 0x3d; // =
 | 
						|
 | 
						|
  /**
 | 
						|
   * HTML 4.01 boolean attributes
 | 
						|
   */
 | 
						|
  static final Map HTML_BOOLEAN_ATTRIBUTES = new HashMap();
 | 
						|
  static
 | 
						|
  {
 | 
						|
    HashSet set;
 | 
						|
 | 
						|
    set = new HashSet();
 | 
						|
    set.add("nohref");
 | 
						|
    HTML_BOOLEAN_ATTRIBUTES.put("area", set);
 | 
						|
 | 
						|
    set = new HashSet();
 | 
						|
    set.add("ismap");
 | 
						|
    HTML_BOOLEAN_ATTRIBUTES.put("img", set);
 | 
						|
 | 
						|
    set = new HashSet();
 | 
						|
    set.add("declare");
 | 
						|
    HTML_BOOLEAN_ATTRIBUTES.put("object", set);
 | 
						|
 | 
						|
    set = new HashSet();
 | 
						|
    set.add("noshade");
 | 
						|
    HTML_BOOLEAN_ATTRIBUTES.put("hr", set);
 | 
						|
 | 
						|
    set = new HashSet();
 | 
						|
    set.add("compact");
 | 
						|
    HTML_BOOLEAN_ATTRIBUTES.put("dl", set);
 | 
						|
    HTML_BOOLEAN_ATTRIBUTES.put("ol", set);
 | 
						|
    HTML_BOOLEAN_ATTRIBUTES.put("ul", set);
 | 
						|
    HTML_BOOLEAN_ATTRIBUTES.put("dir", set);
 | 
						|
    HTML_BOOLEAN_ATTRIBUTES.put("menu", set);
 | 
						|
 | 
						|
    set = new HashSet();
 | 
						|
    set.add("checked");
 | 
						|
    set.add("disabled");
 | 
						|
    set.add("readonly");
 | 
						|
    set.add("ismap");
 | 
						|
    HTML_BOOLEAN_ATTRIBUTES.put("input", set);
 | 
						|
 | 
						|
    set = new HashSet();
 | 
						|
    set.add("multiple");
 | 
						|
    set.add("disabled");
 | 
						|
    HTML_BOOLEAN_ATTRIBUTES.put("select", set);
 | 
						|
 | 
						|
    set = new HashSet();
 | 
						|
    set.add("disabled");
 | 
						|
    HTML_BOOLEAN_ATTRIBUTES.put("optgroup", set);
 | 
						|
 | 
						|
    set = new HashSet();
 | 
						|
    set.add("selected");
 | 
						|
    set.add("disabled");
 | 
						|
    HTML_BOOLEAN_ATTRIBUTES.put("option", set);
 | 
						|
 | 
						|
    set = new HashSet();
 | 
						|
    set.add("disabled");
 | 
						|
    set.add("readonly");
 | 
						|
    HTML_BOOLEAN_ATTRIBUTES.put("textarea", set);
 | 
						|
 | 
						|
    set = new HashSet();
 | 
						|
    set.add("disabled");
 | 
						|
    HTML_BOOLEAN_ATTRIBUTES.put("button", set);
 | 
						|
 | 
						|
    set = new HashSet();
 | 
						|
    set.add("nowrap");
 | 
						|
    HTML_BOOLEAN_ATTRIBUTES.put("th", set);
 | 
						|
    HTML_BOOLEAN_ATTRIBUTES.put("td", set);
 | 
						|
 | 
						|
    set = new HashSet();
 | 
						|
    set.add("noresize");
 | 
						|
    HTML_BOOLEAN_ATTRIBUTES.put("frame", set);
 | 
						|
 | 
						|
    set = new HashSet();
 | 
						|
    set.add("defer");
 | 
						|
    HTML_BOOLEAN_ATTRIBUTES.put("script", set);
 | 
						|
  }
 | 
						|
 | 
						|
  // HTML namespace URIs
 | 
						|
  static final HashSet HTML_URIS = new HashSet();
 | 
						|
  static {
 | 
						|
    HTML_URIS.add("http://www.w3.org/1999/xhtml");
 | 
						|
  }
 | 
						|
 | 
						|
  protected final String encoding;
 | 
						|
  final Charset charset;
 | 
						|
  final CharsetEncoder encoder;
 | 
						|
  final int mode;
 | 
						|
  final LinkedList namespaces;
 | 
						|
  protected String eol;
 | 
						|
  Collection cdataSectionElements = Collections.EMPTY_SET;
 | 
						|
 | 
						|
  protected boolean discardDefaultContent;
 | 
						|
  protected boolean xmlDeclaration = true;
 | 
						|
 | 
						|
  // has a META element with the encoding been added?
 | 
						|
  private boolean htmlEncoded;
 | 
						|
 | 
						|
  public StreamSerializer()
 | 
						|
  {
 | 
						|
    this(Stylesheet.OUTPUT_XML, null, null);
 | 
						|
  }
 | 
						|
 | 
						|
  public StreamSerializer(String encoding)
 | 
						|
  {
 | 
						|
    this(Stylesheet.OUTPUT_XML, encoding, null);
 | 
						|
  }
 | 
						|
 | 
						|
  public StreamSerializer(int mode, String encoding, String eol)
 | 
						|
  {
 | 
						|
    this.mode = mode;
 | 
						|
    if (encoding == null)
 | 
						|
      encoding = (mode == Stylesheet.OUTPUT_HTML) ? "ISO-8859-1" : "UTF-8";
 | 
						|
    this.encoding = encoding.intern();
 | 
						|
    charset = Charset.forName(this.encoding);
 | 
						|
    encoder = charset.newEncoder();
 | 
						|
    this.eol = (eol != null) ? eol : System.getProperty("line.separator");
 | 
						|
    namespaces = new LinkedList();
 | 
						|
  }
 | 
						|
 | 
						|
  void setCdataSectionElements(Collection c)
 | 
						|
  {
 | 
						|
    cdataSectionElements = c;
 | 
						|
  }
 | 
						|
 | 
						|
  public void serialize(final Node node, final OutputStream out)
 | 
						|
    throws IOException
 | 
						|
  {
 | 
						|
    serialize(node, out, false);
 | 
						|
  }
 | 
						|
 | 
						|
  void serialize(Node node, final OutputStream out,
 | 
						|
                 boolean convertToCdata)
 | 
						|
    throws IOException
 | 
						|
  {
 | 
						|
    while (node != null)
 | 
						|
      {
 | 
						|
        Node next = node.getNextSibling();
 | 
						|
        doSerialize(node, out, convertToCdata);
 | 
						|
        node = next;
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  private void doSerialize(final Node node, final OutputStream out,
 | 
						|
                           boolean convertToCdata)
 | 
						|
    throws IOException
 | 
						|
  {
 | 
						|
    if (out == null)
 | 
						|
      throw new NullPointerException("no output stream");
 | 
						|
    htmlEncoded = false;
 | 
						|
    String value, prefix;
 | 
						|
    Node children;
 | 
						|
    String uri = node.getNamespaceURI();
 | 
						|
    short nt = node.getNodeType();
 | 
						|
    if (convertToCdata && nt == Node.TEXT_NODE)
 | 
						|
      nt = Node.CDATA_SECTION_NODE;
 | 
						|
    switch (nt)
 | 
						|
      {
 | 
						|
      case Node.ATTRIBUTE_NODE:
 | 
						|
        prefix = node.getPrefix();
 | 
						|
        if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(uri) ||
 | 
						|
            XMLConstants.XMLNS_ATTRIBUTE.equals(prefix) ||
 | 
						|
            (prefix != null && prefix.startsWith("xmlns:")))
 | 
						|
          {
 | 
						|
            String nsuri = node.getNodeValue();
 | 
						|
            if (isDefined(nsuri, prefix))
 | 
						|
              break;
 | 
						|
            String name = node.getLocalName();
 | 
						|
            if (name == null)
 | 
						|
              {
 | 
						|
                // Namespace-unaware
 | 
						|
                name = node.getNodeName();
 | 
						|
                int ci = name.indexOf(':');
 | 
						|
                if (ci != -1)
 | 
						|
                  name = name.substring(ci + 1);
 | 
						|
              }
 | 
						|
            define(nsuri, name);
 | 
						|
          }
 | 
						|
        else if (uri != null && !isDefined(uri, prefix))
 | 
						|
          {
 | 
						|
            prefix = define(uri, prefix);
 | 
						|
            String nsname = (prefix == null) ? "xmlns" : "xmlns:" + prefix;
 | 
						|
            out.write(SPACE);
 | 
						|
            out.write(encodeText(nsname));
 | 
						|
            out.write(EQ);
 | 
						|
            String nsvalue = "\"" + encode(uri, true, true) + "\"";
 | 
						|
            out.write(nsvalue.getBytes(encoding));
 | 
						|
          }
 | 
						|
        out.write(SPACE);
 | 
						|
        String a_nodeName = node.getNodeName();
 | 
						|
        out.write(encodeText(a_nodeName));
 | 
						|
        String a_nodeValue = node.getNodeValue();
 | 
						|
        if (mode == Stylesheet.OUTPUT_HTML &&
 | 
						|
            a_nodeName.equals(a_nodeValue) &&
 | 
						|
            isHTMLBoolean((Attr) node, a_nodeName))
 | 
						|
          break;
 | 
						|
        out.write(EQ);
 | 
						|
        value = "\"" + encode(a_nodeValue, true, true) + "\"";
 | 
						|
        out.write(encodeText(value));
 | 
						|
        break;
 | 
						|
      case Node.ELEMENT_NODE:
 | 
						|
        pushNamespaceContext();
 | 
						|
        value = node.getNodeName();
 | 
						|
        out.write(BRA);
 | 
						|
        out.write(encodeText(value));
 | 
						|
        prefix = node.getPrefix();
 | 
						|
        if (uri != null && !isDefined(uri, prefix))
 | 
						|
          {
 | 
						|
            prefix = define(uri, prefix);
 | 
						|
            String nsname = (prefix == null) ? "xmlns" : "xmlns:" + prefix;
 | 
						|
            out.write(SPACE);
 | 
						|
            out.write(encodeText(nsname));
 | 
						|
            out.write(EQ);
 | 
						|
            String nsvalue = "\"" + encode(uri, true, true) + "\"";
 | 
						|
            out.write(encodeText(nsvalue));
 | 
						|
          }
 | 
						|
        NamedNodeMap attrs = node.getAttributes();
 | 
						|
        if (attrs != null)
 | 
						|
          {
 | 
						|
            int len = attrs.getLength();
 | 
						|
            for (int i = 0; i < len; i++)
 | 
						|
              {
 | 
						|
                Attr attr = (Attr) attrs.item(i);
 | 
						|
                if (discardDefaultContent && !attr.getSpecified())
 | 
						|
                  {
 | 
						|
                    // NOOP
 | 
						|
                  }
 | 
						|
                else
 | 
						|
                  serialize(attr, out, false);
 | 
						|
              }
 | 
						|
          }
 | 
						|
        convertToCdata = cdataSectionElements.contains(value);
 | 
						|
        children = node.getFirstChild();
 | 
						|
        if (children == null)
 | 
						|
          {
 | 
						|
            out.write(SLASH);
 | 
						|
            out.write(KET);
 | 
						|
          }
 | 
						|
        else
 | 
						|
          {
 | 
						|
            out.write(KET);
 | 
						|
            serialize(children, out, convertToCdata);
 | 
						|
            out.write(BRA);
 | 
						|
            out.write(SLASH);
 | 
						|
            out.write(encodeText(value));
 | 
						|
            out.write(KET);
 | 
						|
          }
 | 
						|
        popNamespaceContext();
 | 
						|
        break;
 | 
						|
      case Node.TEXT_NODE:
 | 
						|
        value = node.getNodeValue();
 | 
						|
        if (!"yes".equals(node.getUserData("disable-output-escaping")) &&
 | 
						|
            mode != Stylesheet.OUTPUT_TEXT)
 | 
						|
          value = encode(value, false, false);
 | 
						|
        out.write(encodeText(value));
 | 
						|
        break;
 | 
						|
      case Node.CDATA_SECTION_NODE:
 | 
						|
        value = node.getNodeValue();
 | 
						|
        // Where any instanceof of ]]> occur, split into multiple CDATA
 | 
						|
        // sections
 | 
						|
        int bbk = value.indexOf("]]>");
 | 
						|
        while (bbk != -1)
 | 
						|
          {
 | 
						|
            String head = value.substring(0, bbk + 2);
 | 
						|
            out.write(encodeText("<![CDATA[" + head + "]]>"));
 | 
						|
            value = value.substring(bbk + 2);
 | 
						|
            bbk = value.indexOf("]]>");
 | 
						|
          }
 | 
						|
        // Write final tail value
 | 
						|
        out.write(encodeText("<![CDATA[" + value + "]]>"));
 | 
						|
        break;
 | 
						|
      case Node.COMMENT_NODE:
 | 
						|
        value = "<!--" + node.getNodeValue() + "-->";
 | 
						|
        out.write(encodeText(value));
 | 
						|
        Node cp = node.getParentNode();
 | 
						|
        if (cp != null && cp.getNodeType() == Node.DOCUMENT_NODE)
 | 
						|
          out.write(encodeText(eol));
 | 
						|
        break;
 | 
						|
      case Node.DOCUMENT_NODE:
 | 
						|
      case Node.DOCUMENT_FRAGMENT_NODE:
 | 
						|
        if (mode == Stylesheet.OUTPUT_XML)
 | 
						|
          {
 | 
						|
            if ("UTF-16".equalsIgnoreCase(encoding))
 | 
						|
              {
 | 
						|
                out.write(0xfe);
 | 
						|
                out.write(0xff);
 | 
						|
              }
 | 
						|
            if (!"yes".equals(node.getUserData("omit-xml-declaration")) &&
 | 
						|
                xmlDeclaration)
 | 
						|
              {
 | 
						|
                Document doc = (node instanceof Document) ?
 | 
						|
                  (Document) node : null;
 | 
						|
                String version = (doc != null) ? doc.getXmlVersion() : null;
 | 
						|
                if (version == null)
 | 
						|
                  version = (String) node.getUserData("version");
 | 
						|
                if (version == null)
 | 
						|
                  version = "1.0";
 | 
						|
                out.write(BRA);
 | 
						|
                out.write(0x3f);
 | 
						|
                out.write("xml version=\"".getBytes("US-ASCII"));
 | 
						|
                out.write(version.getBytes("US-ASCII"));
 | 
						|
                out.write(0x22);
 | 
						|
                if (!("UTF-8".equalsIgnoreCase(encoding)))
 | 
						|
                  {
 | 
						|
                    out.write(" encoding=\"".getBytes("US-ASCII"));
 | 
						|
                    out.write(encoding.getBytes("US-ASCII"));
 | 
						|
                    out.write(0x22);
 | 
						|
                  }
 | 
						|
                if ((doc != null && doc.getXmlStandalone()) ||
 | 
						|
                    "yes".equals(node.getUserData("standalone")))
 | 
						|
                  out.write(" standalone=\"yes\"".getBytes("US-ASCII"));
 | 
						|
                out.write(0x3f);
 | 
						|
                out.write(KET);
 | 
						|
                out.write(encodeText(eol));
 | 
						|
              }
 | 
						|
            // TODO warn if not outputting the declaration would be a
 | 
						|
            // problem
 | 
						|
          }
 | 
						|
        else if (mode == Stylesheet.OUTPUT_HTML)
 | 
						|
          {
 | 
						|
            // Ensure that encoding is accessible if head element is present
 | 
						|
            String mediaType = (String) node.getUserData("media-type");
 | 
						|
            if (mediaType == null)
 | 
						|
              mediaType = "text/html";
 | 
						|
            String contentType = mediaType + "; charset=" +
 | 
						|
              ((encoding.indexOf(' ') != -1) ?
 | 
						|
                "\"" + encoding + "\"" :
 | 
						|
                encoding);
 | 
						|
            Document doc = (node instanceof Document) ? (Document) node :
 | 
						|
              node.getOwnerDocument();
 | 
						|
            Node html = null;
 | 
						|
            for (Node ctx = node.getFirstChild(); ctx != null;
 | 
						|
                 ctx = ctx.getNextSibling())
 | 
						|
              {
 | 
						|
                if (ctx.getNodeType() == Node.ELEMENT_NODE &&
 | 
						|
                    isHTMLElement(ctx, "html"))
 | 
						|
                  {
 | 
						|
                    html = ctx;
 | 
						|
                    break;
 | 
						|
                  }
 | 
						|
              }
 | 
						|
            if (html != null)
 | 
						|
              {
 | 
						|
                Node head = null;
 | 
						|
                for (Node ctx = html.getFirstChild(); ctx != null;
 | 
						|
                     ctx = ctx.getNextSibling())
 | 
						|
                  {
 | 
						|
                    if (isHTMLElement(ctx, "head"))
 | 
						|
                      {
 | 
						|
                        head = ctx;
 | 
						|
                        break;
 | 
						|
                      }
 | 
						|
                  }
 | 
						|
                if (head != null)
 | 
						|
                  {
 | 
						|
                    Node meta = null;
 | 
						|
                    Node metaContent = null;
 | 
						|
                    for (Node ctx = head.getFirstChild(); ctx != null;
 | 
						|
                         ctx = ctx.getNextSibling())
 | 
						|
                      {
 | 
						|
                        if (isHTMLElement(ctx, "meta"))
 | 
						|
                          {
 | 
						|
                            NamedNodeMap metaAttrs = ctx.getAttributes();
 | 
						|
                            int len = metaAttrs.getLength();
 | 
						|
                            String httpEquiv = null;
 | 
						|
                            Node content = null;
 | 
						|
                            for (int i = 0; i < len; i++)
 | 
						|
                              {
 | 
						|
                                Node attr = metaAttrs.item(i);
 | 
						|
                                String attrName = attr.getNodeName();
 | 
						|
                                if ("http-equiv".equalsIgnoreCase(attrName))
 | 
						|
                                  httpEquiv = attr.getNodeValue();
 | 
						|
                                else if ("content".equalsIgnoreCase(attrName))
 | 
						|
                                  content = attr;
 | 
						|
                              }
 | 
						|
                            if ("Content-Type".equalsIgnoreCase(httpEquiv))
 | 
						|
                              {
 | 
						|
                                meta = ctx;
 | 
						|
                                metaContent = content;
 | 
						|
                                break;
 | 
						|
                              }
 | 
						|
                          }
 | 
						|
                      }
 | 
						|
                    if (meta == null)
 | 
						|
                      {
 | 
						|
                        meta = doc.createElement("meta");
 | 
						|
                        // Insert first
 | 
						|
                        Node first = head.getFirstChild();
 | 
						|
                        if (first == null)
 | 
						|
                          head.appendChild(meta);
 | 
						|
                        else
 | 
						|
                          head.insertBefore(meta, first);
 | 
						|
                        Node metaHttpEquiv = doc.createAttribute("http-equiv");
 | 
						|
                        meta.getAttributes().setNamedItem(metaHttpEquiv);
 | 
						|
                        metaHttpEquiv.setNodeValue("Content-Type");
 | 
						|
                      }
 | 
						|
                    if (metaContent == null)
 | 
						|
                      {
 | 
						|
                        metaContent = doc.createAttribute("content");
 | 
						|
                        meta.getAttributes().setNamedItem(metaContent);
 | 
						|
                      }
 | 
						|
                    metaContent.setNodeValue(contentType);
 | 
						|
                    htmlEncoded = true;
 | 
						|
                  }
 | 
						|
              }
 | 
						|
          }
 | 
						|
        children = node.getFirstChild();
 | 
						|
        if (children != null)
 | 
						|
          serialize(children, out, convertToCdata);
 | 
						|
        break;
 | 
						|
      case Node.DOCUMENT_TYPE_NODE:
 | 
						|
        DocumentType doctype = (DocumentType) node;
 | 
						|
        out.write(BRA);
 | 
						|
        out.write(BANG);
 | 
						|
        out.write(encodeText("DOCTYPE "));
 | 
						|
        value = doctype.getNodeName();
 | 
						|
        out.write(encodeText(value));
 | 
						|
        String publicId = doctype.getPublicId();
 | 
						|
        if (publicId != null)
 | 
						|
          {
 | 
						|
            out.write(encodeText(" PUBLIC "));
 | 
						|
            out.write(APOS);
 | 
						|
            out.write(encodeText(publicId));
 | 
						|
            out.write(APOS);
 | 
						|
          }
 | 
						|
        String systemId = doctype.getSystemId();
 | 
						|
        if (systemId != null)
 | 
						|
          {
 | 
						|
            out.write(encodeText(" SYSTEM "));
 | 
						|
            out.write(APOS);
 | 
						|
            out.write(encodeText(systemId));
 | 
						|
            out.write(APOS);
 | 
						|
          }
 | 
						|
        String internalSubset = doctype.getInternalSubset();
 | 
						|
        if (internalSubset != null)
 | 
						|
          {
 | 
						|
            out.write(encodeText(internalSubset));
 | 
						|
          }
 | 
						|
        out.write(KET);
 | 
						|
        out.write(eol.getBytes(encoding));
 | 
						|
        break;
 | 
						|
      case Node.ENTITY_REFERENCE_NODE:
 | 
						|
        value = "&" + node.getNodeValue() + ";";
 | 
						|
        out.write(encodeText(value));
 | 
						|
        break;
 | 
						|
      case Node.PROCESSING_INSTRUCTION_NODE:
 | 
						|
        value = "<?" + node.getNodeName() + " " + node.getNodeValue() + "?>";
 | 
						|
        out.write(encodeText(value));
 | 
						|
        Node pp = node.getParentNode();
 | 
						|
        if (pp != null && pp.getNodeType() == Node.DOCUMENT_NODE)
 | 
						|
          {
 | 
						|
            out.write(encodeText(eol));
 | 
						|
          }
 | 
						|
        break;
 | 
						|
      default:
 | 
						|
        System.err.println("Unhandled node type: "+nt);
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  boolean isHTMLElement(Node node, String name)
 | 
						|
  {
 | 
						|
    if (node.getNodeType() != Node.ELEMENT_NODE)
 | 
						|
      return false;
 | 
						|
    String localName = node.getLocalName();
 | 
						|
    if (localName == null)
 | 
						|
      localName = node.getNodeName();
 | 
						|
    if (!name.equalsIgnoreCase(localName))
 | 
						|
      return false;
 | 
						|
    String uri = node.getNamespaceURI();
 | 
						|
    return (uri == null || HTML_URIS.contains(uri));
 | 
						|
  }
 | 
						|
 | 
						|
  boolean isDefined(String uri, String prefix)
 | 
						|
  {
 | 
						|
    if (XMLConstants.XML_NS_URI.equals(uri))
 | 
						|
      return "xml".equals(prefix);
 | 
						|
    if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(uri))
 | 
						|
      return "xmlns".equals(prefix);
 | 
						|
    if (prefix == null)
 | 
						|
      prefix = "";
 | 
						|
    for (Iterator i = namespaces.iterator(); i.hasNext(); )
 | 
						|
      {
 | 
						|
        Map ctx = (Map) i.next();
 | 
						|
        String val = (String) ctx.get(uri);
 | 
						|
        if (val != null && val.equals(prefix))
 | 
						|
          return true;
 | 
						|
      }
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  void pushNamespaceContext()
 | 
						|
  {
 | 
						|
    namespaces.addFirst(new HashMap());
 | 
						|
  }
 | 
						|
 | 
						|
  String define(String uri, String prefix)
 | 
						|
  {
 | 
						|
    if (namespaces.isEmpty())
 | 
						|
      return prefix;
 | 
						|
    HashMap ctx = (HashMap) namespaces.getFirst();
 | 
						|
    while (ctx.containsValue(prefix))
 | 
						|
      {
 | 
						|
        // Fabricate new prefix
 | 
						|
        prefix = prefix + "_";
 | 
						|
      }
 | 
						|
    ctx.put(uri, prefix);
 | 
						|
    return prefix;
 | 
						|
  }
 | 
						|
 | 
						|
  void popNamespaceContext()
 | 
						|
  {
 | 
						|
    namespaces.removeFirst();
 | 
						|
  }
 | 
						|
 | 
						|
  final byte[] encodeText(String text)
 | 
						|
    throws IOException
 | 
						|
  {
 | 
						|
    encoder.reset();
 | 
						|
    boolean htmlNeedingEncoding =
 | 
						|
      (mode == Stylesheet.OUTPUT_HTML && !htmlEncoded);
 | 
						|
    if (!encoder.canEncode(text) || htmlNeedingEncoding)
 | 
						|
      {
 | 
						|
        // Check each character
 | 
						|
        CPStringBuilder buf = new CPStringBuilder();
 | 
						|
        int len = text.length();
 | 
						|
        for (int i = 0; i < len; i++)
 | 
						|
          {
 | 
						|
            char c = text.charAt(i);
 | 
						|
            if (!encoder.canEncode(c))
 | 
						|
              {
 | 
						|
                // Replace with character entity reference
 | 
						|
                String hex = Integer.toHexString((int) c);
 | 
						|
                buf.append("&#x");
 | 
						|
                buf.append(hex);
 | 
						|
                buf.append(';');
 | 
						|
              }
 | 
						|
            else if (htmlNeedingEncoding)
 | 
						|
              {
 | 
						|
                String entityName = getHTMLCharacterEntity(c);
 | 
						|
                if (entityName != null)
 | 
						|
                  {
 | 
						|
                    buf.append('&');
 | 
						|
                    buf.append(entityName);
 | 
						|
                    buf.append(';');
 | 
						|
                  }
 | 
						|
                else
 | 
						|
                  buf.append(c);
 | 
						|
              }
 | 
						|
            else
 | 
						|
              buf.append(c);
 | 
						|
          }
 | 
						|
        text = buf.toString();
 | 
						|
      }
 | 
						|
    ByteBuffer encoded = encoder.encode(CharBuffer.wrap(text));
 | 
						|
    int len = encoded.limit() - encoded.position();
 | 
						|
    if (encoded.hasArray())
 | 
						|
      {
 | 
						|
        byte[] ret = encoded.array();
 | 
						|
        if (ret.length > len)
 | 
						|
          {
 | 
						|
            // Why?
 | 
						|
            byte[] ret2 = new byte[len];
 | 
						|
            System.arraycopy(ret, 0, ret2, 0, len);
 | 
						|
            ret = ret2;
 | 
						|
          }
 | 
						|
        return ret;
 | 
						|
      }
 | 
						|
    encoded.flip();
 | 
						|
    byte[] ret = new byte[len];
 | 
						|
    encoded.get(ret, 0, len);
 | 
						|
    return ret;
 | 
						|
  }
 | 
						|
 | 
						|
  String encode(String text, boolean encodeCtl, boolean inAttr)
 | 
						|
  {
 | 
						|
    int len = text.length();
 | 
						|
    CPStringBuilder buf = null;
 | 
						|
    for (int i = 0; i < len; i++)
 | 
						|
      {
 | 
						|
        char c = text.charAt(i);
 | 
						|
        if (c == '<')
 | 
						|
          {
 | 
						|
            if (buf == null)
 | 
						|
              buf = new CPStringBuilder(text.substring(0, i));
 | 
						|
            buf.append("<");
 | 
						|
          }
 | 
						|
        else if (c == '>')
 | 
						|
          {
 | 
						|
            if (buf == null)
 | 
						|
              buf = new CPStringBuilder(text.substring(0, i));
 | 
						|
            buf.append(">");
 | 
						|
          }
 | 
						|
        else if (c == '&')
 | 
						|
          {
 | 
						|
            if (mode == Stylesheet.OUTPUT_HTML && (i + 1) < len &&
 | 
						|
                text.charAt(i + 1) == '{')
 | 
						|
              {
 | 
						|
                if (buf != null)
 | 
						|
                  buf.append(c);
 | 
						|
              }
 | 
						|
            else
 | 
						|
              {
 | 
						|
                if (buf == null)
 | 
						|
                  buf = new CPStringBuilder(text.substring(0, i));
 | 
						|
                buf.append("&");
 | 
						|
              }
 | 
						|
          }
 | 
						|
        else if (c == '\'' && inAttr)
 | 
						|
          {
 | 
						|
            if (buf == null)
 | 
						|
              buf = new CPStringBuilder(text.substring(0, i));
 | 
						|
            if (mode == Stylesheet.OUTPUT_HTML)
 | 
						|
              // HTML does not define ', use character entity ref
 | 
						|
              buf.append("'");
 | 
						|
            else
 | 
						|
              buf.append("'");
 | 
						|
          }
 | 
						|
        else if (c == '"' && inAttr)
 | 
						|
          {
 | 
						|
            if (buf == null)
 | 
						|
              buf = new CPStringBuilder(text.substring(0, i));
 | 
						|
            buf.append(""");
 | 
						|
          }
 | 
						|
        else if (encodeCtl)
 | 
						|
          {
 | 
						|
            if (c < 0x20)
 | 
						|
              {
 | 
						|
                if (buf == null)
 | 
						|
                  buf = new CPStringBuilder(text.substring(0, i));
 | 
						|
                buf.append('&');
 | 
						|
                buf.append('#');
 | 
						|
                buf.append((int) c);
 | 
						|
                buf.append(';');
 | 
						|
              }
 | 
						|
            else if (buf != null)
 | 
						|
              buf.append(c);
 | 
						|
          }
 | 
						|
        else if (buf != null)
 | 
						|
          buf.append(c);
 | 
						|
      }
 | 
						|
    return (buf == null) ? text : buf.toString();
 | 
						|
  }
 | 
						|
 | 
						|
  String toString(Node node)
 | 
						|
  {
 | 
						|
    ByteArrayOutputStream out = new ByteArrayOutputStream();
 | 
						|
    try
 | 
						|
      {
 | 
						|
        serialize(node, out);
 | 
						|
        return new String(out.toByteArray(), encoding);
 | 
						|
      }
 | 
						|
    catch (IOException e)
 | 
						|
      {
 | 
						|
        throw new RuntimeException(e.getMessage());
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  boolean isHTMLBoolean(Attr attr, String attrName)
 | 
						|
  {
 | 
						|
    attrName = attrName.toLowerCase();
 | 
						|
    Node element = attr.getOwnerElement();
 | 
						|
    String elementName = element.getLocalName();
 | 
						|
    if (elementName == null)
 | 
						|
      {
 | 
						|
        elementName = element.getNodeName();
 | 
						|
      }
 | 
						|
    elementName = elementName.toLowerCase();
 | 
						|
    Collection attributes =
 | 
						|
      (Collection) HTML_BOOLEAN_ATTRIBUTES.get(elementName);
 | 
						|
    return (attributes != null && attributes.contains(attrName));
 | 
						|
  }
 | 
						|
 | 
						|
  static String getHTMLCharacterEntity(char c)
 | 
						|
  {
 | 
						|
    // Hardcode these here to avoid loading the HTML DTD
 | 
						|
    switch (c)
 | 
						|
      {
 | 
						|
      case 160: return "nbsp";
 | 
						|
      case 161: return "iexcl";
 | 
						|
      case 162: return "cent";
 | 
						|
      case 163: return "pound";
 | 
						|
      case 164: return "curren";
 | 
						|
      case 165: return "yen";
 | 
						|
      case 166: return "brvbar";
 | 
						|
      case 167: return "sect";
 | 
						|
      case 168: return "uml";
 | 
						|
      case 169: return "copy";
 | 
						|
      case 170: return "ordf";
 | 
						|
      case 171: return "laquo";
 | 
						|
      case 172: return "not";
 | 
						|
      case 173: return "shy";
 | 
						|
      case 174: return "reg";
 | 
						|
      case 175: return "macr";
 | 
						|
      case 176: return "deg";
 | 
						|
      case 177: return "plusmn";
 | 
						|
      case 178: return "sup2";
 | 
						|
      case 179: return "sup3";
 | 
						|
      case 180: return "acute";
 | 
						|
      case 181: return "micro";
 | 
						|
      case 182: return "para";
 | 
						|
      case 183: return "middot";
 | 
						|
      case 184: return "cedil";
 | 
						|
      case 185: return "sup1";
 | 
						|
      case 186: return "ordm";
 | 
						|
      case 187: return "raquo";
 | 
						|
      case 188: return "frac14";
 | 
						|
      case 189: return "frac12";
 | 
						|
      case 190: return "frac34";
 | 
						|
      case 191: return "iquest";
 | 
						|
      case 192: return "Agrave";
 | 
						|
      case 193: return "Aacute";
 | 
						|
      case 194: return "Acirc";
 | 
						|
      case 195: return "Atilde";
 | 
						|
      case 196: return "Auml";
 | 
						|
      case 197: return "Aring";
 | 
						|
      case 198: return "AElig";
 | 
						|
      case 199: return "Ccedil";
 | 
						|
      case 200: return "Egrave";
 | 
						|
      case 201: return "Eacute";
 | 
						|
      case 202: return "Ecirc";
 | 
						|
      case 203: return "Euml";
 | 
						|
      case 204: return "Igrave";
 | 
						|
      case 205: return "Iacute";
 | 
						|
      case 206: return "Icirc";
 | 
						|
      case 207: return "Iuml";
 | 
						|
      case 208: return "ETH";
 | 
						|
      case 209: return "Ntilde";
 | 
						|
      case 210: return "Ograve";
 | 
						|
      case 211: return "Oacute";
 | 
						|
      case 212: return "Ocirc";
 | 
						|
      case 213: return "Otilde";
 | 
						|
      case 214: return "Ouml";
 | 
						|
      case 215: return "times";
 | 
						|
      case 216: return "Oslash";
 | 
						|
      case 217: return "Ugrave";
 | 
						|
      case 218: return "Uacute";
 | 
						|
      case 219: return "Ucirc";
 | 
						|
      case 220: return "Uuml";
 | 
						|
      case 221: return "Yacute";
 | 
						|
      case 222: return "THORN";
 | 
						|
      case 223: return "szlig";
 | 
						|
      case 224: return "agrave";
 | 
						|
      case 225: return "aacute";
 | 
						|
      case 226: return "acirc";
 | 
						|
      case 227: return "atilde";
 | 
						|
      case 228: return "auml";
 | 
						|
      case 229: return "aring";
 | 
						|
      case 230: return "aelig";
 | 
						|
      case 231: return "ccedil";
 | 
						|
      case 232: return "egrave";
 | 
						|
      case 233: return "eacute";
 | 
						|
      case 234: return "ecirc";
 | 
						|
      case 235: return "euml";
 | 
						|
      case 236: return "igrave";
 | 
						|
      case 237: return "iacute";
 | 
						|
      case 238: return "icirc";
 | 
						|
      case 239: return "iuml";
 | 
						|
      case 240: return "eth";
 | 
						|
      case 241: return "ntilde";
 | 
						|
      case 242: return "ograve";
 | 
						|
      case 243: return "oacute";
 | 
						|
      case 244: return "ocirc";
 | 
						|
      case 245: return "otilde";
 | 
						|
      case 246: return "ouml";
 | 
						|
      case 247: return "divide";
 | 
						|
      case 248: return "oslash";
 | 
						|
      case 249: return "ugrave";
 | 
						|
      case 250: return "uacute";
 | 
						|
      case 251: return "ucirc";
 | 
						|
      case 252: return "uuml";
 | 
						|
      case 253: return "yacute";
 | 
						|
      case 254: return "thorn";
 | 
						|
      case 255: return "yuml";
 | 
						|
      default: return null;
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
}
 |