All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.mozilla.javascript.xmlimpl.XmlProcessor Maven / Gradle / Ivy

The newest version!
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package org.mozilla.javascript.xmlimpl;

import org.w3c.dom.*;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.ParserConfigurationException;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.util.List;
import java.util.ArrayList;
import java.util.concurrent.LinkedBlockingDeque;

import org.mozilla.javascript.*;

//    Disambiguate from org.mozilla.javascript.Node
import org.w3c.dom.Node;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXParseException;

class XmlProcessor implements Serializable {

    private static final long serialVersionUID = 6903514433204808713L;

    private boolean ignoreComments;
    private boolean ignoreProcessingInstructions;
    private boolean ignoreWhitespace;
    private boolean prettyPrint;
    private int prettyIndent;

    private transient javax.xml.parsers.DocumentBuilderFactory dom;
    private transient javax.xml.transform.TransformerFactory xform;
    private transient LinkedBlockingDeque documentBuilderPool;
    private RhinoSAXErrorHandler errorHandler = new RhinoSAXErrorHandler();

    private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
        stream.defaultReadObject();
        this.dom = javax.xml.parsers.DocumentBuilderFactory.newInstance();
        this.dom.setNamespaceAware(true);
        this.dom.setIgnoringComments(false);
        this.xform = javax.xml.transform.TransformerFactory.newInstance();
        int poolSize = Runtime.getRuntime().availableProcessors() * 2;
        this.documentBuilderPool = new LinkedBlockingDeque(poolSize);
    }

    private static class RhinoSAXErrorHandler implements ErrorHandler, Serializable {

        private static final long serialVersionUID = 6918417235413084055L;

        private void throwError(SAXParseException e) {
            throw ScriptRuntime.constructError("TypeError", e.getMessage(),
                e.getLineNumber() - 1);
        }

        public void error(SAXParseException e) {
            throwError(e);
        }

        public void fatalError(SAXParseException e) {
            throwError(e);
        }

        public void warning(SAXParseException e) {
            Context.reportWarning(e.getMessage());
        }
    }

    XmlProcessor() {
        setDefault();
        this.dom = javax.xml.parsers.DocumentBuilderFactory.newInstance();
        this.dom.setNamespaceAware(true);
        this.dom.setIgnoringComments(false);
        this.xform = javax.xml.transform.TransformerFactory.newInstance();
        int poolSize = Runtime.getRuntime().availableProcessors() * 2;
        this.documentBuilderPool = new LinkedBlockingDeque(poolSize);
    }

    final void setDefault() {
        this.setIgnoreComments(true);
        this.setIgnoreProcessingInstructions(true);
        this.setIgnoreWhitespace(true);
        this.setPrettyPrinting(true);
        this.setPrettyIndent(2);
    }

    final void setIgnoreComments(boolean b) {
        this.ignoreComments = b;
    }

    final void setIgnoreWhitespace(boolean b) {
        this.ignoreWhitespace = b;
    }

    final void setIgnoreProcessingInstructions(boolean b) {
        this.ignoreProcessingInstructions = b;
    }

    final void setPrettyPrinting(boolean b) {
        this.prettyPrint = b;
    }

    final void setPrettyIndent(int i) {
        this.prettyIndent = i;
    }

    final boolean isIgnoreComments() {
        return ignoreComments;
    }

    final boolean isIgnoreProcessingInstructions() {
        return ignoreProcessingInstructions;
    }

    final boolean isIgnoreWhitespace() {
        return ignoreWhitespace;
    }

    final boolean isPrettyPrinting() {
        return prettyPrint;
    }

    final int getPrettyIndent() {
        return prettyIndent;
    }

    private String toXmlNewlines(String rv) {
        StringBuilder nl = new StringBuilder();
        for (int i=0; i list, Node node) {
        if (node instanceof ProcessingInstruction) {
            list.add(node);
        }
        if (node.getChildNodes() != null) {
            for (int i=0; i list, Node node) {
        if (node instanceof Comment) {
            list.add(node);
        }
        if (node.getChildNodes() != null) {
            for (int i=0; i toRemove, Node node) {
        if (node instanceof Text) {
            Text text = (Text)node;
            boolean BUG_369394_IS_VALID = false;
            if (!BUG_369394_IS_VALID) {
                text.setData(text.getData().trim());
            } else {
                if (text.getData().trim().length() == 0) {
                    text.setData("");
                }
            }
            if (text.getData().length() == 0) {
                toRemove.add(node);
            }
        }
        if (node.getChildNodes() != null) {
            for (int i=0; i" + xml + "";
            builder = getDocumentBuilderFromPool();
            Document document = builder.parse( new org.xml.sax.InputSource(new java.io.StringReader(syntheticXml)) );
            if (ignoreProcessingInstructions) {
                List list = new java.util.ArrayList();
                addProcessingInstructionsTo(list, document);
                for (Node node: list) {
                    node.getParentNode().removeChild(node);
                }
            }
            if (ignoreComments) {
                List list = new java.util.ArrayList();
                addCommentsTo(list, document);
                for (Node node: list) {
                    node.getParentNode().removeChild(node);
                }
            }
            if (ignoreWhitespace) {
                //    Apparently JAXP setIgnoringElementContentWhitespace() has a different meaning, it appears from the Javadoc
                //    Refers to element-only content models, which means we would need to have a validating parser and DTD or schema
                //    so that it would know which whitespace to ignore.

                //    Instead we will try to delete it ourselves.
                List list = new java.util.ArrayList();
                addTextNodesToRemoveAndTrim(list, document);
                for (Node node: list) {
                    node.getParentNode().removeChild(node);
                }
            }
            NodeList rv = document.getDocumentElement().getChildNodes();
            if (rv.getLength() > 1) {
                throw ScriptRuntime.constructError("SyntaxError", "XML objects may contain at most one node.");
            } else if (rv.getLength() == 0) {
                Node node = document.createTextNode("");
                return node;
            } else {
                Node node = rv.item(0);
                document.getDocumentElement().removeChild(node);
                return node;
            }
        } catch (java.io.IOException e) {
            throw new RuntimeException("Unreachable.");
        } catch (javax.xml.parsers.ParserConfigurationException e) {
            throw new RuntimeException(e);
        } finally {
            if (builder != null)
                returnDocumentBuilderToPool(builder);
        }
    }

    Document newDocument() {
        DocumentBuilder builder = null;
        try {
            //    TODO    Should this use XML settings?
            builder = getDocumentBuilderFromPool();
            return builder.newDocument();
        } catch (javax.xml.parsers.ParserConfigurationException ex) {
            //    TODO    How to handle these runtime errors?
            throw new RuntimeException(ex);
        } finally {
            if (builder != null)
                returnDocumentBuilderToPool(builder);
        }
    }

    //    TODO    Cannot remember what this is for, so whether it should use settings or not
    private String toString(Node node) {
        javax.xml.transform.dom.DOMSource source = new javax.xml.transform.dom.DOMSource(node);
        java.io.StringWriter writer = new java.io.StringWriter();
        javax.xml.transform.stream.StreamResult result = new javax.xml.transform.stream.StreamResult(writer);
        try {
            javax.xml.transform.Transformer transformer = xform.newTransformer();
            transformer.setOutputProperty(javax.xml.transform.OutputKeys.OMIT_XML_DECLARATION, "yes");
            transformer.setOutputProperty(javax.xml.transform.OutputKeys.INDENT, "no");
            transformer.setOutputProperty(javax.xml.transform.OutputKeys.METHOD, "xml");
            transformer.transform(source, result);
        } catch (javax.xml.transform.TransformerConfigurationException ex) {
            //    TODO    How to handle these runtime errors?
            throw new RuntimeException(ex);
        } catch (javax.xml.transform.TransformerException ex) {
            //    TODO    How to handle these runtime errors?
            throw new RuntimeException(ex);
        }
        return toXmlNewlines(writer.toString());
    }

    String escapeAttributeValue(Object value) {
        String text = ScriptRuntime.toString(value);

        if (text.length() == 0) return "";

        Document dom = newDocument();
        Element e = dom.createElement("a");
        e.setAttribute("b", text);
        String elementText = toString(e);
        int begin = elementText.indexOf('"');
        int end = elementText.lastIndexOf('"');
        return elementText.substring(begin+1,end);
    }

    String escapeTextValue(Object value) {
        if (value instanceof XMLObjectImpl) {
            return ((XMLObjectImpl)value).toXMLString();
        }

        String text = ScriptRuntime.toString(value);

        if (text.length() == 0) return text;

        Document dom = newDocument();
        Element e = dom.createElement("a");
        e.setTextContent(text);
        String elementText = toString(e);

        int begin = elementText.indexOf('>') + 1;
        int end = elementText.lastIndexOf('<');
        return (begin < end) ? elementText.substring(begin, end) : "";
    }

    private String escapeElementValue(String s) {
        //    TODO    Check this
        return escapeTextValue(s);
    }

    private String elementToXmlString(Element element) {
        //    TODO    My goodness ECMA is complicated (see 10.2.1).  We'll try this first.
        Element copy = (Element)element.cloneNode(true);
        if (prettyPrint) {
            beautifyElement(copy, 0);
        }
        return toString(copy);
    }

    final String ecmaToXmlString(Node node) {
        //    See ECMA 357 Section 10.2.1
        StringBuilder s = new StringBuilder();
        int indentLevel = 0;
        if (prettyPrint) {
            for (int i=0; i");
            return s.toString();
        }
        if (node instanceof ProcessingInstruction) {
            ProcessingInstruction pi = (ProcessingInstruction)node;
            s.append("");
            return s.toString();
        }
        s.append(elementToXmlString((Element)node));
        return s.toString();
    }

    private void beautifyElement(Element e, int indent) {
        StringBuilder s = new StringBuilder();
        s.append('\n');
        for (int i=0; i toIndent = new ArrayList();
        boolean indentChildren = false;
        for (int i=0; i list = new ArrayList();
        for (int i=0; i < nodes.getLength(); i++) {
            if (nodes.item(i) instanceof Element) {
                list.add((Element)nodes.item(i));
            }
        }
        for (Element elem: list) {
            beautifyElement(elem, indent + prettyIndent);
        }
        if (indentChildren) {
            e.appendChild(e.getOwnerDocument().createTextNode(afterContent));
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy