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

org.apache.xmlbeans.QNameSet Maven / Gradle / Ivy

There is a newer version: 2024.11.18751.20241128T090041Z-241100
Show newest version
/*   Copyright 2004 The Apache Software Foundation
 *
 *   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.apache.xmlbeans;

import javax.xml.namespace.QName;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

/**
 * This interface represents a lattice of finite and infinite sets of QNames.
 * The lattice the minimal one that is closed under union, intersection, and
 * inverse, and contains individual QNames as well as entire namespaces.
 * Here is a summary of the two kinds of QNameSets:
 * 
    *
  • A QNameSet can cover a finite set of namespaces, additionally including a finite * set of QNames outside those namespaces, and with the exception of * a finite set of QNames excluded from those namespaes: *
      *
    • excludedQNamesInIncludedURIs == the set of excluded QNames from coveredURIs namespaces *
    • excludedURIs == null *
    • includedURIs == the set of covered namespace URIs *
    • includedQNamesInExcludedURIs == set of additional QNames outside coveredURIs namespaces *
    *
  • *
  • A QNameSet can cover all namespaces except for a finite number of excluded ones, * additionally including a finite set of QNames within the excluded namespaces, * and with the exception of a finite set of QNames outside the excluded namespaces: *
      *
    • excludedQNamesInIncludedURIs == the set of excluded QNames outside uncoveredURIs namespaces *
    • excludedURIs == the set of uncovered namespace URIs *
    • includedURIs == null *
    • includedQNamesInExcludedURIs == set of additional QNames from uncoveredURIs namespaces *
    *
  • *
*

* Notice that a finite set of QNames is a degenerate case of the first * category outlined above: *

    *
  • A QnameSet can contain a finite number of QNames: *
      *
    • excludedQNamesInIncludedURIs == empty set *
    • excludedURIs == null *
    • includedURIs == empty set *
    • includedQNamesInExcludedURIs == set of included QNames *
    *
  • *
* * @see QNameSetBuilder */ public final class QNameSet implements QNameSetSpecification, java.io.Serializable { private static final long serialVersionUID = 1L; private final boolean _inverted; private final Set _includedURIs; private final Set _excludedQNames; private final Set _includedQNames; /** * The empty QNameSet. */ public static final QNameSet EMPTY = new QNameSet(null, Collections.emptySet(), Collections.emptySet(), Collections.emptySet()); /** * The QNameSet containing all QNames. */ public static final QNameSet ALL = new QNameSet(Collections.emptySet(), null, Collections.emptySet(), Collections.emptySet()); /** * The QNameSet containing all QNames in the local (no-)namespace. */ public static final QNameSet LOCAL = new QNameSet(null, Collections.singleton(""), Collections.emptySet(), Collections.emptySet()); /** * The QNameSet containing all QNames except for those in the local (no-)namespace. */ public static final QNameSet NONLOCAL = new QNameSet(Collections.singleton(""), null, Collections.emptySet(), Collections.emptySet()); /** * Private function to minimize object creation when copying sets. */ private static Set minSetCopy(Set original) { if (original == null) { return null; } if (original.isEmpty()) { return Collections.emptySet(); } if (original.size() == 1) { return Collections.singleton(original.iterator().next()); } return new HashSet<>(original); } /** * Returns a QNameSet based on the given sets of excluded URIs, * included URIs, excluded QNames in included namespaces, and included * QNames in excluded namespaces. * * @param excludedURIs the finite set of namespace URI strings to exclude from the set, or null if this set is infinite * @param includedURIs the finite set of namespace URI strings to include in the set, or null if this set is infinite * @param excludedQNamesInIncludedURIs the finite set of exceptional QNames to exclude from the included namespaces * @param includedQNamesInExcludedURIs the finite set of exceptional QNames to include that are in the excluded namespaces * @return the constructed QNameSet */ public static QNameSet forSets(Set excludedURIs, Set includedURIs, Set excludedQNamesInIncludedURIs, Set includedQNamesInExcludedURIs) { if ((excludedURIs != null) == (includedURIs != null)) { throw new IllegalArgumentException("Exactly one of excludedURIs and includedURIs must be null"); } if (excludedURIs == null && includedURIs.isEmpty() && includedQNamesInExcludedURIs.isEmpty()) { return EMPTY; } if (includedURIs == null && excludedURIs.isEmpty() && excludedQNamesInIncludedURIs.isEmpty()) { return ALL; } if (excludedURIs == null && includedURIs.size() == 1 && includedURIs.contains("") && includedQNamesInExcludedURIs.isEmpty() && excludedQNamesInIncludedURIs.isEmpty()) { return LOCAL; } if (includedURIs == null && excludedURIs.size() == 1 && excludedURIs.contains("") && excludedQNamesInIncludedURIs.isEmpty() && includedQNamesInExcludedURIs.isEmpty()) { return NONLOCAL; } return new QNameSet( minSetCopy(excludedURIs), minSetCopy(includedURIs), minSetCopy(excludedQNamesInIncludedURIs), minSetCopy(includedQNamesInExcludedURIs)); } /** * Returns a QNameSet based on the given array of included QNames * * @param includedQNames the array of included QNames */ public static QNameSet forArray(QName[] includedQNames) { if (includedQNames == null) { throw new IllegalArgumentException("includedQNames cannot be null"); } return new QNameSet(null, Collections.emptySet(), Collections.emptySet(), new HashSet<>(Arrays.asList(includedQNames))); } /** * Returns a QNameSet with the same contents as the given * QNameSetSpecification. * * @return the copied QNameSet */ public static QNameSet forSpecification(QNameSetSpecification spec) { if (spec instanceof QNameSet) { return (QNameSet) spec; } return QNameSet.forSets(spec.excludedURIs(), spec.includedURIs(), spec.excludedQNamesInIncludedURIs(), spec.includedQNamesInExcludedURIs()); } /** * Returns a QNameSet corresponding to the given wildcard namespace string. * This is a space-separated list of URIs, plus special tokens as specified * in the XML Schema specification (##any, ##other, ##targetNamespace, ##local). * * @return the constructed QNameSet */ public static QNameSet forWildcardNamespaceString(String wildcard, String targetURI) { return QNameSet.forSpecification(new QNameSetBuilder(wildcard, targetURI)); } /** * Returns a QNameSet containing only the given QName. * * @return the constructed QNameSet */ public static QNameSet singleton(QName name) { return new QNameSet(null, Collections.emptySet(), Collections.emptySet(), Collections.singleton(name)); } /** * Constructs a QNameSetBuilder whose contents are given by * the four sets. *

* This constuctor is PRIVATE because it uses the given * sets directly, and it trusts its callers to set only immutable values. * This constructor is is only called by the static builder methods on * QNameSet: those methods are all careful assign only unchanging sets. */ private QNameSet(Set excludedURIs, Set includedURIs, Set excludedQNamesInIncludedURIs, Set includedQNamesInExcludedURIs) { if (includedURIs != null && excludedURIs == null) { _inverted = false; _includedURIs = includedURIs; _excludedQNames = excludedQNamesInIncludedURIs; _includedQNames = includedQNamesInExcludedURIs; } else if (excludedURIs != null && includedURIs == null) { _inverted = true; _includedURIs = excludedURIs; _excludedQNames = includedQNamesInExcludedURIs; _includedQNames = excludedQNamesInIncludedURIs; } else { throw new IllegalArgumentException("Exactly one of excludedURIs and includedURIs must be null"); } } /** * Local xml names are hased using "" as the namespace. */ private static String nsFromName(QName xmlName) { String ns = xmlName.getNamespaceURI(); return ns == null ? "" : ns; } /** * True if this ModelTransitionSet contains the given qname. */ public boolean contains(QName name) { boolean in = _includedURIs.contains(nsFromName(name)) ? !_excludedQNames.contains(name) : _includedQNames.contains(name); return _inverted ^ in; } /** * True if this ModelTransitionSet contains all QNames. */ public boolean isAll() { return _inverted && _includedURIs.isEmpty() && _includedQNames.isEmpty(); } /** * True if this ModelTransitionSet contains no QNames. */ public boolean isEmpty() { return !_inverted && _includedURIs.isEmpty() && _includedQNames.isEmpty(); } /** * Returns a new QNameSet that is the intersection of this one and another. * * @param set the set to insersect with * @return the intersection */ public QNameSet intersect(QNameSetSpecification set) { QNameSetBuilder result = new QNameSetBuilder(this); result.restrict(set); return result.toQNameSet(); } /** * Returns a new QNameSet that is the union of this one and another. * * @param set the set to union with * @return the union */ public QNameSet union(QNameSetSpecification set) { QNameSetBuilder result = new QNameSetBuilder(this); result.addAll(set); return result.toQNameSet(); } /** * Returns a new QNameSet that is the inverse of this one. */ public QNameSet inverse() { if (this == EMPTY) { return ALL; } if (this == ALL) { return EMPTY; } if (this == LOCAL) { return NONLOCAL; } if (this == NONLOCAL) { return LOCAL; } return new QNameSet(includedURIs(), excludedURIs(), includedQNamesInExcludedURIs(), excludedQNamesInIncludedURIs()); } /** * True if the given set is a subset of this one. * * @param set the set to test * @return true if this contains all QNames contained by the given set */ public boolean containsAll(QNameSetSpecification set) { // a.contains(b) == a.inverse.isDisjoint(b) if (!_inverted && set.excludedURIs() != null) { return false; } return inverse().isDisjoint(set); } /** * True if the given set is disjoint from this one. * * @param set the set to test * @return true if the set is disjoint from this set */ public boolean isDisjoint(QNameSetSpecification set) { if (_inverted && set.excludedURIs() != null) { return false; } if (_inverted) { return isDisjointImpl(set, this); } else { return isDisjointImpl(this, set); } } private boolean isDisjointImpl(QNameSetSpecification set1, QNameSetSpecification set2) { Set includeURIs = set1.includedURIs(); Set otherIncludeURIs = set2.includedURIs(); if (otherIncludeURIs != null) { if (!Collections.disjoint(includeURIs, otherIncludeURIs)) { return false; } } else { if (!set2.excludedURIs().containsAll(includeURIs)) { return false; } } if (set1.includedQNamesInExcludedURIs().stream().anyMatch(set2::contains)) { return false; } if (set2.includedQNamesInExcludedURIs().stream().anyMatch(set1::contains)) { return false; } return true; } /** * Namespaces that are fully excluded from the set except for a finite * number of individual QName exceptions. Returns null if this set is infinite. * * @return the set of excluded namespace URI strings */ public Set excludedURIs() { if (_inverted) { return Collections.unmodifiableSet(_includedURIs); } return null; } /** * Namespaces that are fully included in set except for a finite * number of individual QName exceptions. Returns null if this set is infinite. * * @return the set of included namespace URI strings */ public Set includedURIs() { if (!_inverted) { return _includedURIs; } return null; } /** * The set of QNames excluded from the set even though they are within * a namespace that is otherwise fully included in the set. * * @return the set of excluded QNames from within includedURI namespaces */ public Set excludedQNamesInIncludedURIs() { return Collections.unmodifiableSet(_inverted ? _includedQNames : _excludedQNames); } /** * The set of QNames included in the set even though they are within * a namespace that is otherwise fully included in the set. * * @return the set of included QNames from within excludedURI namespaces */ public Set includedQNamesInExcludedURIs() { return Collections.unmodifiableSet(_inverted ? _excludedQNames : _includedQNames); } private String prettyQName(QName name) { if (name.getNamespaceURI() == null) { return name.getLocalPart(); } return name.getLocalPart() + "@" + name.getNamespaceURI(); } /** * Returns a string representation useful for debugging, subject to change. */ public String toString() { StringBuilder sb = new StringBuilder(); sb.append("QNameSet"); sb.append(_inverted ? "-(" : "+("); for (String includedURIs : _includedURIs) { sb.append("+*@"); sb.append(includedURIs); sb.append(", "); } for (QName excludedQName : _excludedQNames) { sb.append("-"); sb.append(prettyQName(excludedQName)); sb.append(", "); } for (QName includedQName : _includedQNames) { sb.append("+"); sb.append(prettyQName(includedQName)); sb.append(", "); } int index = sb.lastIndexOf(", "); if (index > 0) { sb.setLength(index); } sb.append(')'); return sb.toString(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy