Clover coverage report - QedeqKernelSe Coverage Report
Coverage timestamp: Do Jan 11 2007 09:03:50 CET
file stats: LOC: 411   Methods: 23
NCLOC: 217   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
SimpleXPath.java 62,5% 76,5% 91,3% 73,4%
coverage coverage
 1    /* $Id: SimpleXPath.java,v 1.10 2006/10/20 20:23:06 m31 Exp $
 2    *
 3    * This file is part of the project "Hilbert II" - http://www.qedeq.org
 4    *
 5    * Copyright 2000-2006, Michael Meyling <mime@qedeq.org>.
 6    *
 7    * "Hilbert II" is free software; you can redistribute
 8    * it and/or modify it under the terms of the GNU General Public
 9    * License as published by the Free Software Foundation; either
 10    * version 2 of the License, or (at your option) any later version.
 11    *
 12    * This program is distributed in the hope that it will be useful,
 13    * but WITHOUT ANY WARRANTY; without even the implied warranty of
 14    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 15    * GNU General Public License for more details.
 16    */
 17   
 18    package org.qedeq.kernel.xml.tracker;
 19   
 20    import java.util.ArrayList;
 21    import java.util.List;
 22    import java.util.StringTokenizer;
 23   
 24    import org.qedeq.kernel.utility.EqualsUtility;
 25    import org.qedeq.kernel.xml.parser.SourcePosition;
 26   
 27   
 28    /**
 29    * Simple XPath like description of a location in an XML file.
 30    *
 31    * @version $Revision: 1.10 $
 32    * @author Michael Meyling
 33    */
 34    public final class SimpleXPath {
 35   
 36    /** List with element names. */
 37    private final List elements;
 38   
 39    /** List with element occurrence numbers. */
 40    private final List numbers;
 41   
 42    /** Attribute of element. */
 43    private String attribute;
 44   
 45    /** Starting position in source. */
 46    private SourcePosition start;
 47   
 48    /** Ending position in source. */
 49    private SourcePosition end;
 50   
 51    /**
 52    * Constructor with simple XPath string as parameter.
 53    * This is not the standard XPath definition but it is similar to a subset of
 54    * the abbreviation XPath notation.
 55    * <p>
 56    * <code>/element1/element2[3]@attribute</code> is an example for such
 57    * a notation. This selects from the first occurrence of <code>element1</code>
 58    * and from the third occurrence of subnode <code>element2</code> the attribute
 59    * <code>attribute</code>. The attribute is optional. It is always exactly one node or
 60    * the attribute of one node specified.
 61    * <p>
 62    * The general syntax could be described as follows:
 63    * {"/"<em>element</em>"["<em>index</em>"]"}+
 64    * ["@"<em>attribute</em>]
 65    *
 66    *
 67    * @param xpath String with the syntax as described above. If the syntax is violated
 68    * RuntimeExceptions may occur.
 69    */
 70  6368 public SimpleXPath(final String xpath) {
 71  6368 elements = new ArrayList();
 72  6368 numbers = new ArrayList();
 73  6368 attribute = null;
 74  6368 init(xpath);
 75    }
 76   
 77    /**
 78    *
 79    */
 80  6320 public SimpleXPath() {
 81  6320 elements = new ArrayList();
 82  6320 numbers = new ArrayList();
 83  6320 attribute = null;
 84    }
 85   
 86    /**
 87    * Initialize all object attributes according to XPath parameter.
 88    *
 89    * @see SimpleXPath#SimpleXPath(String)
 90    *
 91    * @param xpath String with the syntax as described above. If the syntax is violated
 92    * RuntimeExceptions may occur.
 93    */
 94  6368 private void init(final String xpath) {
 95  6368 final StringTokenizer tokenizer = new StringTokenizer(xpath, "/");
 96  6368 while (tokenizer.hasMoreTokens()) {
 97  36371 String token = tokenizer.nextToken();
 98  36371 if (!tokenizer.hasMoreTokens() && token.indexOf('@') >= 0) {
 99  314 attribute = token.substring(token.indexOf('@') + 1);
 100  314 token = token.substring(0, token.indexOf('@'));
 101    }
 102  36371 if (token.indexOf('[') < 0) {
 103  21513 elements.add(token);
 104  21513 numbers.add(new Integer(1));
 105    } else {
 106  14858 final StringTokenizer getnu = new StringTokenizer(token, "[]");
 107  14858 elements.add(getnu.nextToken());
 108  14858 numbers.add(new Integer(getnu.nextToken()));
 109    }
 110    }
 111    }
 112   
 113    /**
 114    * Get number of collected exceptions.
 115    *
 116    * @return Number of collected exceptions.
 117    */
 118  23841109 public final int size() {
 119  23841109 return elements.size();
 120    }
 121   
 122    /**
 123    * Get <code>i</code>-th Element name.
 124    *
 125    * @param i Starts with 0 and must be smaller than {@link #size()}.
 126    * @return Wanted element name.
 127    */
 128  9879584 public final String getElementName(final int i) {
 129  9879584 return (String) elements.get(i);
 130    }
 131   
 132    /**
 133    * Get <code>i</code>-th occurrence number.
 134    *
 135    * @param i Starts with 0 and must be smaller than {@link #size()}.
 136    * @return Wanted element occurrence number.
 137    */
 138  6674928 public final int getElementOccurrence(final int i) {
 139  6674928 return ((Integer) numbers.get(i)).intValue();
 140    }
 141   
 142    /**
 143    * Add new element to end of XPath.
 144    *
 145    * @param elementName element to add.
 146    */
 147  276 public final void addElement(final String elementName) {
 148  276 elements.add(elementName);
 149  276 numbers.add(new Integer(1));
 150    }
 151   
 152    /**
 153    * Add new element to end of XPath.
 154    *
 155    * @param elementName element to add.
 156    * @param occurrence Occurrence number of element. Starts with 1.
 157    */
 158  11237432 public final void addElement(final String elementName, final int occurrence) {
 159  11237432 elements.add(elementName);
 160  11237432 numbers.add(new Integer(occurrence));
 161    }
 162   
 163    /**
 164    * Get last XPath element name.
 165    *
 166    * @return Last element name. Could be <code>null</code> if no elements exist.
 167    */
 168  3153 public final String getLastElement() {
 169  3153 int size = elements.size();
 170  3153 if (size <= 0) {
 171  0 return null;
 172    }
 173  3153 return (String) elements.get(size - 1);
 174    }
 175   
 176    /**
 177    * Get XPath element name before last.
 178    *
 179    * @return Before last element name. Could be <code>null</code> if no more than one element
 180    * exist.
 181    */
 182  3153 public final String getBeforeLastElement() {
 183  3153 int size = elements.size();
 184  3153 if (size <= 1) {
 185  0 return null;
 186    }
 187  3153 return (String) elements.get(size - 2);
 188    }
 189   
 190    /**
 191    * Delete last XPath element if any.
 192    */
 193  11237765 public void deleteLastElement() {
 194  11237765 int size = elements.size();
 195  11237765 if (size > 0) {
 196  11237765 elements.remove(size - 1);
 197  11237765 numbers.remove(size - 1);
 198  11237765 attribute = null;
 199    }
 200    }
 201   
 202    /**
 203    * Set attribute.
 204    *
 205    * @param attribute Attribute, maybe <code>null</code>.
 206    */
 207  293 public final void setAttribute(final String attribute) {
 208  293 this.attribute = attribute;
 209    }
 210   
 211    /**
 212    * Get attribute.
 213    *
 214    * @return Attribute, maybe <code>null</code>.
 215    */
 216  13457 public final String getAttribute() {
 217  13457 return attribute;
 218    }
 219   
 220    /**
 221    * Set starting location of XPath.
 222    *
 223    * @param position Starting point of this XPath.
 224    */
 225  3455 public final void setStartLocation(final SourcePosition position) {
 226  3455 start = position;
 227    }
 228   
 229    /**
 230    * Get start location.
 231    *
 232    * @return File position.
 233    */
 234  3177 public final SourcePosition getStartLocation() {
 235  3177 return start;
 236    }
 237   
 238    /**
 239    * Set ending location of XPath.
 240    *
 241    * @param position Ending point of this XPath.
 242    */
 243  3160 public final void setEndLocation(final SourcePosition position) {
 244  3160 end = position;
 245    }
 246   
 247    /**
 248    * Get end location.
 249    *
 250    * @return File position.
 251    */
 252  3177 public final SourcePosition getEndLocation() {
 253  3177 return end;
 254    }
 255   
 256  53 public final boolean equals(final Object obj) {
 257  53 if (!(obj instanceof SimpleXPath)) {
 258  0 return false;
 259    }
 260  53 final SimpleXPath other = (SimpleXPath) obj;
 261  53 if (!EqualsUtility.equals(this.getAttribute(), other.getAttribute())) {
 262  19 return false;
 263    }
 264  34 final int size = this.size();
 265  34 if (size != other.size()) {
 266  15 return false;
 267    }
 268   
 269  19 for (int i = 0; i < size; i++) {
 270  51 if (!EqualsUtility.equals(this.getElementName(i), other.getElementName(i))) {
 271  7 return false;
 272    }
 273  44 if (this.getElementOccurrence(i) != other.getElementOccurrence(i)) {
 274  1 return false;
 275    }
 276    }
 277  11 return true;
 278    }
 279   
 280    /**
 281    * Are the elements and occurrences of this and another element equal? No special treatment
 282    * of "*" elements.
 283    *
 284    * @param other Compare with this object.
 285    * @return Are the elements of this and the parameter object equal?
 286    */
 287  0 public final boolean equalsElements(final SimpleXPath other) {
 288  0 final int size = this.size();
 289  0 if (size != other.size()) {
 290  0 return false;
 291    }
 292   
 293  0 for (int i = 0; i < size; i++) {
 294  0 if (!EqualsUtility.equals(this.getElementName(i), other.getElementName(i))) {
 295  0 return false;
 296    }
 297  0 if (getElementOccurrence(i) != other.getElementOccurrence(i)) {
 298  0 return false;
 299    }
 300    }
 301  0 return true;
 302    }
 303   
 304    /**
 305    * Match the elements and occurrences of this finder object and current elements?
 306    * This object may contain "*" elements.
 307    *
 308    * @param current Compare with this current elements. These elements should not
 309    * contain "*" elements.
 310    * @param currentSummary Contains only "*" elements. This parameter must be identify the same
 311    * XPath as <code>current</code>
 312    * @return Match the elements of this finder object and the parameter objects?
 313    */
 314  11237236 public final boolean matchesElements(final SimpleXPath current,
 315    final SimpleXPath currentSummary) {
 316  11237236 final int size = current.size();
 317  11237236 if (size != size()) {
 318  9913538 return false;
 319    }
 320  1323698 if (size != currentSummary.size()) {
 321  0 throw new IllegalArgumentException("summary size doesn't match");
 322    }
 323   
 324  1323698 for (int i = 0; i < size; i++) {
 325  3373602 if ("*".equals(getElementName(i))) {
 326  138824 if (getElementOccurrence(i) != currentSummary.getElementOccurrence(i)) {
 327  118440 return false;
 328    }
 329  20384 continue;
 330    }
 331  3234778 if (!EqualsUtility.equals(current.getElementName(i), getElementName(i))) {
 332  60560 return false;
 333    }
 334  3174218 if (current.getElementOccurrence(i) != getElementOccurrence(i)) {
 335  1138378 return false;
 336    }
 337    }
 338  6320 return true;
 339    }
 340   
 341    /**
 342    * Match the elements and occurrences of this finder object and current elements?
 343    * This object may contain "*" elements. Checks only to current.size().
 344    *
 345    * @param current Compare with this current elements. These elements should not
 346    * contain "*" elements.
 347    * @param currentSummary Contains only "*" elements. This parameter must be identify the same
 348    * XPath as <code>current</code>
 349    * @return Match the elements of this finder object and the parameter objects?
 350    */
 351  0 public final boolean matchesElementsBegining(final SimpleXPath current,
 352    final SimpleXPath currentSummary) {
 353  0 final int size = current.size();
 354  0 if (size > size()) {
 355  0 return false;
 356    }
 357  0 if (size != currentSummary.size()) {
 358  0 throw new IllegalArgumentException("summary size doesn't match");
 359    }
 360   
 361  0 for (int i = 0; i < size; i++) {
 362  0 if ("*".equals(getElementName(i))) {
 363  0 if (getElementOccurrence(i) != currentSummary.getElementOccurrence(i)) {
 364  0 return false;
 365    }
 366  0 continue;
 367    }
 368  0 if (!EqualsUtility.equals(current.getElementName(i), getElementName(i))) {
 369  0 return false;
 370    }
 371  0 if (current.getElementOccurrence(i) != getElementOccurrence(i)) {
 372  0 return false;
 373    }
 374    }
 375  0 return true;
 376    }
 377   
 378  6320 public final String toString() {
 379  6320 final StringBuffer buffer = new StringBuffer();
 380  6320 for (int i = 0; i < size(); i++) {
 381  36140 if (i != 0) {
 382  29820 buffer.append("/");
 383    }
 384  36140 buffer.append(getElementName(i));
 385  36140 if (getElementOccurrence(i) != 1) {
 386  12236 buffer.append("[");
 387  12236 buffer.append(getElementOccurrence(i));
 388  12236 buffer.append("]");
 389    }
 390    }
 391  6320 if (getAttribute() != null) {
 392  295 buffer.append("@");
 393  295 buffer.append(getAttribute());
 394    }
 395  6320 return buffer.toString();
 396    }
 397   
 398  46 public final int hashCode() {
 399  46 int code = 0;
 400  46 if (attribute != null) {
 401  14 code ^= attribute.hashCode();
 402    }
 403  46 for (int i = 0; i < size(); i++) {
 404  164 code ^= i + 1;
 405  164 code ^= getElementName(i).hashCode();
 406  164 code ^= getElementOccurrence(i);
 407    }
 408  46 return code;
 409    }
 410   
 411    }