org.codehaus.cargo.util.Dom4JUtil.java Source code

Java tutorial

Introduction

Here is the source code for org.codehaus.cargo.util.Dom4JUtil.java

Source

/*
 * ========================================================================
 *
 * Codehaus CARGO, copyright 2004-2011 Vincent Massol, 2012-2015 Ali Tokmen.
 *
 * 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.codehaus.cargo.util;

import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.XPath;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import org.xml.sax.SAXException;

/**
 * This class offers utility methods not exposed in the current dom4j api.
 * 
 */
public class Dom4JUtil {
    /**
     * namespace prefixes used for selecting nodes in config.xml.
     */
    private Map<String, String> namespaces;

    /**
     * File utility class.
     */
    private FileHandler fileHandler;

    /**
     * default constructor will assign no namespaces and use a default file handler.
     */
    public Dom4JUtil() {
        this(new DefaultFileHandler());
    }

    /**
     * constructor will assign no namespaces.
     * 
     * @param fileHandler used to read and write xml files.
     */
    public Dom4JUtil(FileHandler fileHandler) {
        this.fileHandler = fileHandler;
        this.setNamespaces(new HashMap<String, String>());
    }

    /**
     * The following will search the given element for the specified xpath and return a list of
     * nodes that match.
     * 
     * @param xpath - selection criteria
     * @param toSearch - element to start the search at
     * @return List of matching elements
     */
    public List<Element> selectElementsMatchingXPath(String xpath, Element toSearch) {
        XPath xpathSelector = DocumentHelper.createXPath(xpath);
        xpathSelector.setNamespaceURIs(getNamespaces());
        List<Element> results = xpathSelector.selectNodes(toSearch);
        return results;
    }

    /**
     * The following will search the given element for the specified xpath and return any node that
     * matches.
     * 
     * @param xpath - selection criteria
     * @param toSearch - element to start the search at
     * @return a matching element
     */
    public Element selectElementMatchingXPath(String xpath, Element toSearch) {
        List<Element> results = selectElementsMatchingXPath(xpath, toSearch);
        if (results.isEmpty()) {
            throw new ElementNotFoundException(xpath, toSearch);
        }
        Element match = results.get(0);
        return match;
    }

    /**
     * write the xml document to disk, closing the destination on completion.
     * 
     * @param document document to write to disk
     * @param destination where to write the document
     * @throws IOException when the document cannot be written to the destination
     */
    private void writeXmlToOutputStream(Document document, OutputStream destination) throws IOException {
        try {
            OutputFormat outformat = OutputFormat.createPrettyPrint();
            XMLWriter writer = new XMLWriter(destination, outformat);
            writer.write(document);
            writer.flush();
            writer.close();
        } finally {
            destination.close();
        }
    }

    /**
     * read the specified file into a Document.
     * 
     * @param sourceFile file to read
     * @return Document corresponding with sourceFile
     */
    public Document loadXmlFromFile(String sourceFile) {
        Document xml;
        try {
            SAXReader reader = new SAXReader(false);
            setDontAccessExternalResources(reader);
            xml = reader.read(getFileHandler().getInputStream(sourceFile));
        } catch (DocumentException e) {
            throw new CargoException("Error parsing " + sourceFile, e);
        }
        return xml;
    }

    /**
     * Turn off anything that would make this class touch the outside world.
     * 
     * @param reader what to disable external fetches from.
     */
    private void setDontAccessExternalResources(SAXReader reader) {
        try {
            reader.setFeature("http://xml.org/sax/features/external-general-entities", false);
            reader.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
            reader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
        } catch (SAXException e) {
            throw new CargoException("Error disabling external xml resources", e);
        }
    }

    /**
     * write the xml document to disk, rethrowing checked exceptions as runtime.
     * 
     * @param document document to write to disk
     * @param filename where to write the document
     */
    public void saveXml(Document document, String filename) {
        OutputStream destination = null;
        try {
            if (!getFileHandler().exists(filename)) {
                getFileHandler().createFile(filename);
            }
            destination = getFileHandler().getOutputStream(filename);
            writeXmlToOutputStream(document, destination);
        } catch (IOException e) {
            throw new CargoException("Error writing " + filename, e);
        }
    }

    /**
     * @return the Cargo file utility class
     */
    public FileHandler getFileHandler() {
        return this.fileHandler;
    }

    /**
     * @param fileHandler the Cargo file utility class to use. This method is useful for unit
     * testing with Mock objects as it can be passed a test file handler that doesn't perform any
     * real file action.
     */
    public void setFileHandler(FileHandler fileHandler) {
        this.fileHandler = fileHandler;
    }

    /**
     * @param namespaces the namespaces to set
     */
    public void setNamespaces(Map<String, String> namespaces) {
        this.namespaces = namespaces;
    }

    /**
     * @return the namespaces
     */
    public Map<String, String> getNamespaces() {
        return namespaces;
    }

    /**
     * parse the passed string into an {@link Element Element} object.
     * 
     * @param elementToParse string to parse
     * @return result of parsing
     */
    public Element parseIntoElement(String elementToParse) {
        try {
            Document parsed = DocumentHelper.parseText(elementToParse);
            return parsed.getRootElement();
        } catch (DocumentException e) {
            throw new CargoException("Could not parse element: " + elementToParse);
        }
    }

}