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

org.tinystruct.dom.Document Maven / Gradle / Ivy

/*******************************************************************************
 * Copyright  (c) 2013, 2017 James Mover Zhou
 *
 * 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
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *******************************************************************************/
package org.tinystruct.dom;

import org.tinystruct.ApplicationException;
import org.tinystruct.system.Resources;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.*;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;

/**
 * XML IO reading and writing utility.
 *
 * @author James Zhou
 */
public class Document extends DefaultHandler {
    private static final Logger LOG = Logger.getLogger("Document.class");

    private static final String DOCTYPE_CONFIGURATION = "org/tinystruct/application/application-1.0.dtd";
    private static final String XHTML_TRANSITIONAL_DOCTYPE_CONFIGURATION = "org/tinystruct/application/application-1.0.dtd";
    private static final String XHTML_STRICT_DOCTYPE_CONFIGURATION = "org/tinystruct/application/application-1.0.dtd";

    private static final Map doctypeMap = new HashMap();

    static {
        doctypeMap
                .put("-//development.tinystruct.org//DTD APPLICATION Configuration 2.0//EN",
                        DOCTYPE_CONFIGURATION);
        doctypeMap.put("http://development.tinystruct.org/dtd/application-1.0.dtd",
                DOCTYPE_CONFIGURATION);
        doctypeMap.put("-//W3C//DTD XHTML 1.0 Transitional//EN",
                XHTML_TRANSITIONAL_DOCTYPE_CONFIGURATION);
        doctypeMap.put("-//W3C//DTD XHTML 1.0 Strict//EN",
                XHTML_STRICT_DOCTYPE_CONFIGURATION);
    }

    // Top level element (Used to hold everything else)
    private Element rootElement;
    // The current element you are working on
    private Element currentElement;

    // Buffer for collecting data from
    // the "characters" SAX event.
    private CharArrayWriter contents = new CharArrayWriter();
    private URL url = null;

    public Document(URL url) {
        super();
        this.url = url;
    }

    // setup and load constructor
    public Document() {
        this.currentElement = null;
        this.rootElement = null;
    }

    // setup and load constructor

    /**
     * Creates a XmlIO object with the specified element at the top.
     *
     * @param element the element at the top.
     */
    public Document(Element element) {
        this.rootElement = element;
    }

    public void setURL(URL url) {
        this.url = url;
    }

    public boolean load() {
        return load(url);
    }

    public boolean load(String file) throws ApplicationException {
        try {
            InputStream input = new FileInputStream(file);
            return load(input);
        } catch (FileNotFoundException FileNotFound) {
            throw new ApplicationException(FileNotFound.getMessage(),
                    FileNotFound);
        }
    }

    /**
     * Loads from the InputStream into the root Xml Element.
     *
     * @param input the input stream to load from.
     * @return boolean
     */
    public boolean load(InputStream input) {
        try {
            SAXParserFactory factory = SAXParserFactory.newInstance();
            SAXParser saxParser = factory.newSAXParser();
            saxParser.parse(input, this);
        } catch (javax.xml.parsers.ParserConfigurationException ex) {
            LOG.severe("XML config error while attempting to read from the input stream \n'"
                    + input + "'");
            LOG.severe(ex.toString());
            ex.printStackTrace();
            return (false);
        } catch (SAXException ex) {
            LOG.severe("XML parse error while attempting to read from the input stream \n'"
                    + input + "'");
            LOG.severe(ex.toString());
            ex.printStackTrace();
            return (false);
        } catch (IOException ex) {
            LOG.severe("I/O error while attempting to read from the input stream \n'"
                    + input + "'");
            LOG.severe(ex.toString());
            ex.printStackTrace();
            return (false);
        }

        return true;
    }

    /**
     * Load a file. This is what starts things off.
     *
     * @param inputURL the URL to load XML from.
     * @return boolean
     */
    public boolean load(URL inputURL) {
        try {
            SAXParserFactory factory = SAXParserFactory.newInstance();
            SAXParser saxParser = factory.newSAXParser();
            saxParser.parse(inputURL.toString(), this);
        } catch (javax.xml.parsers.ParserConfigurationException ex) {
            LOG.severe("XML config error while attempting to read XML file \n'"
                    + inputURL + "'");
            LOG.severe(ex.toString());
            ex.printStackTrace();
            return (false);
        } catch (SAXException ex) {
            // Error
            LOG.severe("XML parse error while attempting to read XML file \n'"
                    + inputURL + "'");
            LOG.severe(ex.toString());
            ex.printStackTrace();
            return (false);
        } catch (IOException ex) {
            LOG.severe("I/O error while attempting to read XML file \n'"
                    + inputURL + "'");
            LOG.severe(ex.toString());
            ex.printStackTrace();
            return (false);
        }

        return (true);
    }

    public boolean read(String text) throws ApplicationException {
        try {
            SAXParserFactory factory = SAXParserFactory.newInstance();
            SAXParser saxParser = factory.newSAXParser();
            saxParser.parse(new ByteArrayInputStream(text.getBytes()), this);
        } catch (javax.xml.parsers.ParserConfigurationException ex) {
            LOG.severe("XML config ParserConfigurationException error while attempting to read XML text");
            LOG.severe(ex.toString());
            throw new ApplicationException(ex.getMessage(), ex);
        } catch (SAXException ex) {
            // Error
            LOG.severe("XML config SAXException error while attempting to read XML text");
            LOG.severe(ex.toString());
            throw new ApplicationException(ex.getMessage(), ex);
        } catch (IOException ex) {
            LOG.severe("XML config IOException error while attempting to read XML text");
            LOG.severe(ex.toString());
            throw new ApplicationException(ex.getMessage(), ex);
        }

        return (true);

    }

    @Override
    public void startElement(String namespaceURI, String localName,
                             String qName, Attributes attrs) throws SAXException {
        // Resetting contents buffer.
        // Assuming that tags either tag content or children, not both.
        // This is usually the case with XML that is representing
        // data strucutures in a programming language independant way.
        // This assumption is not typically valid where XML is being
        // used in the classical text mark up style where tagging
        // is used to style content and several styles may overlap
        // at once.
        try {
            contents.reset();
            String name = localName; // element name
            if (name.equals("")) {
                name = qName; // namespaceAware = false
            }

            if (this.rootElement == null) {
                this.rootElement = new Element(name);
                this.currentElement = this.rootElement;
            } else {
                this.currentElement = this.currentElement.addElement(name);
            }

            if (attrs != null) {
                for (int i = 0; i < attrs.getLength(); i++) {
                    String aName = attrs.getLocalName(i); // Attr name
                    if (aName.equals("")) {
                        aName = attrs.getQName(i);
                    }
                    this.currentElement.setAttribute(aName, attrs.getValue(i));
                }
            }
        } catch (java.lang.NullPointerException ex) {
            LOG.severe("Null!!!");
            LOG.severe(ex.toString());
            ex.printStackTrace();
        }
    }

    @Override
    public void endElement(String namespaceURI, String localName, String qName)
            throws SAXException {
        if (this.currentElement != null) {
            this.currentElement.setData(contents.toString().trim());
            contents.reset();
            this.currentElement = this.currentElement.getParent();
        }
    }

    @Override
    public void characters(char[] ch, int start, int length)
            throws SAXException {
        // accumulate the contents into a buffer.
        contents.write(ch, start, length);
    }

    /**
     * Returns the root for the Element hierarchy.
     * 

* Methods that want to retrieve elements from this root should use the * {@link Element} in order to get the wanted * element. * * @return a Element if it has been loaded or initialized with it; null * otherwise. */ public Element getRoot() { return this.rootElement; } public void save() throws Exception { save(new FileOutputStream(url.getPath())); } // // Writer interface // public void save(OutputStream out) throws IOException { BufferedWriter PW = new BufferedWriter(new OutputStreamWriter(out, "UTF-8")); PW.write("\n"); if (rootElement.getChildNodes().size() > 0) { PW.write(rootElement.toString()); } PW.flush(); } public InputSource resolveEntity(String publicId, String systemId) throws IOException, SAXException { InputSource source = null; try { String path = (String) doctypeMap.get(publicId); source = getInputSource(path, source); if (source != null) { path = (String) doctypeMap.get(systemId); source = getInputSource(path, source); } /* * else { throw new SAXException("Input Source is NULL"); } */ } catch (Exception e) { throw new SAXException(e.toString()); } return source; } private InputSource getInputSource(String path, InputSource source) { if (path != null) { InputStream in = null; try { in = Resources.getResourceAsStream(path); source = new InputSource(in); } catch (IOException e) { LOG.severe(e.toString()); e.printStackTrace(); } } return source; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy