com.github.lukaszkusek.xml.comparator.document.XMLDocument.java Source code

Java tutorial

Introduction

Here is the source code for com.github.lukaszkusek.xml.comparator.document.XMLDocument.java

Source

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Lukasz Kusek
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

package com.github.lukaszkusek.xml.comparator.document;

import javax.xml.transform.TransformerException;
import java.io.IOException;
import java.io.StringReader;
import java.util.Collection;
import java.util.Map;

import com.github.lukaszkusek.xml.comparator.node.Node;
import com.google.common.base.Predicate;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
import com.google.common.io.CharStreams;

public class XMLDocument {

    private Node rootNode;

    private XMLDocument(String xml, boolean ignoreNamespace) throws TransformerException, IOException {
        rootNode = findRootNode(
                buildNodeTree(createNodeMap(createNodeMultiMap(extractXPathLines(xml, ignoreNamespace)))));
    }

    private Collection<XPathLine> extractXPathLines(String xml, boolean ignoreNamespace)
            throws IOException, TransformerException {

        return CharStreams.readLines(
                new StringInputSupplier(new StringReader(XMLToXPathsTransformer.translate(xml))),
                new XPathLineProcessor(ignoreNamespace));
    }

    private Multimap<String, Node> createNodeMultiMap(Collection<XPathLine> xPathLines) {
        return Multimaps.transformValues(FluentIterable.from(xPathLines).index(XPathLine::getXPath), xPathLine -> {
            Node node = new Node(xPathLine.getIndex(), xPathLine.getXPath());
            node.setValue(xPathLine.getValue());
            node.putAttribute(xPathLine.getAttributeName(), xPathLine.getAttributeValue());

            return node;
        });
    }

    private Map<String, Node> createNodeMap(Multimap<String, Node> xpathToNodeMultimap) {
        return Maps.newHashMap(Maps.transformEntries(xpathToNodeMultimap.asMap(),
                (key, nodes) -> nodes.stream().reduce(Node::merge).get()));
    }

    private Collection<Node> buildNodeTree(Map<String, Node> xpathToNodeMap) {
        xpathToNodeMap.forEach((xPath, child) -> {
            String parentKey = extractParentXPath(xPath);

            if (hasParent(parentKey)) {
                Node parent = xpathToNodeMap.get(parentKey);

                linkChildWithParent(parent, child, xPath);
            }
        });

        return xpathToNodeMap.values();
    }

    private Node findRootNode(Collection<Node> nodes) {
        return FluentIterable.from(nodes).filter(isRoot()).first().get();
    }

    private Predicate<Node> isRoot() {
        return node -> node.getParent() == null;
    }

    private void linkChildWithParent(Node parent, Node child, String childKey) {
        child.setParent(parent);

        parent.addChild(childKey, child);
    }

    private boolean hasParent(String parentKey) {
        return !parentKey.isEmpty();
    }

    private String extractParentXPath(String xPath) {
        return xPath.replaceAll("/[^/]+$", "");
    }

    public static XMLDocument fromXML(String xml, boolean ignoreNamespace)
            throws TransformerException, IOException {
        return new XMLDocument(xml, ignoreNamespace);
    }

    public static XMLDocument fromXML(String xml) throws TransformerException, IOException {
        return new XMLDocument(xml, true);
    }

    public Node getRootNode() {
        return rootNode;
    }

}