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

org.integratedmodelling.utils.xml.XMLDocument Maven / Gradle / Ivy

The newest version!
/*******************************************************************************
 *  Copyright (C) 2007, 2014:
 *  
 *    - Ferdinando Villa 
 *    - integratedmodelling.org
 *    - any other authors listed in @author annotations
 *
 *    All rights reserved. This file is part of the k.LAB software suite,
 *    meant to enable modular, collaborative, integrated 
 *    development of interoperable data and model components. For
 *    details, see http://integratedmodelling.org.
 *    
 *    This program is free software; you can redistribute it and/or
 *    modify it under the terms of the Affero General Public License 
 *    Version 3 or any later version.
 *
 *    This program 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
 *    Affero General Public License for more details.
 *  
 *     You should have received a copy of the Affero General Public License
 *     along with this program; if not, write to the Free Software
 *     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *     The license is also available at: https://www.gnu.org/licenses/agpl.html
 *******************************************************************************/
package org.integratedmodelling.utils.xml;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.StringWriter;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

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.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.apache.xerces.parsers.DOMParser;
import org.integratedmodelling.collections.Pair;
import org.integratedmodelling.exceptions.KlabException;
import org.integratedmodelling.exceptions.KlabIOException;
import org.integratedmodelling.exceptions.KlabRuntimeException;
import org.integratedmodelling.exceptions.KlabValidationException;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.ProcessingInstruction;
import org.xml.sax.InputSource;

/**
 * Trivial helper class to wrap the read/write interface for an XML file without having to remember too much. 
 * Non-ADD people need not apply.
 * 
 * Write operations will fail if the document has been read from a non-writable source (a 
 * write protected file or a remote URL).
 * 
 * @author Ferdinando Villa
 */
public class XMLDocument {

    DOMParser parser;
    Document  dom;
    String    namespace  = null;
    boolean   isWritable = false;
    boolean   needsWrite = false;
    File      docFile    = null;
    Element   root       = null;

    public class NodeIterator implements Iterator {

        Node _current = null;

        public NodeIterator(Node node) {
            _current = node.getFirstChild();
        }

        @Override
        public boolean hasNext() {
            return _current != null;
        }

        @Override
        public Node next() {
            Node ret = _current;
            _current = _current.getNextSibling();

            if (ret == null)
                System.out.println("FUCK I'M RETURNING A FUCKING NULL");
            return ret;
        }

        @Override
        public void remove() {
            throw new KlabRuntimeException("Node iterator is read only");
        }

    }

    public NodeIterator iterator() {
        return new NodeIterator(root());
    }

    public NodeIterator iterator(Node node) {
        return new NodeIterator(node);
    }

    public XMLDocument(String rootNode) throws KlabValidationException {

        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder docBuilder = null;
        try {
            docBuilder = factory.newDocumentBuilder();
        } catch (ParserConfigurationException e) {
            throw new KlabValidationException(e);
        }
        dom = docBuilder.newDocument();
        root = dom.createElement(rootNode);
        dom.appendChild(root);

    }

    public XMLDocument(File f) throws KlabIOException {
        createFromFile(f, null);
    }

    public XMLDocument(URL f) throws KlabIOException {
        createFromUrl(f);
    }

    public XMLDocument(File f, String namespace) throws KlabIOException {
        createFromFile(f, namespace);
    }

    public Node createNode(String tag, Node parent) {

        Node ret = null;
        ret = dom.createElement(tag);
        parent.appendChild(ret);
        return ret;
    }

    public void addNamespace(String ns, String uri) {

        // if (uri.endsWith("#")) {
        // uri = uri.substring(0, uri.length()-1);
        // }

        Attr ret = dom.createAttributeNS(uri, ns);
        root.setAttributeNode(ret);
    }

    public void addAttribute(Node parent, String aName, String aValue) {

        if (parent instanceof Element) {
            Attr ret = dom.createAttribute(aName);
            ret.setValue(aValue);
            ((Element) parent).setAttributeNode(ret);
        }
    }

    private void createFromUrl(URL url) throws KlabIOException {

        // if (!NetUtilities.urlResponds(url.toString())) {
        // throw new ThinklabIOException(e);
        // }

        InputStream is = null;
        try {
            is = url.openStream();
        } catch (IOException e) {
            throw new KlabIOException(e);
        }
        createFromInputStream(is);

        try {
            is.close();
        } catch (IOException e) {
            throw new KlabIOException(e);
        }
    }

    private void createFromInputStream(InputStream is) throws KlabIOException {

        parser = new DOMParser();
        try {
            parser.setFeature("http://xml.org/sax/features/namespaces", true);
            parser.parse(new InputSource(is));
        } catch (Exception e) {
            throw new KlabIOException(e);
        }
        dom = parser.getDocument();
    }

    private void createFromFile(File f, String namespace) throws KlabIOException {

        this.namespace = namespace;
        this.docFile = f;

        if (!f.exists()) {

            /* create XML document */
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            factory.setNamespaceAware(namespace != null);
            try {
                dom = factory.newDocumentBuilder().newDocument();
            } catch (ParserConfigurationException e) {
                /* why in the world should this happen? */
            }
            isWritable = new File(f.getParent()).canWrite();
        } else {

            isWritable = f.canWrite();

            FileInputStream is;
            try {
                is = new FileInputStream(f);
            } catch (FileNotFoundException e) {
                throw new KlabIOException(e);
            }

            createFromInputStream(is);

            try {
                is.close();
            } catch (IOException e) {
                throw new KlabIOException(e);
            }
        }
    }

    @Override
    protected void finalize() throws KlabIOException {
        if (needsWrite)
            flush();
    }

    public XMLDocument(InputStream is) throws KlabException {
        parser = new DOMParser();
        try {
            parser.setFeature("http://xml.org/sax/features/namespaces", true);
            parser.parse(new InputSource(is));
        } catch (Exception e) {
            throw new KlabValidationException(e);
        }
        dom = parser.getDocument();
    }

    public Element root() {
        return root == null ? dom.getDocumentElement() : root;
    }

    public void flush() throws KlabIOException {

        Transformer transformer = null;
        try {
            transformer = TransformerFactory.newInstance().newTransformer();
        } catch (Exception e) {
            throw new KlabIOException(e);
        }
        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
        StreamResult result = new StreamResult(docFile);
        DOMSource source = new DOMSource(dom);
        try {
            transformer.transform(source, result);
        } catch (TransformerException e) {
            throw new KlabIOException(e);
        }
    }

    /**
     * Take a xml element and the tag name, look for the tag and get
     * the text content 
     * i.e for John xml snippet if
     * the Element points to employee node and tagName is name I will return John  
     * @param ele
     * @param tagName
     * @return the string value.
     */
    public static String getTextValue(Element ele, String tagName) {
        String textVal = null;
        NodeList nl = ele.getElementsByTagName(tagName);
        if (nl != null && nl.getLength() > 0) {
            Element el = (Element) nl.item(0);
            textVal = el.getFirstChild().getNodeValue();
        }

        return textVal;
    }

    public static String getTextValue(Element ele, String tagName, String optionalPrefix) {

        String ret = getTextValue(ele, tagName);
        if (ret == null) {
            ret = getTextValue(ele, optionalPrefix + ":" + tagName);
        }
        return ret;
    }

    public static String getNodeValue(Node node) {
        StringBuffer buf = new StringBuffer();
        NodeList children = node.getChildNodes();
        for (int i = 0; i < children.getLength(); i++) {
            Node textChild = children.item(i);
            if (textChild.getNodeType() != Node.TEXT_NODE
                    && textChild.getNodeType() != Node.CDATA_SECTION_NODE) {
                continue;
            }
            buf.append(textChild.getNodeValue());
        }
        return buf.toString();
    }

    /**
     * Calls getTextValue and returns a int value
     * @param ele
     * @param tagName
     * @return the int value
     */
    public static int getIntValue(Element ele, String tagName) {
        // in production application you would catch the exception
        return Integer.parseInt(getTextValue(ele, tagName));
    }

    /**
     * Extract attribute string value from node.
     * @param n the Node
     * @param attr the attribute name
     * @return attribute value, or null if not there.
     */
    public static String getAttributeValue(Node n, String attr) {

        String ret = null;

        if (n.hasAttributes()) {
            Node nn = n.getAttributes().getNamedItem(attr);
            if (nn != null)
                ret = nn.getTextContent();
        }

        return ret;
    }

    /**
     * Return the given attribute value or the given default parameter if not there.
     * @param n
     * @param attr
     * @param defval
     * @return attribute value
     */
    public static String getAttributeValue(Node n, String attr, String defval) {
        String ret = getAttributeValue(n, attr);
        return ret == null ? defval : ret;
    }

    public static Node getChildNode(Node nn, String string) {
        Node ret = null;
        for (Node n = nn.getFirstChild(); n != null; n = n.getNextSibling())
            if (n.getNodeName().equals(string)) {
                ret = n;
                break;
            }
        return ret;
    }

    public static Node findNode(Node node, String string) {

        Node ret = null;
        String name = node.getNodeName();
        if (name != null && name.equals(string))
            return node;

        for (Node n = node.getFirstChild(); n != null; n = n.getNextSibling())
            if ((ret = findNode(n, string)) != null) {
                return ret;
            }

        return null;
    }

    public Node findNode(String s) {
        return findNode(root(), s);
    }

    public Node findNode(String s, String optionalPrefix) {
        Node ret = findNode(root(), s);
        if (ret == null) {
            ret = findNode(root(), optionalPrefix + ":" + s);
        }
        return ret;
    }

    public Collection getProcessingInstructions() {

        ArrayList ret = new ArrayList();

        for (Node n = dom.getFirstChild(); n != null; n = n.getNextSibling())
            if (n.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE) {
                ret.add((ProcessingInstruction) n);
            }

        return ret;
    }

    public Node appendTextNode(String tag, String text, Node parent) {

        Node nn = createNode(tag, parent);
        nn.setTextContent(text);
        return nn;
    }

    public void addProcessingInstruction(String target, String data) {
        dom.createProcessingInstruction(target, data);
    }

    /**
     * What this does should be obvious. How it does it is quite far from that.
     * 
     * FIXME by now I just hard-coded options such as pretty printing. Of course we
     * want to pass or set them.
     * 
     * @param outfile
     * @throws KlabIOException
     */
    public void writeToFile(File outfile) throws KlabIOException {

        Transformer transformer;
        try {
            transformer = TransformerFactory.newInstance().newTransformer();
            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
            StreamResult result = new StreamResult(new StringWriter());
            DOMSource source = new DOMSource(dom);
            transformer.transform(source, result);
            String xmlString = result.getWriter().toString();
            OutputStream outputStream = new FileOutputStream(outfile);
            outputStream.write(xmlString.getBytes());
            outputStream.close();
        } catch (Exception e) {
            throw new KlabIOException(e);
        }
    }

    /**
     * What this does should be obvious. How it does it is quite far from that.
     * 
     * FIXME by now I just hard-coded options such as pretty printing. Of course we
     * want to pass or set them.
     * 
     * @param outputStream
     * @throws KlabIOException
     */
    public void dump(OutputStream outputStream) throws KlabIOException {

        Transformer transformer;
        try {
            transformer = TransformerFactory.newInstance().newTransformer();
            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
            StreamResult result = new StreamResult(new StringWriter());
            DOMSource source = new DOMSource(dom);
            transformer.transform(source, result);
            String xmlString = result.getWriter().toString();
            outputStream.write(xmlString.getBytes());
        } catch (Exception e) {
            throw new KlabIOException(e);
        }
    }

    public static Collection> getNodeAttributes(Node n) {

        ArrayList> ret = new ArrayList>();

        if (n.hasAttributes()) {
            NamedNodeMap nnn = n.getAttributes();
            for (int i = 0; i < nnn.getLength(); i++) {
                Node zit = nnn.item(i);
                ret.add(new Pair(zit.getNodeName(), zit.getTextContent()));
            }
        }
        return ret;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy