Home » xmlbeans-2.5.0-src » org.apache » xmlbeans » [javadoc | source]

    1   /*   Copyright 2004 The Apache Software Foundation
    2    *
    3    *   Licensed under the Apache License, Version 2.0 (the "License");
    4    *   you may not use this file except in compliance with the License.
    5    *   You may obtain a copy of the License at
    6    *
    7    *       http://www.apache.org/licenses/LICENSE-2.0
    8    *
    9    *   Unless required by applicable law or agreed to in writing, software
   10    *   distributed under the License is distributed on an "AS IS" BASIS,
   11    *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   12    *   See the License for the specific language governing permissions and
   13    *  limitations under the License.
   14    */
   15   
   16   package org.apache.xmlbeans;
   17   
   18   import javax.xml.namespace.QName;
   19   
   20   import java.util.Set;
   21   import java.util.HashSet;
   22   import java.util.Collections;
   23   import java.util.Iterator;
   24   import java.util.List;
   25   import java.util.ArrayList;
   26   
   27   /**
   28    * Used to build {@link QNameSet QNameSets}.
   29    */ 
   30   public class QNameSetBuilder implements QNameSetSpecification, java.io.Serializable
   31   {
   32       private static final long serialVersionUID = 1L;
   33       
   34       private boolean _inverted;
   35       private Set _includedURIs;
   36       private Set _excludedQNames;
   37       private Set _includedQNames;
   38   
   39       /**
   40        * Constructs an empty QNameSetBuilder.
   41        */
   42       public QNameSetBuilder()
   43       {
   44           _inverted = false;
   45           _includedURIs = new HashSet();
   46           _excludedQNames = new HashSet();
   47           _includedQNames = new HashSet();
   48       }
   49   
   50       /**
   51        * Constructs a QNameSetBuilder whose initial contents are given by
   52        * another QNameSetSpecification.
   53        * @param set the QNameSetSpecificaiton to copy
   54        */
   55       public QNameSetBuilder(QNameSetSpecification set)
   56       {
   57           Set includedURIs = set.includedURIs();
   58           if (includedURIs != null)
   59           {
   60               _inverted = false;
   61               _includedURIs = new HashSet(includedURIs);
   62               _excludedQNames = new HashSet(set.excludedQNamesInIncludedURIs());
   63               _includedQNames = new HashSet(set.includedQNamesInExcludedURIs());
   64           }
   65           else
   66           {
   67               _inverted = true;
   68               _includedURIs = new HashSet(set.excludedURIs());
   69               _excludedQNames = new HashSet(set.includedQNamesInExcludedURIs());
   70               _includedQNames = new HashSet(set.excludedQNamesInIncludedURIs());
   71           }
   72       }
   73   
   74       /**
   75        * Constructs a QNameSetBuilder whose inital contents are given by
   76        * the four sets.  Exactly one of either excludedURIs or includedURIs must
   77        * be non-null.
   78        * 
   79        * @param excludedURIs the finite set of namespace URI strings to exclude from the set, or null if this set is infinite
   80        * @param includedURIs the finite set of namespace URI strings to include in the set, or null if this set is infinite
   81        * @param excludedQNamesInIncludedURIs the finite set of exceptional QNames to exclude from the included namespaces
   82        * @param excludedQNamesInIncludedURIs the finite set of exceptional QNames to include that are in the excluded namespaces
   83        */
   84       public QNameSetBuilder(Set excludedURIs, Set includedURIs, Set excludedQNamesInIncludedURIs, Set includedQNamesInExcludedURIs)
   85       {
   86           if (includedURIs != null && excludedURIs == null)
   87           {
   88               _inverted = false;
   89               _includedURIs = new HashSet(includedURIs);
   90               _excludedQNames = new HashSet(excludedQNamesInIncludedURIs);
   91               _includedQNames = new HashSet(includedQNamesInExcludedURIs);
   92           }
   93           else if (excludedURIs != null && includedURIs == null)
   94           {
   95               _inverted = true;
   96               _includedURIs = new HashSet(excludedURIs);
   97               _excludedQNames = new HashSet(includedQNamesInExcludedURIs);
   98               _includedQNames = new HashSet(excludedQNamesInIncludedURIs);
   99           }
  100           else
  101               throw new IllegalArgumentException("Exactly one of excludedURIs and includedURIs must be null");
  102       }
  103   
  104   
  105       /**
  106        * Constructs a QNameSetBuilder whose initial contents are given
  107        * as a list of namespace URIs, using the same format used by wildcards
  108        * in XSD files.
  109        * 
  110        * @param str a wildcard namespace specification string such as "##any",
  111        *        "##other", "##local", "##targetNamespace", or a space-separated
  112        *        list of URIs.
  113        * @param targetURI the current targetNamespace
  114        */
  115       public QNameSetBuilder(String str, String targetURI)
  116       {
  117           this();
  118   
  119           if (str == null)
  120               str = "##any";
  121   
  122           String[] uri = splitList(str);
  123           for (int i = 0; i < uri.length; i++)
  124           {
  125               String adduri = uri[i];
  126               if (adduri.startsWith("##"))
  127               {
  128                   if (adduri.equals("##other"))
  129                   {
  130                       if (targetURI == null)
  131                           throw new IllegalArgumentException();
  132                       QNameSetBuilder temp = new QNameSetBuilder();
  133                       temp.addNamespace(targetURI);
  134                       temp.addNamespace("");
  135                       temp.invert();
  136                       addAll(temp);
  137                       continue;
  138                   }
  139                   else if (adduri.equals("##any"))
  140                   {
  141                       clear();
  142                       invert();
  143                       continue;
  144                   }
  145                   else if (uri[i].equals("##targetNamespace"))
  146                   {
  147                       if (targetURI == null)
  148                           throw new IllegalArgumentException();
  149                       adduri = targetURI;
  150                   }
  151                   else if (uri[i].equals("##local"))
  152                   {
  153                       adduri = "";
  154                   }
  155               }
  156               addNamespace(adduri);
  157           }
  158       }
  159       
  160       /**
  161        * Local xml names are hased using "" as the namespace.
  162        */
  163       private static String nsFromName(QName QName)
  164       {
  165           String ns = QName.getNamespaceURI();
  166           return ns == null ? "" : ns;
  167       }
  168       
  169       private static final String[] EMPTY_STRINGARRAY = new String[0];
  170       
  171       private static boolean isSpace(char ch)
  172       {
  173           switch (ch)
  174           {
  175               case ' ':
  176               case '\t':
  177               case '\r':
  178               case '\n':
  179                   return true;
  180               default:
  181                   return false;
  182           }
  183       }
  184   
  185       private static String[] splitList(String s)
  186       {
  187           if (s.length() == 0)
  188               return EMPTY_STRINGARRAY;
  189                   
  190           List result = new ArrayList();
  191           int i = 0;
  192           int start = 0;
  193           for (;;)
  194           {
  195               while (i < s.length() && isSpace(s.charAt(i)))
  196                   i += 1;
  197               if (i >= s.length())
  198                   return (String[])result.toArray(EMPTY_STRINGARRAY);
  199               start = i;
  200               while (i < s.length() && !isSpace(s.charAt(i)))
  201                   i += 1;
  202               result.add(s.substring(start, i));
  203           }
  204       }
  205       
  206       /**
  207        * Remove all xml names from qnameset whose namespace matches the uri.
  208        */
  209       private static void removeAllMatchingNs(String uri, Set qnameset)
  210       {
  211           for (Iterator i = qnameset.iterator(); i.hasNext(); )
  212           {
  213               if (uri.equals(nsFromName((QName)i.next())))
  214                   i.remove();
  215           }
  216       }
  217   
  218       /**
  219        * Remove all xml names from qnameset whose namespace is in the
  220        * first set of uris but not the second.
  221        */
  222       private static void removeAllMatchingFirstOnly(Set setFirst, Set setSecond, Set qnameset)
  223       {
  224           for (Iterator i = qnameset.iterator(); i.hasNext(); )
  225           {
  226               String ns = nsFromName((QName)i.next());
  227               if (setFirst.contains(ns) && !setSecond.contains(ns))
  228                   i.remove();
  229           }
  230       }
  231   
  232       /**
  233        * Remove all xml names from qnameset whose namespace is in both
  234        * sets of uris.
  235        */
  236       private static void removeAllMatchingBoth(Set setFirst, Set setSecond, Set qnameset)
  237       {
  238           for (Iterator i = qnameset.iterator(); i.hasNext(); )
  239           {
  240               String ns = nsFromName((QName)i.next());
  241               if (setFirst.contains(ns) && setSecond.contains(ns))
  242                   i.remove();
  243           }
  244       }
  245   
  246       /**
  247        * Remove all xml names from qnameset whose namespace is in neither
  248        * set of uris.
  249        */
  250       private static void removeAllMatchingNeither(Set setFirst, Set setSecond, Set qnameset)
  251       {
  252           for (Iterator i = qnameset.iterator(); i.hasNext(); )
  253           {
  254               String ns = nsFromName((QName)i.next());
  255               if (!setFirst.contains(ns) && !setSecond.contains(ns))
  256                   i.remove();
  257           }
  258       }
  259   
  260       /**
  261        * True if this ModelTransitionSet contains the given qname.
  262        */
  263       public boolean contains(QName name)
  264       {
  265           boolean in = _includedURIs.contains(nsFromName(name)) ?
  266                        !_excludedQNames.contains(name) :
  267                         _includedQNames.contains(name);
  268           return _inverted ^ in;
  269       }
  270   
  271       /**
  272        * True if this ModelTransitionSet contains all QNames.
  273        */
  274       public boolean isAll()
  275       {
  276           return _inverted && _includedURIs.size() == 0 && _includedQNames.size() == 0;
  277       }
  278   
  279       /**
  280        * True if this ModelTransitionSet contains no QNames.
  281        */
  282       public boolean isEmpty()
  283       {
  284           return !_inverted && _includedURIs.size() == 0 && _includedQNames.size() == 0;
  285       }
  286   
  287       /**
  288        * Returns a new QNameSet that is the intersection of this one and another.
  289        */
  290       public QNameSet intersect(QNameSetSpecification set)
  291       {
  292           QNameSetBuilder result = new QNameSetBuilder(this);
  293           result.restrict(set);
  294           return result.toQNameSet();
  295       }
  296   
  297       /**
  298        * Returns a new QNameSet that is the union of this one and another.
  299        */
  300       public QNameSet union(QNameSetSpecification set)
  301       {
  302           QNameSetBuilder result = new QNameSetBuilder(this);
  303           result.addAll(set);
  304           return result.toQNameSet();
  305       }
  306   
  307       /**
  308        * Returns a new QNameSet that is the inverse of this one.
  309        */
  310       public QNameSet inverse()
  311       {
  312           return QNameSet.forSets(includedURIs(), excludedURIs(), includedQNamesInExcludedURIs(), excludedQNamesInIncludedURIs());
  313       }
  314   
  315       /**
  316        * True if the parameter is a subset of this set.
  317        */
  318       public boolean containsAll(QNameSetSpecification set)
  319       {
  320           if (!_inverted && set.excludedURIs() != null)
  321               return false;
  322           
  323           return inverse().isDisjoint(set);
  324       }
  325   
  326       /**
  327        * True if the given set is disjoint from this one.
  328        */
  329       public boolean isDisjoint(QNameSetSpecification set)
  330       {
  331           if (_inverted && set.excludedURIs() != null)
  332               return false;
  333   
  334           if (_inverted)
  335               return isDisjointImpl(set, this);
  336           else
  337               return isDisjointImpl(this, set);
  338       }
  339   
  340       private boolean isDisjointImpl(QNameSetSpecification set1, QNameSetSpecification set2)
  341       {
  342           Set includeURIs = set1.includedURIs();
  343           Set otherIncludeURIs = set2.includedURIs();
  344           if (otherIncludeURIs != null)
  345           {
  346               for (Iterator i = includeURIs.iterator(); i.hasNext(); )
  347               {
  348                   if (otherIncludeURIs.contains(i.next()))
  349                       return false;
  350               }
  351           }
  352           else
  353           {
  354               Set otherExcludeURIs = set2.excludedURIs();
  355               for (Iterator i = includeURIs.iterator(); i.hasNext(); )
  356               {
  357                   if (!otherExcludeURIs.contains(i.next()))
  358                       return false;
  359               }
  360           }
  361   
  362           for (Iterator i = set1.includedQNamesInExcludedURIs().iterator(); i.hasNext(); )
  363           {
  364               if (set2.contains((QName)i.next()))
  365                   return false;
  366           }
  367   
  368           if (includeURIs.size() > 0)
  369               for (Iterator i = set2.includedQNamesInExcludedURIs().iterator(); i.hasNext(); )
  370           {
  371               if (set1.contains((QName)i.next()))
  372                   return false;
  373           }
  374   
  375           return true;
  376       }
  377   
  378   
  379       /**
  380        * Clears this QNameSetBuilder
  381        */
  382       public void clear()
  383       {
  384           _inverted = false;
  385           _includedURIs.clear();
  386           _excludedQNames.clear();
  387           _includedQNames.clear();
  388       }
  389   
  390       /**
  391        * Inverts this QNameSetBuilder.
  392        */
  393       public void invert()
  394       {
  395           _inverted = !_inverted;
  396       }
  397   
  398       /**
  399        * Adds a single QName to this QNameSetBuilder.
  400        */
  401       public void add(QName qname)
  402       {
  403           if (!_inverted)
  404               addImpl(qname);
  405           else
  406               removeImpl(qname);
  407       }
  408   
  409       /**
  410        * Adds an entire namespace URI of QNames to this QNameSetBuilder.
  411        * The empty string is used to signifiy the (local) no-namespace.
  412        */
  413       public void addNamespace(String uri)
  414       {
  415           if (!_inverted)
  416               addNamespaceImpl(uri);
  417           else
  418               removeNamespaceImpl(uri);
  419       }
  420   
  421       /**
  422        * Adds the contents of another QNameSet to this QNameSetBuilder.
  423        */
  424       public void addAll(QNameSetSpecification set)
  425       {
  426           if (_inverted)
  427               removeAllImpl(set.includedURIs(), set.excludedURIs(), set.includedQNamesInExcludedURIs(), set.excludedQNamesInIncludedURIs());
  428           else
  429               addAllImpl(set.includedURIs(), set.excludedURIs(), set.includedQNamesInExcludedURIs(), set.excludedQNamesInIncludedURIs());
  430       }
  431   
  432       /**
  433        * Removes the given qname from this QNameSetBuilder.
  434        */
  435       public void remove(QName qname)
  436       {
  437           if (_inverted)
  438               addImpl(qname);
  439           else
  440               removeImpl(qname);
  441       }
  442   
  443       /**
  444        * Removes an entire namespace URI from this QNameSetBuilder.
  445        */
  446       public void removeNamespace(String uri)
  447       {
  448           if (_inverted)
  449               addNamespaceImpl(uri);
  450           else
  451               removeNamespaceImpl(uri);
  452       }
  453   
  454       /**
  455        * Removes all contents of a given QNameSet from this QNameSetBuilder.
  456        */
  457       public void removeAll(QNameSetSpecification set)
  458       {
  459           if (_inverted)
  460               addAllImpl(set.includedURIs(), set.excludedURIs(), set.includedQNamesInExcludedURIs(), set.excludedQNamesInIncludedURIs());
  461           else
  462               removeAllImpl(set.includedURIs(), set.excludedURIs(), set.includedQNamesInExcludedURIs(), set.excludedQNamesInIncludedURIs());
  463       }
  464   
  465       /**
  466        * Restricts the contents of this QNameSetBuilder to be a subset of the
  467        * given QNameSet. In other words, computes an intersection.
  468        */
  469       public void restrict(QNameSetSpecification set)
  470       {
  471           if (_inverted)
  472               addAllImpl(set.excludedURIs(), set.includedURIs(), set.excludedQNamesInIncludedURIs(), set.includedQNamesInExcludedURIs());
  473           else
  474               removeAllImpl(set.excludedURIs(), set.includedURIs(), set.excludedQNamesInIncludedURIs(), set.includedQNamesInExcludedURIs());
  475       }
  476   
  477       /**
  478        * Implementation of add(qname) that ignores inversion.
  479        */
  480       private void addImpl(QName qname)
  481       {
  482           if (_includedURIs.contains(nsFromName(qname)))
  483               _excludedQNames.remove(qname);
  484           else
  485               _includedQNames.add(qname);
  486       }
  487   
  488       /**
  489        * Implementation of add(ns) that ignores inversion.
  490        */
  491       private void addNamespaceImpl(String uri)
  492       {
  493           if (_includedURIs.contains(uri))
  494           {
  495               removeAllMatchingNs(uri, _excludedQNames);
  496           }
  497           else
  498           {
  499               removeAllMatchingNs(uri, _includedQNames);
  500               _includedURIs.add(uri);
  501           }
  502       }
  503   
  504       /**
  505        * Implementation of add(set) that ignores inversion.
  506        */
  507       private void addAllImpl(Set includedURIs, Set excludedURIs, Set includedQNames, Set excludedQNames)
  508       {
  509           boolean exclude = (excludedURIs != null);
  510           Set specialURIs = exclude ? excludedURIs : includedURIs;
  511   
  512           for (Iterator i = _excludedQNames.iterator(); i.hasNext(); )
  513           {
  514               QName name = (QName)i.next();
  515               String uri = nsFromName(name);
  516               if ((exclude ^ specialURIs.contains(uri)) && !excludedQNames.contains(name))
  517                   i.remove();
  518           }
  519   
  520           for (Iterator i = excludedQNames.iterator(); i.hasNext(); )
  521           {
  522               QName name = (QName)i.next();
  523               String uri = nsFromName(name);
  524               if (!_includedURIs.contains(uri) && !_includedQNames.contains(name))
  525                   _excludedQNames.add(name);
  526           }
  527   
  528           for (Iterator i = includedQNames.iterator(); i.hasNext(); )
  529           {
  530               QName name = (QName)i.next();
  531               String uri = nsFromName(name);
  532               if (!_includedURIs.contains(uri))
  533                   _includedQNames.add(name);
  534               else
  535                   _excludedQNames.remove(name);
  536           }
  537   
  538           if (!exclude)
  539           {
  540               removeAllMatchingFirstOnly(includedURIs, _includedURIs, _includedQNames);
  541               _includedURIs.addAll(includedURIs);
  542           }
  543           else
  544           {
  545               removeAllMatchingNeither(excludedURIs, _includedURIs, _includedQNames);
  546               for (Iterator i = _includedURIs.iterator(); i.hasNext(); )
  547               {
  548                   String uri = (String)i.next();
  549                   if (!excludedURIs.contains(uri))
  550                       i.remove();
  551               }
  552   
  553               for (Iterator i = excludedURIs.iterator(); i.hasNext(); )
  554               {
  555                   String uri = (String)i.next();
  556                   if (!_includedURIs.contains(uri))
  557                       _includedURIs.add(uri);
  558                   else
  559                       _includedURIs.remove(uri);
  560               }
  561               Set temp = _excludedQNames;
  562               _excludedQNames = _includedQNames;
  563               _includedQNames = temp;
  564               _inverted = !_inverted;
  565           }
  566       }
  567   
  568       /**
  569        * Implementation of remove(qname) that ignores inversion.
  570        */
  571       private void removeImpl(QName qname)
  572       {
  573           if (_includedURIs.contains(nsFromName(qname)))
  574               _excludedQNames.add(qname);
  575           else
  576               _includedQNames.remove(qname);
  577       }
  578   
  579       /**
  580        * Implementation of remove(ns) that ignores inversion.
  581        */
  582       private void removeNamespaceImpl(String uri)
  583       {
  584           if (_includedURIs.contains(uri))
  585           {
  586               removeAllMatchingNs(uri, _excludedQNames);
  587               _includedURIs.remove(uri);
  588           }
  589           else
  590           {
  591               removeAllMatchingNs(uri, _includedQNames);
  592           }
  593       }
  594   
  595       /**
  596        * Implementation of remove(set) that ignores inversion.
  597        */
  598       private void removeAllImpl(Set includedURIs, Set excludedURIs, Set includedQNames, Set excludedQNames)
  599       {
  600           boolean exclude = (excludedURIs != null);
  601           Set specialURIs = exclude ? excludedURIs : includedURIs;
  602   
  603           for (Iterator i = _includedQNames.iterator(); i.hasNext(); )
  604           {
  605               QName name = (QName)i.next();
  606               String uri = nsFromName(name);
  607               if (exclude ^ specialURIs.contains(uri))
  608               {
  609                   if (!excludedQNames.contains(name))
  610                       i.remove();
  611               }
  612               else
  613               {
  614                   if (includedQNames.contains(name))
  615                       i.remove();
  616               }
  617           }
  618   
  619           for (Iterator i = includedQNames.iterator(); i.hasNext(); )
  620           {
  621               QName name = (QName)i.next();
  622               String uri = nsFromName(name);
  623               if (_includedURIs.contains(uri))
  624                   _excludedQNames.add(name);
  625           }
  626   
  627           for (Iterator i = excludedQNames.iterator(); i.hasNext(); )
  628           {
  629               QName name = (QName)i.next();
  630               String uri = nsFromName(name);
  631               if (_includedURIs.contains(uri) && !_excludedQNames.contains(name))
  632                   _includedQNames.add(name);
  633           }
  634   
  635           if (exclude)
  636           {
  637               removeAllMatchingFirstOnly(_includedURIs, excludedURIs, _excludedQNames);
  638           }
  639           else
  640           {
  641               removeAllMatchingBoth(_includedURIs, includedURIs, _excludedQNames);
  642           }
  643   
  644           for (Iterator i = _includedURIs.iterator(); i.hasNext(); )
  645           {
  646               if (exclude ^ specialURIs.contains(i.next()))
  647                   i.remove();
  648           }
  649       }
  650   
  651       public Set excludedURIs()
  652       {
  653           if (_inverted) return Collections.unmodifiableSet(_includedURIs);
  654           return null;
  655       }
  656   
  657       public Set includedURIs()
  658       {
  659           if (!_inverted) return _includedURIs;
  660           return null;
  661       }
  662   
  663       public Set excludedQNamesInIncludedURIs()
  664       {
  665           return Collections.unmodifiableSet(_inverted ? _includedQNames : _excludedQNames);
  666       }
  667   
  668       public Set includedQNamesInExcludedURIs()
  669       {
  670           return Collections.unmodifiableSet(_inverted ? _excludedQNames : _includedQNames);
  671       }
  672   
  673       private String prettyQName(QName name)
  674       {
  675           if (name.getNamespaceURI() == null)
  676               return name.getLocalPart();
  677           return name.getLocalPart() + "@" + name.getNamespaceURI();
  678       }
  679   
  680       /**
  681        * Returns a string representation useful for debugging, subject to change.
  682        */ 
  683       public String toString()
  684       {
  685           StringBuffer sb = new StringBuffer();
  686           sb.append("QNameSetBuilder");
  687           sb.append(_inverted ? "-(" : "+(");
  688           for (Iterator i = _includedURIs.iterator(); i.hasNext(); )
  689           {
  690               sb.append("+*@");
  691               sb.append(i.next());
  692               sb.append(", ");
  693           }
  694           for (Iterator i = _excludedQNames.iterator(); i.hasNext(); )
  695           {
  696               sb.append("-");
  697               sb.append(prettyQName((QName)i.next()));
  698               sb.append(", ");
  699           }
  700           for (Iterator i = _includedQNames.iterator(); i.hasNext(); )
  701           {
  702               sb.append("+");
  703               sb.append(prettyQName((QName)i.next()));
  704               sb.append(", ");
  705           }
  706           int index = sb.lastIndexOf(", ");
  707           if (index > 0)
  708               sb.setLength(index);
  709           sb.append(')');
  710           return sb.toString();
  711       }
  712       
  713       /**
  714        * Returns a {@link QNameSet} equivalent to the current state of this
  715        * QNameSetBuilder.
  716        */ 
  717       public QNameSet toQNameSet()
  718       {
  719           return QNameSet.forSpecification(this);
  720       }
  721   }

Home » xmlbeans-2.5.0-src » org.apache » xmlbeans » [javadoc | source]