001/*
002 * #%L
003 * Netarchivesuite - harvester
004 * %%
005 * Copyright (C) 2005 - 2014 The Royal Danish Library, the Danish State and University Library,
006 *             the National Library of France and the Austrian National Library.
007 * %%
008 * This program is free software: you can redistribute it and/or modify
009 * it under the terms of the GNU Lesser General Public License as
010 * published by the Free Software Foundation, either version 2.1 of the
011 * License, or (at your option) any later version.
012 * 
013 * This program is distributed in the hope that it will be useful,
014 * but WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
016 * GNU General Lesser Public License for more details.
017 * 
018 * You should have received a copy of the GNU General Lesser Public
019 * License along with this program.  If not, see
020 * <http://www.gnu.org/licenses/lgpl-2.1.html>.
021 * #L%
022 */
023package dk.netarkivet.common.xml;
024
025import org.w3c.dom.Document;
026import org.w3c.dom.Element;
027import org.w3c.dom.NamedNodeMap;
028import org.w3c.dom.Node;
029import org.w3c.dom.NodeList;
030
031/** Provides functionality for generating xml document nodes ad-hoc for test purposes. The NodeTraverser
032 * uses a builder pattern to chain childnode calls to create multilevel structures. Example <p>
033 *     Node deduplicationNode = NodeTraverser.create(orderxmlDoc).getChildNode("crawl-order", null)
034 .getChildNode("controller", null).getChildNode("map", "write-processors")
035 .getChildNode("newObject", "DeDuplicator").getChildNode("boolean", "enabled").getNode();
036 * </p>
037 */
038public class NodeTraverser {
039    private final Document doc;
040    private Node currentNode;
041
042    public NodeTraverser(Document doc) {
043        this.doc = doc;
044        currentNode = doc;
045    }
046
047    public Node getNode() {
048        return currentNode;
049    }
050
051    public static NodeTraverser create(Document doc) {
052        return new NodeTraverser(doc);
053    }
054
055    /** Will create a NodeTraverser for accessing the indicated node. If the current node does
056     * exist it will be created.
057     * @param element The tag for the element to make available.
058     * @param name A optional name attribute to add to the element if created.
059     * @return The NodeTraverser reference, which can be used to create further child nodes.
060     */
061    public NodeTraverser getChildNode(String element, String name) {
062        Node childNode = null;
063        NodeList nodes = currentNode.getChildNodes();
064        if (nodes != null) {
065            for (int i = 0; i < nodes.getLength(); i++) {
066                Node node = nodes.item(i);
067                NamedNodeMap attributes = node.getAttributes();
068                String nameAttr = null;
069                if (attributes != null) {
070                        Node attrNode = attributes.getNamedItem("name");
071                        if (attrNode != null && attrNode.getNodeType() == Node.ATTRIBUTE_NODE) {
072                                nameAttr = attrNode.getNodeValue();
073                        }
074                }
075                if (element.equals(node.getNodeName()) && (name == null || name.equals(nameAttr))) {
076                    childNode = node;
077                    break;
078                }
079            }
080        }
081        if (childNode == null) {
082            Element newNode = doc.createElement(element);
083            if (name != null) {
084                newNode.setAttribute("name", name);
085            }
086            currentNode.appendChild(newNode);
087            childNode = newNode;
088        }
089        currentNode = childNode;
090
091        return this;
092    }
093}