bogdanrechi.xmlo.Xmlo.java Source code

Java tutorial

Introduction

Here is the source code for bogdanrechi.xmlo.Xmlo.java

Source

/*
The MIT License (MIT)
    
Copyright (c) 2015 Bogdan Rechi
    
This program 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
of the License, or (at your option) 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
GNU General Public License for more details.
    
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

package bogdanrechi.xmlo;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.cli.BasicParser;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.OptionGroup;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.log4j.Logger;
import org.w3c.dom.NodeList;

import bogdan.rechi.commons.Files;
import bogdan.rechi.commons.Format;
import bogdan.rechi.commons.General;
import bogdan.rechi.commons.Platform;
import bogdan.rechi.commons.Property;
import bogdan.rechi.commons.Strings;
import bogdan.rechi.commons.time.TimeMeasure;
import bogdan.rechi.commons.xml.Xml;

/**
 * XML mass operations.
 *
 * @author Bogdan Rechi
 */
public class Xmlo {
    private static String PROCESSING = "Processing...";
    private static String GETTING_FILES = "Gathering files...";

    private static String EXTENSION_XPATH = ".xpath";
    private static String EXTENSION_XPATH_RESULT = ".rxpath";

    private static String EXTENSION_XSD = ".xsd";
    private static String EXTENSION_XSD_RESULT = ".rxsd";

    private static String EXTENSION_DTD = ".dtd";
    private static String EXTENSION_DTD_RESULT = ".rdtd";

    private static String EXTENSION_XSLT = ".xsl";
    private static String EXTENSION_XSLT_RESULT = ".rxsl";

    private static String EXTENSION_XQUERY = ".xquery";
    private static String EXTENSION_XQUERY_RESULT = ".rxquery";

    // =============================================================================

    /**
     * Application log4j log.
     */
    private static Logger _log;

    // =============================================================================

    // arguments
    private static Boolean _recursive = false;
    private static Boolean _keepStructure = false;
    private static Boolean _resultsOnly = false;
    private static Boolean _verbose = false;
    private static String _extension;
    private static String _destination;
    private static Boolean _destinationIsFile = false;
    private static Boolean _destinationIsTerminal = false;
    private static String _target;
    private static String _targetFolder;
    private static String _namespaces;
    private static Boolean _notNumbered = false;
    private static Boolean _keepBlanks = false;
    private static Boolean _showDuration = false;

    private static String[] _namespaceAliases;

    private static Property<String> _errorMessage = new Property<String>();

    // =============================================================================

    /**
     * Main method.
     *
     * @param args
     *          Program arguments.
     */
    @SuppressWarnings("static-access")
    public static void main(String[] args) {
        long timeStart = System.currentTimeMillis();

        _log = Logger.getLogger(Xmlo.class);

        Options argOptions = new Options();

        OptionGroup operationTypes = new OptionGroup();

        operationTypes.addOption(
                OptionBuilder.withDescription("XPath query").hasArg().withArgName("file").create("xpath"));
        operationTypes.addOption(
                OptionBuilder.withDescription("XSLT transformation").hasArg().withArgName("file").create("xslt"));
        operationTypes.addOption(
                OptionBuilder.withDescription("XQuery (with $sourceFilePath, see XmlOperations for details)")
                        .hasArg().withArgName("file").create("xquery"));
        operationTypes
                .addOption(OptionBuilder.withDescription("XSD verify").hasArgs().withArgName("file").create("xsd"));
        operationTypes
                .addOption(OptionBuilder.withDescription("DTD verify").hasArgs().withArgName("file").create("dtd"));

        argOptions.addOptionGroup(operationTypes);

        argOptions.addOption(OptionBuilder.withDescription("on screen information while performing")
                .withLongOpt("verbose").create("v"));

        argOptions.addOption(OptionBuilder.withDescription("output non-void or invalid-type results only")
                .withLongOpt("results-only").create("o"));

        argOptions.addOption(OptionBuilder.withDescription("replicate input structure on the destination side")
                .withLongOpt("keep-structure").create("k"));

        argOptions.addOption(OptionBuilder.withDescription("recursive browsing of the target structure")
                .withLongOpt("resursive").create("r"));

        argOptions.addOption(OptionBuilder.withDescription("XPath and XQuery results not numbered")
                .withLongOpt("not-numbered").create("nn"));

        argOptions.addOption(OptionBuilder.withDescription("destination files extension").hasArg()
                .withArgName("ext").withLongOpt("extension").create("x"));

        argOptions.addOption(OptionBuilder.withDescription("target files mask").hasArg().withArgName("files mask")
                .withLongOpt("target").create("t"));

        OptionGroup destinationGroup = new OptionGroup();

        destinationGroup.addOption(OptionBuilder.withDescription("destination file").hasArg().withArgName("file")
                .withLongOpt("destination-file").create("df"));
        destinationGroup.addOption(OptionBuilder.withDescription("destination folder").hasArg()
                .withArgName("folder").withLongOpt("destination-directory").create("dd"));
        destinationGroup.addOption(OptionBuilder.withDescription("destination terminal (and verbose)")
                .withLongOpt("destination-terminal").create("dt"));

        argOptions.addOptionGroup(destinationGroup);

        argOptions.addOption(OptionBuilder.withDescription("file containing namespaces aliases").hasArg()
                .withArgName("file").withLongOpt("namespaces").create("n"));

        argOptions.addOption(OptionBuilder.withDescription("usage information").withLongOpt("help").create("h"));

        argOptions.addOption(OptionBuilder.withDescription("show examples").withLongOpt("examples").create("e"));

        argOptions.addOption(OptionBuilder.withDescription("keep blank nodes while printing")
                .withLongOpt("keep-blanks").create("b"));

        argOptions.addOption(
                OptionBuilder.withDescription("show duration for each file when the verbose option is activated")
                        .withLongOpt("show-duration").create("d"));

        CommandLineParser parser = new BasicParser();
        try {
            CommandLine cmd = parser.parse(argOptions, args);

            if (cmd.hasOption('h') || cmd.hasOption('e') || cmd.getOptions().length == 0) {
                Format.println("\n" + General.getAboutInformation("resources/xmlo/metadata.properties"));

                if (cmd.hasOption('h') || cmd.getOptions().length == 0) {
                    HelpFormatter formatter = new HelpFormatter();
                    formatter.printHelp("xmlo", "where:", argOptions, null, true);
                    Format.println();
                }

                if (cmd.hasOption("e")) {
                    String examples = Files.readTextFileFromResources("resources/xmlo/examples.txt", _errorMessage);
                    if (examples != null)
                        Format.println(examples);
                    else {
                        Format.println("Internal error! Please see the log file for detalis.");
                        _log.error(_errorMessage.get());

                        System.exit(1);
                    }
                }

                System.exit(0);
                return;
            }

            Format.println();

            // options

            if (cmd.hasOption('r'))
                _recursive = true;

            if (cmd.hasOption('k'))
                _keepStructure = true;

            if (cmd.hasOption('o'))
                _resultsOnly = true;

            if (cmd.hasOption('v'))
                _verbose = true;

            if (cmd.hasOption('b'))
                _keepBlanks = true;

            if (cmd.hasOption('d'))
                _showDuration = true;

            if (cmd.hasOption('x'))
                _extension = "." + cmd.getOptionValue('x');

            if (cmd.hasOption("nn"))
                _notNumbered = true;

            if (cmd.hasOption("df")) {
                _destination = cmd.getOptionValue("df");

                if (Files.isFolder(_destination))
                    printErrorAndExit("The destination is a folder!");

                _destinationIsFile = true;
            }

            if (cmd.hasOption("dd")) {
                _destination = cmd.getOptionValue("dd");

                if (!Files.exists(_destination))
                    printErrorAndExit("The destination folder does not exist!");

                if (!Files.isFolder(_destination))
                    printErrorAndExit("The destination is not a folder!");
            }

            if (cmd.hasOption("dt"))
                _destinationIsTerminal = _verbose = true;

            if (cmd.hasOption('t'))
                _target = cmd.getOptionValue('t');

            if (cmd.hasOption('n')) {
                _namespaces = cmd.getOptionValue('n');
                extractNamespacesAliases();
            }

            // operations

            if (cmd.hasOption("xpath")) {
                if (_target == null)
                    _target = Files.CURRENT_DIRECTORY + Files.FILE_SEPARATOR + "*" + EXTENSION_XPATH;

                doXPath(cmd.getOptionValue("xpath"));
            }

            if (cmd.hasOption("xslt")) {
                if (_target == null)
                    _target = Files.CURRENT_DIRECTORY + Files.FILE_SEPARATOR + "*" + EXTENSION_XSLT;

                doXslt(cmd.getOptionValue("xslt"));
            }

            if (cmd.hasOption("xquery")) {
                if (_target == null)
                    _target = Files.CURRENT_DIRECTORY + Files.FILE_SEPARATOR + "*" + EXTENSION_XQUERY;

                doXQuery(cmd.getOptionValue("xquery"));
            }

            if (cmd.hasOption("xsd")) {
                if (_target == null)
                    _target = Files.CURRENT_DIRECTORY + Files.FILE_SEPARATOR + "*" + EXTENSION_XSD;

                doXsd(cmd.getOptionValues("xsd"));
            }

            if (cmd.hasOption("dtd")) {
                if (_target == null)
                    _target = Files.CURRENT_DIRECTORY + Files.FILE_SEPARATOR + "*" + EXTENSION_DTD;

                doDtd(cmd.getOptionValues("dtd"));
            }
        } catch (ParseException e) {
            printErrorAndExit(e.getMessage());
        }

        Format.println("Finished%s.", _showDuration ? " in " + TimeMeasure.printDuration(timeStart) : "");

        if (Platform.SYSTEM_IS_LINUX)
            Format.println();

        System.exit(0);
    }

    /**
     * Verify by XSD files.
     *
     * @param xsdFiles
     *          Files to verify by.
     */
    private static void doXsd(String[] xsdFiles) {
        Writer destinationFileStream = null;

        try {
            _targetFolder = Files.getParent(_target);

            Format.println(GETTING_FILES);
            ArrayList<String> targets = new ArrayList<String>();
            if (Files.browseFolder2(targets, _target, _recursive, _errorMessage)) {
                Format.println(PROCESSING);

                if (!_destinationIsTerminal && _destinationIsFile)
                    destinationFileStream = new OutputStreamWriter(new FileOutputStream(_destination));

                for (int i = 0; i < targets.size(); i++) {
                    String target = targets.get(i);

                    long timeStart = System.currentTimeMillis();

                    if (_verbose)
                        Format.println(String.format("\n%s", target));

                    String outputFile = null;

                    if (!_destinationIsTerminal && !_destinationIsFile) {
                        outputFile = getDestinationFile(target,
                                _extension == null ? EXTENSION_XSD_RESULT : _extension);

                        if (_verbose)
                            Format.print("Out: " + outputFile + "... ");
                    }

                    if (_verbose && _destinationIsFile && !_destinationIsTerminal)
                        Format.print("... ");

                    String output = null;
                    Boolean isValid = false;
                    Boolean error = false;

                    Xml doc = new Xml();
                    if (!doc.load(new File(target))) {
                        output = String.format("Error: %s\n\n", doc.getLastError());
                        if (_destinationIsTerminal)
                            Format.print(output);

                        error = true;
                    } else {
                        isValid = doc.validateAgainstXsdFiles(xsdFiles);

                        output = String.format("%s%s\n\n", isValid ? "Valid." : "Invalid: ",
                                isValid ? "" : doc.getLastError());
                        if (_destinationIsTerminal)
                            Format.print(output);
                    }

                    if (!_destinationIsTerminal)
                        if (_destinationIsFile) {
                            if (isValid || !_resultsOnly) {
                                if (_showDuration)
                                    destinationFileStream.write(String.format("--File: %s in %s\n\n", target,
                                            TimeMeasure.printDuration(timeStart)));
                                else
                                    destinationFileStream.write(String.format("--File: %s\n\n", target));

                                destinationFileStream.write(output);
                                destinationFileStream.flush();
                            }
                        } else if (isValid || !_resultsOnly) {
                            Files.createFolderForFile(outputFile);
                            Files.writeTextFile(output, outputFile);
                        }

                    if (!_destinationIsTerminal && _verbose)
                        if (_showDuration)
                            Format.println(error ? "error!"
                                    : String.format("done in %s.", TimeMeasure.printDuration(timeStart)));
                        else
                            Format.println(error ? "error!" : "done.");
                }
            } else
                printErrorAndExit(_errorMessage.get());
        } catch (Exception e) {
            printErrorAndExit(e.getMessage());
        } finally {
            if (destinationFileStream != null)
                try {
                    destinationFileStream.close();

                    if (_verbose)
                        Format.println("Out: " + _destination + "... done.");
                } catch (IOException e) {
                    printErrorAndExit("Unable to create results file!");
                }
        }
    }

    /**
     * Verify by DTD files.
     *
     * @param dtdFiles
     *          Files to verify by.
     */
    private static void doDtd(String[] dtdFiles) {
        Writer destinationFileStream = null;

        try {
            _targetFolder = Files.getParent(_target);

            Format.println(GETTING_FILES);
            ArrayList<String> targets = new ArrayList<String>();
            if (Files.browseFolder2(targets, _target, _recursive, _errorMessage)) {
                Format.println(PROCESSING);

                if (!_destinationIsTerminal && _destinationIsFile)
                    destinationFileStream = new OutputStreamWriter(new FileOutputStream(_destination));

                for (int i = 0; i < targets.size(); i++) {
                    String target = targets.get(i);

                    long timeStart = System.currentTimeMillis();

                    if (_verbose)
                        Format.println(String.format("\n%s", target));

                    String outputFile = null;

                    if (!_destinationIsTerminal && !_destinationIsFile) {
                        outputFile = getDestinationFile(target,
                                _extension == null ? EXTENSION_DTD_RESULT : _extension);

                        if (_verbose)
                            Format.print("Out: " + outputFile + "... ");
                    }

                    if (_verbose && _destinationIsFile && !_destinationIsTerminal)
                        Format.print("... ");

                    String output = null;
                    Boolean isValid = false;
                    Boolean error = false;

                    Xml doc = new Xml();
                    if (!doc.load(new File(target))) {
                        output = String.format("Error: %s\n\n", doc.getLastError());
                        if (_destinationIsTerminal)
                            Format.print(output);

                        error = true;
                    } else {
                        Property<Boolean> dtdError = new Property<Boolean>();
                        isValid = doc.validateAgainstDtdFiles(dtdFiles, dtdError);

                        if (!isValid && dtdError.get())
                            printErrorAndExit(doc.getLastError());

                        output = String.format("%s%s\n", isValid ? "Valid." : "Invalid: ",
                                isValid ? "" : doc.getLastError());
                        if (_destinationIsTerminal)
                            Format.print(output);
                    }

                    if (!_destinationIsTerminal)
                        if (_destinationIsFile) {
                            if (isValid || !_resultsOnly) {
                                if (_showDuration)
                                    destinationFileStream.write(String.format("--File: %s in %s\n\n", target,
                                            TimeMeasure.printDuration(timeStart)));
                                else
                                    destinationFileStream.write(String.format("--File: %s\n\n", target));

                                destinationFileStream.write(output);
                                destinationFileStream.flush();
                            }
                        } else if (isValid || !_resultsOnly) {
                            Files.createFolderForFile(outputFile);
                            Files.writeTextFile(output, outputFile);
                        }

                    if (!_destinationIsTerminal && _verbose)
                        if (_showDuration)
                            Format.println(error ? "error!"
                                    : String.format("done in %s.", TimeMeasure.printDuration(timeStart)));
                        else
                            Format.println(error ? "error!" : "done.");
                }
            } else
                printErrorAndExit(_errorMessage.get());
        } catch (Exception e) {
            printErrorAndExit(e.getMessage());
        } finally {
            if (destinationFileStream != null)
                try {
                    destinationFileStream.close();

                    if (_verbose)
                        Format.println("Out: " + _destination + "... done.");
                } catch (IOException e) {
                    printErrorAndExit("Unable to create results file!");
                }
        }
    }

    /**
     * Perform XQuery operation.
     *
     * @param xqueryFile
     *          XQuery file to perform by.
     */
    private static void doXQuery(String xqueryFile) {
        Writer destinationFileStream = null;

        try {
            String xquery = Files.readTextFile(xqueryFile);

            _targetFolder = Files.getParent(_target);

            Format.println(GETTING_FILES);
            ArrayList<String> targets = new ArrayList<String>();
            if (Files.browseFolder2(targets, _target, _recursive, _errorMessage)) {
                Format.println(PROCESSING);

                if (!_destinationIsTerminal && _destinationIsFile)
                    destinationFileStream = new OutputStreamWriter(new FileOutputStream(_destination));

                for (int i = 0; i < targets.size(); i++) {
                    String target = targets.get(i);

                    long timeStart = System.currentTimeMillis();

                    if (_verbose)
                        Format.println(target);

                    String outputFile = null;

                    if (!_destinationIsTerminal && !_destinationIsFile) {
                        outputFile = getDestinationFile(target,
                                _extension == null ? EXTENSION_XQUERY_RESULT : _extension);

                        if (_verbose)
                            Format.print("Out: " + outputFile + "... ");
                    }

                    if (_verbose && _destinationIsFile && !_destinationIsTerminal)
                        Format.print("... ");

                    String output = null;
                    Boolean error = false;

                    Xml doc = new Xml();
                    if (!doc.load(new File(target))) {
                        output = String.format("Error: %s", doc.getLastError());
                        if (_destinationIsTerminal)
                            Format.print(output);

                        error = true;
                    } else if (!doc.applyXQuery(xquery, true, _errorMessage)) {
                        output = String.format("Error: %s", doc.getLastError());
                        if (_destinationIsTerminal)
                            Format.print(output);

                        error = true;
                    }

                    Boolean hasResults = false;
                    StringBuilder sb = new StringBuilder();

                    if (!error)
                        if (hasResults = doc.hasXQueryResults()) {
                            int j = 1;
                            String firstItemText = "";

                            Property<String> itemTextProp = new Property<String>();

                            for (; doc.getNextXQueryResultItem(itemTextProp, _errorMessage); j++) {
                                String itemText = itemTextProp.get();

                                if (!itemText.endsWith("\n"))
                                    itemText += "\n";

                                switch (j) {
                                case 1:
                                    firstItemText = itemText;
                                    break;

                                case 2:
                                    if (!_notNumbered)
                                        sb.append("\n-1-\n\n");
                                    else
                                        sb.append("\n");

                                    sb.append(firstItemText);

                                default:
                                    if (!_notNumbered)
                                        sb.append(String.format("\n-%d-\n\n", j));
                                    else
                                        sb.append("\n");

                                    sb.append(itemText);
                                    break;
                                }
                            }

                            if (!_errorMessage.isNull())
                                output = String.format("Error: %s", _errorMessage.get());
                            else {
                                if (j == 1)
                                    sb.append("Empty selection");
                                else {
                                    if (j == 2)
                                        sb.append(firstItemText);

                                    if (!_notNumbered)
                                        sb.insert(0, String.format("%d node%s selected\n%s", j - 1,
                                                j == 2 ? "" : "s", j == 2 ? "\n" : ""));
                                }

                                output = sb.toString();
                            }

                            if (_destinationIsTerminal)
                                Format.print(output);
                        }

                    if (!_destinationIsTerminal)
                        if (_destinationIsFile) {
                            if (hasResults || !_resultsOnly) {
                                if (_showDuration)
                                    destinationFileStream.write(String.format("--File: %s (in %s)\n\n", target,
                                            TimeMeasure.printDuration(timeStart)));
                                else
                                    destinationFileStream.write(String.format("--File: %s\n\n", target));

                                if (output == null && !_resultsOnly)
                                    destinationFileStream.write(String.format("Error: %s\n\n", doc.getLastError()));
                                else
                                    destinationFileStream.write(String.format("%s\n\n", output));

                                destinationFileStream.flush();
                            }
                        } else if (hasResults || !_resultsOnly) {
                            Files.createFolderForFile(outputFile);

                            if (output == null && !_resultsOnly)
                                Files.writeTextFile(String.format("Error: %s", doc.getLastError()), outputFile);
                            else
                                Files.writeTextFile(output, outputFile);
                        }

                    if (!_destinationIsTerminal && _verbose)
                        if (_showDuration)
                            Format.println(error ? "error!"
                                    : String.format("done in %s.", TimeMeasure.printDuration(timeStart)));
                        else
                            Format.println(error ? "error!" : "done.");
                }
            } else
                printErrorAndExit(_errorMessage.get());
        } catch (Exception e) {
            printErrorAndExit(e.getMessage());
        } finally {
            if (destinationFileStream != null)
                try {
                    destinationFileStream.close();

                    if (_verbose)
                        Format.println("Out: " + _destination + "... done.");
                } catch (IOException e) {
                    printErrorAndExit("Unable to create results file!");
                }
        }
    }

    /**
     * Perform XSLT operations.
     *
     * @param xsltFile
     *          XSLT file to perform by.
     */
    private static void doXslt(String xsltFile) {
        Writer destinationFileStream = null;

        try {
            _targetFolder = Files.getParent(_target);

            Format.println(GETTING_FILES);
            ArrayList<String> targets = new ArrayList<String>();
            if (Files.browseFolder2(targets, _target, _recursive, _errorMessage)) {
                Format.println(PROCESSING);

                if (!_destinationIsTerminal && _destinationIsFile)
                    destinationFileStream = new OutputStreamWriter(new FileOutputStream(_destination));

                for (int i = 0; i < targets.size(); i++) {
                    String target = targets.get(i);

                    long timeStart = System.currentTimeMillis();

                    if (_verbose)
                        Format.println(target);

                    String outputFile = null;

                    if (!_destinationIsTerminal && !_destinationIsFile) {
                        outputFile = getDestinationFile(target,
                                _extension == null ? EXTENSION_XSLT_RESULT : _extension);

                        if (_verbose)
                            Format.print("Out: " + outputFile + "... ");
                    }

                    if (_verbose && _destinationIsFile && !_destinationIsTerminal)
                        Format.print("... ");

                    String output = null;
                    Boolean error = false;

                    Xml doc = new Xml();
                    if (!doc.load(new File(target))) {
                        output = String.format("Error: %s", doc.getLastError());
                        if (_destinationIsTerminal)
                            Format.print(output);

                        error = true;
                    } else {
                        output = doc.applyXsltFile(xsltFile);

                        if (output == null)
                            error = true;
                        else if (_destinationIsTerminal)
                            Format.print(output);
                    }

                    if (_destinationIsFile) {
                        if (_showDuration)
                            destinationFileStream.write(String.format("--File: %s (in %s)\n\n", target,
                                    TimeMeasure.printDuration(timeStart)));
                        else
                            destinationFileStream.write(String.format("--File: %s\n\n", target));

                        if (output == null)
                            destinationFileStream.write(String.format("Error: %s\n\n", doc.getLastError()));
                        else
                            destinationFileStream.write(String.format("%s\n\n", output));

                        destinationFileStream.flush();
                    } else {
                        Files.createFolderForFile(outputFile);

                        if (output == null)
                            Files.writeTextFile(String.format("Error: %s", doc.getLastError()), outputFile);
                        else
                            Files.writeTextFile(output, outputFile);
                    }

                    if (_verbose)
                        if (_showDuration)
                            Format.println(error ? "error!"
                                    : String.format("done in %s.", TimeMeasure.printDuration(timeStart)));
                        else
                            Format.println(error ? "error!" : "done.");
                }
            } else
                printErrorAndExit(_errorMessage.get());
        } catch (Exception e) {
            printErrorAndExit(e.getMessage());
        } finally {
            if (destinationFileStream != null)
                try {
                    destinationFileStream.close();

                    if (_verbose)
                        Format.println("Out: " + _destination + "... done.");
                } catch (IOException e) {
                    printErrorAndExit("Unable to create results file!");
                }
        }
    }

    /**
     * Perform XPath operations.
     *
     * @param xpathFile
     *          File containing the XPath operation.
     */
    private static void doXPath(String xpathFile) {
        Writer destinationFileStream = null;

        try {
            String[] xpathLines = Strings.splitLines(Files.readTextFile(xpathFile).trim(), true);
            _targetFolder = Files.getParent(_target);

            Format.println(GETTING_FILES);
            ArrayList<String> targets = new ArrayList<String>();
            if (Files.browseFolder2(targets, _target, _recursive, _errorMessage)) {
                Format.println(PROCESSING);

                if (!_destinationIsTerminal && _destinationIsFile)
                    destinationFileStream = new OutputStreamWriter(new FileOutputStream(_destination));

                for (int i = 0; i < targets.size(); i++) {
                    String target = targets.get(i);

                    long timeStart = System.currentTimeMillis();

                    if (_verbose)
                        Format.println(String.format("\n%s", target));

                    String outputFile = null;

                    if (!_destinationIsTerminal && !_destinationIsFile) {
                        outputFile = getDestinationFile(target,
                                _extension == null ? EXTENSION_XPATH_RESULT : _extension);

                        if (_verbose)
                            Format.print("\nOut: " + outputFile + "... ");
                    }

                    if (_verbose && _destinationIsFile && !_destinationIsTerminal)
                        Format.print("... ");

                    StringBuilder sb = new StringBuilder();
                    Boolean hasResults = false;
                    Boolean error = false;

                    Xml doc = new Xml();
                    if (!doc.load(new File(target))) {
                        sb.append(String.format("Error: %s", doc.getLastError()));
                        if (_destinationIsTerminal)
                            Format.print(sb.toString());

                        error = true;
                    } else {
                        for (int k = 0; k < xpathLines.length; k++) {
                            Property<NodeList> nodesPro = new Property<NodeList>();
                            if (_namespaceAliases == null) {
                                if (!doc.selectNodesWithDefaultNamespaces(xpathLines[k], nodesPro))
                                    printErrorAndExit(doc.getLastError());
                            } else if (!doc.selectNodes(xpathLines[k], nodesPro, _namespaceAliases))
                                printErrorAndExit(doc.getLastError());

                            NodeList nodes = nodesPro.get();
                            int nodesLen = nodes.getLength();

                            if (nodesLen > 0 || !_resultsOnly) {
                                hasResults = true;

                                if (!_notNumbered && nodesLen > 0) {
                                    sb.append(String.format("--XPath: %s\n", xpathLines[k]));
                                    sb.append(String.format("%d node%s selected\n\n", nodesLen,
                                            nodesLen == 1 ? "" : "s"));
                                } else
                                    sb.append("\n");

                                for (int j = 0; j < nodesLen; j++)
                                    sb.append(String.format("%s%s\n\n",
                                            _notNumbered ? "" : String.format("-%d-\n\n", j + 1),
                                            doc.nodeToString(nodes.item(j), !_keepBlanks, false)));
                            }
                        }
                    }

                    if (!_destinationIsTerminal) {
                        if (_destinationIsFile) {
                            if (hasResults || !_resultsOnly) {
                                if (_showDuration)
                                    destinationFileStream.write(String.format("--File: %s (in %s)\n\n", target,
                                            TimeMeasure.printDuration(timeStart)));
                                else
                                    destinationFileStream.write(String.format("--File: %s\n\n", target));

                                if (hasResults)
                                    destinationFileStream.write(sb.toString());

                                destinationFileStream.flush();
                            }
                        } else if (hasResults || !_resultsOnly) {
                            Files.createFolderForFile(outputFile);
                            Files.writeTextFile(sb.toString(), outputFile);
                        }
                    } else
                        Format.print(sb.toString());

                    if (!_destinationIsTerminal && _verbose)
                        if (_showDuration)
                            Format.println(error ? "error!"
                                    : String.format("done in %s.", TimeMeasure.printDuration(timeStart)));
                        else
                            Format.println(error ? "error!" : "done.");
                }
            } else
                printErrorAndExit(_errorMessage.get());
        } catch (Exception e) {
            printErrorAndExit(e.getMessage());
        } finally {
            if (destinationFileStream != null)
                try {
                    destinationFileStream.close();

                    if (_verbose)
                        Format.println("Out: " + _destination + "... done.");
                } catch (IOException e) {
                    printErrorAndExit("Unable to create results file!");
                }
        }
    }

    /**
     * Get destination file for the current target.
     *
     * @param target
     *          Target file to get the destination file for.
     * @param extension
     *          Extension of the destination file.
     *
     * @return The destination file.
     */
    private static String getDestinationFile(String target, String extension) {
        if (_destination != null) {
            if (_keepStructure)
                return _destination + Files.FILE_SEPARATOR + target.substring(_targetFolder.length() + 1)
                        + extension;
            else
                return _destination + Files.FILE_SEPARATOR + new File(target).getName() + extension;
        } else
            return target + extension;
    }

    /**
     * Extract namespaces aliases.
     *
     * @return true if successful, otherwise false.
     */
    private static void extractNamespacesAliases() {
        if (_namespaces != null) {
            String aliases = null;

            try {
                aliases = Files.readTextFile(_namespaces);
            } catch (IOException e) {
                printErrorAndExit("Cannot read from namespaces file!");
            } catch (URISyntaxException e) {
                printErrorAndExit("Namespaces file not found!");
            }

            List<String> result = new ArrayList<String>();
            String lines[] = aliases.split("\n");
            for (String line2 : lines) {
                String line = line2.trim();
                if (line.length() != 0) {
                    String two[] = line.split("=");
                    if (two.length == 2) {
                        result.add(two[0].trim());
                        result.add(two[1].trim());
                    } else
                        printErrorAndExit("Namespaces file contains errors!");
                }
            }

            _namespaceAliases = new String[result.size()];
            result.toArray(_namespaceAliases);
        } else
            _namespaceAliases = new String[] {};
    }

    /**
     * Print error and exit.
     *
     * @param errorMessage
     *          Error message.
     */
    private static void printErrorAndExit(String errorMessage) {
        Format.println("\nError: " + errorMessage);
        Format.println("\nUse \"xmlo -h\" to get help.");

        System.exit(1);
    }
}