View Javadoc

    1   /*
    2    * Copyright 2001-2005 (C) MetaStuff, Ltd. All Rights Reserved.
    3    *
    4    * This software is open source.
    5    * See the bottom of this file for the licence.
    6    */
    7
    8   package org.dom4j.util;
    9
    10  import java.util.Comparator;
    11
    12  import org.dom4j.Attribute;
    13  import org.dom4j.Branch;
    14  import org.dom4j.CDATA;
    15  import org.dom4j.CharacterData;
    16  import org.dom4j.Comment;
    17  import org.dom4j.Document;
    18  import org.dom4j.DocumentType;
    19  import org.dom4j.Element;
    20  import org.dom4j.Entity;
    21  import org.dom4j.Namespace;
    22  import org.dom4j.Node;
    23  import org.dom4j.ProcessingInstruction;
    24  import org.dom4j.QName;
    25  import org.dom4j.Text;
    26
    27  /***
    28   * <p>
    29   * <code>NodeComparator</code> is a {@link Comparator}of Node instances which
    30   * is capable of comparing Nodes for equality based on their values.
    31   * </p>
    32   *
    33   * @author <a href="mailto:jstrachan@apache.org">James Strachan </a>
    34   * @version $Revision: 1.10 $
    35   */
    36  public class NodeComparator implements Comparator {
    37      /***
    38       * Compares its two arguments for order. Returns a negative integer, zero,
    39       * or a positive integer as the first argument is less than, equal to, or
    40       * greater than the second.
    41       *
    42       * <p>
    43       * The implementor must ensure that <tt>sgn(compare(x, y)) ==
    44       * -sgn(compare(y, x))</tt>
    45       * for all <tt>x</tt> and <tt>y</tt>. (This implies that
    46       * <tt>compare(x, y)</tt> must throw an exception if and only if
    47       * <tt>compare(y, x)</tt> throws an exception.)
    48       * </p>
    49       *
    50       * <p>
    51       * The implementor must also ensure that the relation is transitive:
    52       * <tt>((compare(x, y)&gt;0) &amp;&amp; (compare(y, z)&gt;0))</tt> implies
    53       * <tt>compare(x, z)&gt;0</tt>.
    54       * </p>
    55       *
    56       * <p>
    57       * Finally, the implementer must ensure that <tt>compare(x, y)==0</tt>
    58       * implies that <tt>sgn(compare(x, z))==sgn(compare(y, z))</tt> for all
    59       * <tt>z</tt>.
    60       * </p>
    61       *
    62       * <p>
    63       * It is generally the case, but <i>not </i> strictly required that
    64       * <tt>(compare(x, y)==0) == (x.equals(y))</tt>. Generally speaking, any
    65       * comparator that violates this condition should clearly indicate this
    66       * fact. The recommended language is "Note: this comparator imposes
    67       * orderings that are inconsistent with equals."
    68       * </p>
    69       *
    70       * @param o1
    71       *            the first object to be compared.
    72       * @param o2
    73       *            the second object to be compared.
    74       *
    75       * @return a negative integer, zero, or a positive integer as the first
    76       *         argument is less than, equal to, or greater than the second.
    77       */
    78      public int compare(Object o1, Object o2) {
    79          if (o1 == o2) {
    80              return 0;
    81          } else if (o1 == null) {
    82              // null is less
    83              return -1;
    84          } else if (o2 == null) {
    85              return 1;
    86          }
    87
    88          if (o1 instanceof Node) {
    89              if (o2 instanceof Node) {
    90                  return compare((Node) o1, (Node) o2);
    91              } else {
    92                  // Node implementations are greater
    93                  return 1;
    94              }
    95          } else {
    96              if (o2 instanceof Node) {
    97                  // Node implementations are greater
    98                  return -1;
    99              } else {
    100                 if (o1 instanceof Comparable) {
    101                     Comparable c1 = (Comparable) o1;
    102
    103                     return c1.compareTo(o2);
    104                 } else {
    105                     String name1 = o1.getClass().getName();
    106                     String name2 = o2.getClass().getName();
    107
    108                     return name1.compareTo(name2);
    109                 }
    110             }
    111         }
    112     }
    113
    114     public int compare(Node n1, Node n2) {
    115         int nodeType1 = n1.getNodeType();
    116         int nodeType2 = n2.getNodeType();
    117         int answer = nodeType1 - nodeType2;
    118
    119         if (answer != 0) {
    120             return answer;
    121         } else {
    122             switch (nodeType1) {
    123                 case Node.ELEMENT_NODE:
    124                     return compare((Element) n1, (Element) n2);
    125
    126                 case Node.DOCUMENT_NODE:
    127                     return compare((Document) n1, (Document) n2);
    128
    129                 case Node.ATTRIBUTE_NODE:
    130                     return compare((Attribute) n1, (Attribute) n2);
    131
    132                 case Node.TEXT_NODE:
    133                     return compare((Text) n1, (Text) n2);
    134
    135                 case Node.CDATA_SECTION_NODE:
    136                     return compare((CDATA) n1, (CDATA) n2);
    137
    138                 case Node.ENTITY_REFERENCE_NODE:
    139                     return compare((Entity) n1, (Entity) n2);
    140
    141                 case Node.PROCESSING_INSTRUCTION_NODE:
    142                     return compare((ProcessingInstruction) n1,
    143                             (ProcessingInstruction) n2);
    144
    145                 case Node.COMMENT_NODE:
    146                     return compare((Comment) n1, (Comment) n2);
    147
    148                 case Node.DOCUMENT_TYPE_NODE:
    149                     return compare((DocumentType) n1, (DocumentType) n2);
    150
    151                 case Node.NAMESPACE_NODE:
    152                     return compare((Namespace) n1, (Namespace) n2);
    153
    154                 default:
    155                     throw new RuntimeException("Invalid node types. node1: "
    156                             + n1 + " and node2: " + n2);
    157             }
    158         }
    159     }
    160
    161     public int compare(Document n1, Document n2) {
    162         int answer = compare(n1.getDocType(), n2.getDocType());
    163
    164         if (answer == 0) {
    165             answer = compareContent(n1, n2);
    166         }
    167
    168         return answer;
    169     }
    170
    171     public int compare(Element n1, Element n2) {
    172         int answer = compare(n1.getQName(), n2.getQName());
    173
    174         if (answer == 0) {
    175             // lets compare attributes
    176             int c1 = n1.attributeCount();
    177             int c2 = n2.attributeCount();
    178             answer = c1 - c2;
    179
    180             if (answer == 0) {
    181                 for (int i = 0; i < c1; i++) {
    182                     Attribute a1 = n1.attribute(i);
    183                     Attribute a2 = n2.attribute(a1.getQName());
    184                     answer = compare(a1, a2);
    185
    186                     if (answer != 0) {
    187                         return answer;
    188                     }
    189                 }
    190
    191                 answer = compareContent(n1, n2);
    192             }
    193         }
    194
    195         return answer;
    196     }
    197
    198     public int compare(Attribute n1, Attribute n2) {
    199         int answer = compare(n1.getQName(), n2.getQName());
    200
    201         if (answer == 0) {
    202             answer = compare(n1.getValue(), n2.getValue());
    203         }
    204
    205         return answer;
    206     }
    207
    208     public int compare(QName n1, QName n2) {
    209         int answer = compare(n1.getNamespaceURI(), n2.getNamespaceURI());
    210
    211         if (answer == 0) {
    212             answer = compare(n1.getQualifiedName(), n2.getQualifiedName());
    213         }
    214
    215         return answer;
    216     }
    217
    218     public int compare(Namespace n1, Namespace n2) {
    219         int answer = compare(n1.getURI(), n2.getURI());
    220
    221         if (answer == 0) {
    222             answer = compare(n1.getPrefix(), n2.getPrefix());
    223         }
    224
    225         return answer;
    226     }
    227
    228     public int compare(CharacterData t1, CharacterData t2) {
    229         return compare(t1.getText(), t2.getText());
    230     }
    231
    232     public int compare(DocumentType o1, DocumentType o2) {
    233         if (o1 == o2) {
    234             return 0;
    235         } else if (o1 == null) {
    236             // null is less
    237             return -1;
    238         } else if (o2 == null) {
    239             return 1;
    240         }
    241
    242         int answer = compare(o1.getPublicID(), o2.getPublicID());
    243
    244         if (answer == 0) {
    245             answer = compare(o1.getSystemID(), o2.getSystemID());
    246
    247             if (answer == 0) {
    248                 answer = compare(o1.getName(), o2.getName());
    249             }
    250         }
    251
    252         return answer;
    253     }
    254
    255     public int compare(Entity n1, Entity n2) {
    256         int answer = compare(n1.getName(), n2.getName());
    257
    258         if (answer == 0) {
    259             answer = compare(n1.getText(), n2.getText());
    260         }
    261
    262         return answer;
    263     }
    264
    265     public int compare(ProcessingInstruction n1, ProcessingInstruction n2) {
    266         int answer = compare(n1.getTarget(), n2.getTarget());
    267
    268         if (answer == 0) {
    269             answer = compare(n1.getText(), n2.getText());
    270         }
    271
    272         return answer;
    273     }
    274
    275     public int compareContent(Branch b1, Branch b2) {
    276         int c1 = b1.nodeCount();
    277         int c2 = b2.nodeCount();
    278         int answer = c1 - c2;
    279
    280         if (answer == 0) {
    281             for (int i = 0; i < c1; i++) {
    282                 Node n1 = b1.node(i);
    283                 Node n2 = b2.node(i);
    284                 answer = compare(n1, n2);
    285
    286                 if (answer != 0) {
    287                     break;
    288                 }
    289             }
    290         }
    291
    292         return answer;
    293     }
    294
    295     public int compare(String o1, String o2) {
    296         if (o1 == o2) {
    297             return 0;
    298         } else if (o1 == null) {
    299             // null is less
    300             return -1;
    301         } else if (o2 == null) {
    302             return 1;
    303         }
    304
    305         return o1.compareTo(o2);
    306     }
    307 }
    308
    309 /*
    310  * Redistribution and use of this software and associated documentation
    311  * ("Software"), with or without modification, are permitted provided that the
    312  * following conditions are met:
    313  *
    314  * 1. Redistributions of source code must retain copyright statements and
    315  * notices. Redistributions must also contain a copy of this document.
    316  *
    317  * 2. Redistributions in binary form must reproduce the above copyright notice,
    318  * this list of conditions and the following disclaimer in the documentation
    319  * and/or other materials provided with the distribution.
    320  *
    321  * 3. The name "DOM4J" must not be used to endorse or promote products derived
    322  * from this Software without prior written permission of MetaStuff, Ltd. For
    323  * written permission, please contact dom4j-info@metastuff.com.
    324  *
    325  * 4. Products derived from this Software may not be called "DOM4J" nor may
    326  * "DOM4J" appear in their names without prior written permission of MetaStuff,
    327  * Ltd. DOM4J is a registered trademark of MetaStuff, Ltd.
    328  *
    329  * 5. Due credit should be given to the DOM4J Project - http://www.dom4j.org
    330  *
    331  * THIS SOFTWARE IS PROVIDED BY METASTUFF, LTD. AND CONTRIBUTORS ``AS IS'' AND
    332  * ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    333  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    334  * ARE DISCLAIMED. IN NO EVENT SHALL METASTUFF, LTD. OR ITS CONTRIBUTORS BE
    335  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    336  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    337  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    338  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    339  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    340  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    341  * POSSIBILITY OF SUCH DAMAGE.
    342  *
    343  * Copyright 2001-2005 (C) MetaStuff, Ltd. All Rights Reserved.
    344  */