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

org.pageseeder.diffx.xml.NamespaceSet Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2010-2021 Allette Systems (Australia)
 *    http://www.allette.com.au
 *
 * 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.pageseeder.diffx.xml;

import javax.xml.XMLConstants;
import java.util.*;

/**
 * Provides a mapping of namespace URIs to prefixes.
 *
 * 

This class can be used to reconstruct the qualified element or attribute names. * *

Note that for each namespace URI there can only be one prefix. * * @author Christophe Lauret * @version 0.9.0 * @since 0.7 */ public final class NamespaceSet extends AbstractCollection implements Collection { /** * Maps namespace URIs to namespace instances. */ private final Map namespacesByUri = new HashMap<>(); /** * Maps prefixes to namespace instances. */ private final Map namespacesByPrefix = new HashMap<>(); public NamespaceSet() { } /** * Create a new prefix mapping with the specified namespace. */ public NamespaceSet(Namespace namespace) { this.namespacesByUri.put(namespace.getUri(), namespace); this.namespacesByPrefix.put(namespace.getPrefix(), namespace); } /** * Merge two prefix mapping and return a new prefix mapping * *

The first prefix mapping takes precedence over the second one, so if a namespace URI is mapped different * prefixes, the prefix from first mapping is used.

* * @return a new prefix mapping including namespaces from both mappings */ public static NamespaceSet noNamespace() { return new NamespaceSet(Namespace.NO_NAMESPACE); } /** * Add the specified mapping if the namespace URI has not been mapped before. * *

This method will ensure that the mapping is actually unique, that is that * the namespace URI correspond to one and only one prefix and that the prefix only * corresponds to one and only one namespace URI. * * @param uri The namespace URI to map. * @param prefix The prefix to use. * * @throws NullPointerException if the URI or prefix is null */ public boolean add(String uri, String prefix) throws NullPointerException { assert uri != null; assert prefix != null; if (!this.namespacesByUri.containsKey(uri)) { int count = 0; String actualPrefix = prefix; while (this.namespacesByPrefix.containsKey(actualPrefix)) { actualPrefix = autoprefix(uri, prefix, count++); } Namespace namespace = new Namespace(uri, actualPrefix); this.namespacesByUri.put(uri, namespace); this.namespacesByPrefix.put(actualPrefix, namespace); return true; } return false; } /** * Computes a prefix if we have a clash. */ private static String autoprefix(String uri, String prefix, int count) { if (prefix.isEmpty()) { Namespace common = Namespace.getCommon(uri); if (common != null) return count == 0 ? common.getPrefix() : common.getPrefix() + count; return "ns" + count; } return prefix + count; } /** * Add the specified mappings if the namespace URI has not been mapped before. */ @Override public boolean add(Namespace namespace) { return add(namespace.getUri(), namespace.getPrefix()); } /** * Add the specified mapping if the namespace URI has not been mapped before. * *

This method will ensure that the mapping is actually unique, that is that * the namespace URI correspond to one and only one prefix and that the prefix only * corresponds to one and only one namespace URI. * * @param uri The namespace URI to map. * @param prefix The prefix to use. * * @throws NullPointerException if the URI or prefix is null */ public Namespace replace(String uri, String prefix) throws NullPointerException { return this.replace(new Namespace(uri, prefix)); } /** * Add the specified mapping if the namespace URI has not been mapped before. * *

This method will ensure that the mapping is actually unique, that is that * the namespace URI correspond to one and only one prefix and that the prefix only * corresponds to one and only one namespace URI. * * @param namespace The namespace declaration to replace. * * @return the previous namespace mapped to this URI * @throws NullPointerException if the URI or prefix is null */ public Namespace replace(Namespace namespace) throws NullPointerException { if (contains(namespace)) return namespace; // Always replace the mapping for namespace URI directly Namespace previous = this.namespacesByUri.put(namespace.getUri(), namespace); if (previous != null) { // If previously mapped we must remove the old prefix mapping this.namespacesByPrefix.remove(previous.getPrefix()); } Namespace matching = this.namespacesByPrefix.put(namespace.getPrefix(), namespace); if (matching != null) { // If previously mapped we must remove the old prefix mapping this.namespacesByUri.remove(matching.getUri()); } // But if prefix already used, we need to remap, but we cannot remap the null namespace if (matching != null && !matching.getUri().equals(XMLConstants.NULL_NS_URI)) { // By adding it again, it will get a new prefix add(matching); } return previous; } /** * Clears the prefix mapping. */ @Override public void clear() { this.namespacesByUri.clear(); this.namespacesByPrefix.clear(); } /** * Returns the size of the */ @Override public int size() { return this.namespacesByUri.size(); } /** * Add the specified mappings if the namespace URI has not been mapped before. * *

This method will ensure that the mappings are actually unique, that is that * the namespace URI correspond to one and only one prefix and that the prefix only * corresponds to one and only one namespace URI. * * @param other more mappings */ public void add(NamespaceSet other) { this.addAll(other); } /** * @return An iterator over the URIs used in this mapping. */ @Override public Iterator iterator() { return Collections.unmodifiableCollection(this.namespacesByUri.values()).iterator(); } /** * @return the prefix mapping as a map. */ public Map toMap() { Map map = new HashMap<>(this.namespacesByUri.values().size()); this.namespacesByUri.values().forEach(namespace -> map.put(namespace.getUri(), namespace.getPrefix())); return map; } /** * Returns the prefix corresponding to the given namespace URI. * * @param uri The namespace URI. * * @return The corresponding prefix or null if not mapped. */ public String getPrefix(String uri) { Namespace namespace = this.namespacesByUri.get(uri); return namespace != null ? namespace.getPrefix() : null; } /** * Returns the prefix corresponding to the given namespace URI. * * @param prefix The namespace prefix. * * @return The corresponding URI or null if not mapped. */ public String getUri(String prefix) { Namespace namespace = this.namespacesByPrefix.get(prefix); return namespace != null ? namespace.getUri() : null; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; NamespaceSet mapping = (NamespaceSet) o; return this.namespacesByUri.equals(mapping.namespacesByUri); } @Override public int hashCode() { return Objects.hash(this.namespacesByUri.values()); } @Override public String toString() { return "(" + this.namespacesByUri.values() + ')'; } /** * Merge two sets of namespaces and return a set. * *

The first namespace takes precedence over the second one, so if a namespace URI is mapped different * prefixes, the prefix from first mapping is used.

* * @return a new set of namespaces including namespaces from both mappings */ public static NamespaceSet merge(NamespaceSet a, NamespaceSet b) { NamespaceSet namespaces = new NamespaceSet(); namespaces.add(a); namespaces.add(b); return namespaces; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy