EMMA Coverage Report (generated Fri Feb 14 08:28:31 UTC 2014)
[all classes][org.qedeq.kernel.xml.tracker]

COVERAGE SUMMARY FOR SOURCE FILE [SimpleXPath.java]

nameclass, %method, %block, %line, %
SimpleXPath.java100% (1/1)80%  (16/20)77%  (487/632)76%  (107/140)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class SimpleXPath100% (1/1)80%  (16/20)77%  (487/632)76%  (107/140)
addElement (String): void 0%   (0/1)0%   (0/17)0%   (0/4)
getBeforeLastElement (): String 0%   (0/1)0%   (0/17)0%   (0/4)
getLastElement (): String 0%   (0/1)0%   (0/16)0%   (0/4)
matchesElementsBegining (SimpleXPath, SimpleXPath): boolean 0%   (0/1)0%   (0/61)0%   (0/14)
matchesElements (SimpleXPath, SimpleXPath): boolean 100% (1/1)77%  (47/61)79%  (11/14)
equals (Object): boolean 100% (1/1)90%  (18/20)83%  (5/6)
init (String): void 100% (1/1)90%  (169/187)91%  (29/32)
SimpleXPath (): void 100% (1/1)100% (16/16)100% (5/5)
SimpleXPath (SimpleXPath): void 100% (1/1)100% (20/20)100% (6/6)
SimpleXPath (String): void 100% (1/1)100% (19/19)100% (6/6)
addElement (String, int): void 100% (1/1)100% (17/17)100% (4/4)
deleteLastElement (): void 100% (1/1)100% (24/24)100% (6/6)
equalsElements (SimpleXPath): boolean 100% (1/1)100% (37/37)100% (9/9)
getAttribute (): String 100% (1/1)100% (3/3)100% (1/1)
getElementName (int): String 100% (1/1)100% (6/6)100% (1/1)
getElementOccurrence (int): int 100% (1/1)100% (7/7)100% (1/1)
hashCode (): int 100% (1/1)100% (40/40)100% (8/8)
setAttribute (String): void 100% (1/1)100% (4/4)100% (2/2)
size (): int 100% (1/1)100% (4/4)100% (1/1)
toString (): String 100% (1/1)100% (56/56)100% (12/12)

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

[all classes][org.qedeq.kernel.xml.tracker]
EMMA 2.1.5320 (stable) (C) Vladimir Roubtsov