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

com.mycila.xmltool.XMLDocDefinition Maven / Gradle / Ivy

There is a newer version: 4.4.ga
Show newest version
/**
 * Copyright (C) 2008 Mycila ([email protected])
 *
 * 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 com.mycila.xmltool;

import org.w3c.dom.Attr;
import org.w3c.dom.CDATASection;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.Text;

import javax.xml.namespace.NamespaceContext;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;

import static com.mycila.xmltool.Utils.notEmpty;
import static com.mycila.xmltool.Utils.notNull;
import static javax.xml.XMLConstants.DEFAULT_NS_PREFIX;
import static javax.xml.XMLConstants.NULL_NS_URI;
import static javax.xml.XMLConstants.XMLNS_ATTRIBUTE;
import static javax.xml.XMLConstants.XMLNS_ATTRIBUTE_NS_URI;
import static javax.xml.XMLConstants.XML_NS_PREFIX;
import static javax.xml.XMLConstants.XML_NS_URI;

/**
 * @author Mathieu Carbou ([email protected])
 */
final class XMLDocDefinition implements NamespaceContext {

    private Element root;
    private final Document document;
    private final XMLDocPath xpath;
    private final Map namespaces = new HashMap();
    private final boolean ignoreNamespaces;

    XMLDocDefinition(Node node, boolean ignoreNamespaces) {
        this.ignoreNamespaces = ignoreNamespaces;
        this.document = node instanceof Document ? (Document) node : node.getOwnerDocument();
        this.root = this.document.getDocumentElement();
        xpath = new XMLDocPath(this);
        resetNamespaces();
        readNamespaces();
    }

    XMLDocDefinition addNamespace(String prefix, String namespaceURI) throws XMLDocumentException {
        if (!ignoreNamespaces) {
            notNull("prefix", prefix);
            notNull("namespaceURI", namespaceURI);
            String existing = namespaces.get(prefix);
            if (existing != null && !existing.equals(namespaceURI)) {
                throw new XMLDocumentException("Prefix '%s' is already bound to another namespace '%s'", prefix, namespaces.get(prefix));
            }
            if (!namespaces.values().contains(namespaceURI)) {
                namespaces.put(prefix, namespaceURI);
            }
        }
        return this;
    }

    XMLDocDefinition addDefaultNamespace(String defaultNamespaceURI) {
        if (!ignoreNamespaces) {
            notNull("defaultNamespaceURI", defaultNamespaceURI);
            Iterator i = getPrefixes(defaultNamespaceURI);
            while (i.hasNext()) {
                namespaces.remove(i.next());
            }
            namespaces.put(DEFAULT_NS_PREFIX, defaultNamespaceURI);
            namespaces.put(generatePrefix(), defaultNamespaceURI);
        }
        return this;
    }

    String getEncoding() {
        String enc = document.getXmlEncoding();
        return enc == null ? "UTF-8" : enc;
    }

    Document getDocument() {
        return document;
    }

    Element getRoot() {
        return root;
    }

    XMLDocPath getXpath() {
        return xpath;
    }

    Element createElement(String tagName) {
        notEmpty("tag name", tagName);
        if (ignoreNamespaces && tagName.contains(":")) {
            tagName = tagName.substring(tagName.indexOf(":") + 1);
        }
        return document.createElementNS(getNamespace(tagName), tagName);
    }

    Attr createAttribute(Element current, String name, String value) {
        notEmpty("Attribute name", name);
        if (ignoreNamespaces && name.contains(":")) {
            name = name.substring(name.indexOf(":") + 1);
        }
        Attr attr = document.createAttributeNS(getNamespace(name), name);
        attr.setValue(value);
        current.setAttributeNodeNS(attr);
        return attr;
    }

    Text createText(String text) {
        notNull("Text", text);
        return document.createTextNode(text);
    }

    CDATASection createCDATA(String data) {
        notNull("Data", data);
        return document.createCDATASection(data);
    }

    XMLDocDefinition createRoot(String tagName) {
        root = createElement(tagName);
        document.appendChild(root);
        return this;
    }

    Element rename(Element node, String newNodeName) {
        return rename(node, newNodeName, getNamespace(newNodeName));
    }

    Element renameWithoutNS(Element node, String newNodeName) {
        return rename(node, newNodeName, null);
    }

    Element rename(Element node, String newNodeName, String ns) {
        Element el = (Element) getDocument().renameNode(node, ns, newNodeName);
        if (root.equals(node)) {
            root = el;
        }
        return el;
    }

    public Attr rename(Attr attr, String newTagName) {
        return (Attr) getDocument().renameNode(attr, getNamespace(newTagName), newTagName);
    }

    public Attr renameWithoutNS(Attr attr, String newTagName) {
        return (Attr) getDocument().renameNode(attr, null, newTagName);
    }

    XMLDocDefinition normalize() {
        document.normalizeDocument();
        return this;
    }

    void resetNamespaces() {
        namespaces.clear();
        namespaces.put(XML_NS_PREFIX, XML_NS_URI);
        namespaces.put(XMLNS_ATTRIBUTE, XMLNS_ATTRIBUTE_NS_URI);
        namespaces.put(DEFAULT_NS_PREFIX, NULL_NS_URI);
    }

    private String getNamespace(String tagName) {
        int pos = tagName.indexOf(":");
        return getNamespaceURI(pos == -1 ? DEFAULT_NS_PREFIX : tagName.substring(0, pos));
    }

    void readNamespaces() {
        if (!ignoreNamespaces) {
            Set defNs = new LinkedHashSet();
            for (Node node : xpath.findNodes(root, "//*")) {
                NamedNodeMap attrs = node.getAttributes();
                for (int i = 0; i < attrs.getLength(); i++) {
                    Node attr = attrs.item(i);
                    if (XMLNS_ATTRIBUTE.equals(attr.getNodeName())) {
                        defNs.add(attr.getNodeValue());
                    } else if (XMLNS_ATTRIBUTE.equals(attr.getPrefix())) {
                        addNamespace(attr.getNodeName().substring(6), attr.getNodeValue());
                    }
                }
            }
            for (String ns : defNs) {
                if (defaultNamespaceDefined()) {
                    addNamespace(generatePrefix(), ns);
                } else {
                    addDefaultNamespace(ns);
                }
            }
        }
    }

    private boolean defaultNamespaceDefined() {
        return !NULL_NS_URI.equals(getDefaultNamespace());
    }

    private String getDefaultNamespace() {
        return namespaces.get(DEFAULT_NS_PREFIX);
    }

    private String generatePrefix() {
        String prefix = "ns0";
        int i = 1;
        while (namespaces.keySet().contains(prefix)) {
            prefix = "ns" + i++;
        }
        return prefix;
    }

    public boolean isIgnoreNamespaces() {
        return ignoreNamespaces;
    }

    // Implementation methods. Please read the spec of each methods befores modifying them !

    public String getNamespaceURI(String prefix) {
        if (prefix == null) {
            throw new IllegalArgumentException("prefix cannot be null");
        }
        String namespaceURI = namespaces.get(prefix);
        return namespaceURI == null ? NULL_NS_URI : namespaceURI;
    }

    public String getPrefix(String namespaceURI) {
        if (namespaceURI == null) {
            throw new IllegalArgumentException("namespaceURI cannot be null");
        } else {
            for (Map.Entry entry : namespaces.entrySet()) {
                if (!DEFAULT_NS_PREFIX.equals(entry.getKey()) && entry.getValue().equals(namespaceURI)) {
                    return entry.getKey();
                }
            }
        }
        return null;
    }

    public Iterator getPrefixes(String namespaceURI) {
        if (namespaceURI == null) {
            throw new IllegalArgumentException("namespaceURI cannot be null");
        }
        Set prefixes = new HashSet();
        for (Map.Entry entry : namespaces.entrySet()) {
            if (entry.getValue().equals(namespaceURI)) {
                prefixes.add(entry.getKey());
            }
        }
        return prefixes.iterator();
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy