|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
SimpleXPath | Line # 34 | 142 | 68 | 68% |
0.68
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||
(38) | |||
Result | |||
0.48
|
org.qedeq.kernel.bo.module.VisitorContextTest.testContext org.qedeq.kernel.bo.module.VisitorContextTest.testContext | 1 PASS | |
0.48
|
org.qedeq.kernel.bo.latex.GenerateLatexTest.testNegative08 org.qedeq.kernel.bo.latex.GenerateLatexTest.testNegative08 | 1 PASS | |
0.48
|
org.qedeq.kernel.bo.control.QedeqBoFactoryTest.testCreateStringQedeq5 org.qedeq.kernel.bo.control.QedeqBoFactoryTest.testCreateStringQedeq5 | 1 PASS | |
0.48
|
org.qedeq.kernel.bo.control.QedeqBoFactoryTest.testCreateStringQedeq3 org.qedeq.kernel.bo.control.QedeqBoFactoryTest.testCreateStringQedeq3 | 1 PASS | |
0.48
|
org.qedeq.kernel.bo.latex.GenerateLatexTest.testGeneration org.qedeq.kernel.bo.latex.GenerateLatexTest.testGeneration | 1 PASS | |
0.48
|
org.qedeq.kernel.bo.control.LoadRequiredModulesTest.testLoadRequiredModules_07 org.qedeq.kernel.bo.control.LoadRequiredModulesTest.testLoadRequiredModules_07 | 1 PASS | |
0.48
|
org.qedeq.kernel.bo.control.LoadRequiredModulesTest.testLoadRequiredModules_04 org.qedeq.kernel.bo.control.LoadRequiredModulesTest.testLoadRequiredModules_04 | 1 PASS | |
0.48
|
org.qedeq.kernel.bo.control.QedeqBoFactoryTest.testCreateStringQedeq2 org.qedeq.kernel.bo.control.QedeqBoFactoryTest.testCreateStringQedeq2 | 1 PASS | |
0.48
|
org.qedeq.kernel.bo.control.QedeqBoFactoryTest.testCreateStringQedeq6 org.qedeq.kernel.bo.control.QedeqBoFactoryTest.testCreateStringQedeq6 | 1 PASS | |
0.48
|
org.qedeq.kernel.bo.control.QedeqBoFactoryTest.testCreateStringQedeq1 org.qedeq.kernel.bo.control.QedeqBoFactoryTest.testCreateStringQedeq1 | 1 PASS | |
0.48
|
org.qedeq.kernel.bo.latex.ExtendedGenerateLatexTest.testGeneration org.qedeq.kernel.bo.latex.ExtendedGenerateLatexTest.testGeneration | 1 PASS | |
0.48
|
org.qedeq.kernel.bo.latex.GenerateLatexTest.testNegative08 org.qedeq.kernel.bo.latex.GenerateLatexTest.testNegative08 | 1 PASS | |
0.48
|
org.qedeq.kernel.bo.control.QedeqBoFactoryTest.testCreateStringQedeq4 org.qedeq.kernel.bo.control.QedeqBoFactoryTest.testCreateStringQedeq4 | 1 PASS | |
0.448
|
org.qedeq.kernel.bo.latex.GenerateLatexTest.testNegative06 org.qedeq.kernel.bo.latex.GenerateLatexTest.testNegative06 | 1 PASS | |
0.448
|
org.qedeq.kernel.bo.latex.GenerateLatexTest.testNegative06 org.qedeq.kernel.bo.latex.GenerateLatexTest.testNegative06 | 1 PASS | |
0.448
|
org.qedeq.kernel.bo.latex.GenerateLatexTest.testNegative07 org.qedeq.kernel.bo.latex.GenerateLatexTest.testNegative07 | 1 PASS | |
0.448
|
org.qedeq.kernel.bo.latex.GenerateLatexTest.testNegative02 org.qedeq.kernel.bo.latex.GenerateLatexTest.testNegative02 | 1 PASS | |
0.448
|
org.qedeq.kernel.bo.latex.GenerateLatexTest.testNegative02 org.qedeq.kernel.bo.latex.GenerateLatexTest.testNegative02 | 1 PASS | |
0.448
|
org.qedeq.kernel.bo.latex.GenerateLatexTest.testNegative07 org.qedeq.kernel.bo.latex.GenerateLatexTest.testNegative07 | 1 PASS | |
0.44
|
org.qedeq.kernel.bo.latex.GenerateLatexTest.testNegative05 org.qedeq.kernel.bo.latex.GenerateLatexTest.testNegative05 | 1 PASS | |
0.44
|
org.qedeq.kernel.xml.parser.CharsetParserTest.testParse2 org.qedeq.kernel.xml.parser.CharsetParserTest.testParse2 | 1 PASS | |
0.44
|
org.qedeq.kernel.xml.parser.CharsetParserTest.testParse1 org.qedeq.kernel.xml.parser.CharsetParserTest.testParse1 | 1 PASS | |
0.44
|
org.qedeq.kernel.bo.latex.GenerateLatexTest.testNegative05 org.qedeq.kernel.bo.latex.GenerateLatexTest.testNegative05 | 1 PASS | |
0.42
|
org.qedeq.kernel.bo.control.LoadRequiredModulesTest.testLoadRequiredModules_03 org.qedeq.kernel.bo.control.LoadRequiredModulesTest.testLoadRequiredModules_03 | 1 PASS | |
0.42
|
org.qedeq.kernel.bo.control.LoadRequiredModulesTest.testLoadRequiredModules_09 org.qedeq.kernel.bo.control.LoadRequiredModulesTest.testLoadRequiredModules_09 | 1 PASS | |
0.42
|
org.qedeq.kernel.bo.control.LoadRequiredModulesTest.testLoadRequiredModules_02 org.qedeq.kernel.bo.control.LoadRequiredModulesTest.testLoadRequiredModules_02 | 1 PASS | |
0.388
|
org.qedeq.kernel.bo.logic.wf.CheckLogicTest.testNegative02 org.qedeq.kernel.bo.logic.wf.CheckLogicTest.testNegative02 | 1 PASS | |
0.388
|
org.qedeq.kernel.bo.logic.wf.CheckLogicTest.testNegative04 org.qedeq.kernel.bo.logic.wf.CheckLogicTest.testNegative04 | 1 PASS | |
0.388
|
org.qedeq.kernel.bo.logic.wf.CheckLogicTest.testNegative03 org.qedeq.kernel.bo.logic.wf.CheckLogicTest.testNegative03 | 1 PASS | |
0.376
|
org.qedeq.kernel.xml.tracker.XPathLocationParserTest.testGetXPathLocation org.qedeq.kernel.xml.tracker.XPathLocationParserTest.testGetXPathLocation | 1 PASS | |
0.348
|
org.qedeq.kernel.xml.tracker.SimpleXPathTest.testEquals org.qedeq.kernel.xml.tracker.SimpleXPathTest.testEquals | 1 PASS | |
0.192
|
org.qedeq.kernel.xml.tracker.SimpleXPathTest.testSimpleXPath org.qedeq.kernel.xml.tracker.SimpleXPathTest.testSimpleXPath | 1 PASS | |
0.108
|
org.qedeq.kernel.xml.tracker.SimpleXPathTest.testToString org.qedeq.kernel.xml.tracker.SimpleXPathTest.testToString | 1 PASS | |
0.076
|
org.qedeq.kernel.xml.tracker.SimpleXPathTest.testHashCode org.qedeq.kernel.xml.tracker.SimpleXPathTest.testHashCode | 1 PASS | |
0.0080
|
org.qedeq.kernel.xml.tracker.SimpleXPathTest.testGetElementName org.qedeq.kernel.xml.tracker.SimpleXPathTest.testGetElementName | 1 PASS | |
0.0080
|
org.qedeq.kernel.xml.tracker.SimpleXPathTest.testGetAttribute org.qedeq.kernel.xml.tracker.SimpleXPathTest.testGetAttribute | 1 PASS | |
0.0080
|
org.qedeq.kernel.xml.tracker.SimpleXPathTest.testGetElementOccurrence org.qedeq.kernel.xml.tracker.SimpleXPathTest.testGetElementOccurrence | 1 PASS | |
0.0080
|
org.qedeq.kernel.xml.tracker.SimpleXPathTest.testSize org.qedeq.kernel.xml.tracker.SimpleXPathTest.testSize | 1 PASS | |
1 | /* $Id: SimpleXPath.java,v 1.1 2008/07/26 08:00:50 m31 Exp $ | |
2 | * | |
3 | * This file is part of the project "Hilbert II" - http://www.qedeq.org | |
4 | * | |
5 | * Copyright 2000-2008, 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.base.utility.EqualsUtility; | |
25 | import org.qedeq.kernel.common.SourcePosition; | |
26 | ||
27 | ||
28 | /** | |
29 | * Simple XPath like description of a location in an XML file. | |
30 | * | |
31 | * @version $Revision: 1.1 $ | |
32 | * @author Michael Meyling | |
33 | */ | |
34 | public 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 | 32624 | public SimpleXPath(final String xpath) { |
71 | 32624 | elements = new ArrayList(); |
72 | 32624 | numbers = new ArrayList(); |
73 | 32624 | attribute = null; |
74 | 32624 | init(xpath); |
75 | } | |
76 | ||
77 | /** | |
78 | * Empty constructor. | |
79 | */ | |
80 | 97658 | public SimpleXPath() { |
81 | 97658 | elements = new ArrayList(); |
82 | 97658 | numbers = new ArrayList(); |
83 | 97658 | attribute = null; |
84 | } | |
85 | ||
86 | /** | |
87 | * Copy constructor. | |
88 | * | |
89 | * @param original XPath to copy. | |
90 | */ | |
91 | 338744 | public SimpleXPath(final SimpleXPath original) { |
92 | 338744 | elements = new ArrayList(); |
93 | 338744 | numbers = new ArrayList(); |
94 | 338744 | attribute = null; |
95 | 338744 | init(original.toString()); |
96 | } | |
97 | ||
98 | /** | |
99 | * Initialize all object attributes according to XPath parameter. | |
100 | * | |
101 | * @see SimpleXPath#SimpleXPath(String) | |
102 | * | |
103 | * @param xpath String with the syntax as described above. If the syntax is violated | |
104 | * RuntimeExceptions may occur. | |
105 | */ | |
106 | 371368 | private void init(final String xpath) { |
107 | 371368 | if (xpath == null) { |
108 | 0 | throw new NullPointerException(); |
109 | } | |
110 | 371368 | if (xpath.length() <= 0) { |
111 | 1 | throw new RuntimeException("XPath must not be empty"); |
112 | } | |
113 | 371367 | if (xpath.charAt(0) != '/') { |
114 | 2 | throw new RuntimeException("XPath must start with '/': " + xpath); |
115 | } | |
116 | 371365 | if (xpath.indexOf("//") >= 0) { |
117 | 1 | throw new RuntimeException("empty tag not permitted: " + xpath); |
118 | } | |
119 | 371364 | if (xpath.endsWith("/")) { |
120 | 1 | throw new RuntimeException("XPath must not end with '/': " + xpath); |
121 | } | |
122 | 371363 | final StringTokenizer tokenizer = new StringTokenizer(xpath, "/"); |
123 | 2160066 | while (tokenizer.hasMoreTokens()) { |
124 | 1788705 | String token = tokenizer.nextToken(); |
125 | 1788705 | if (!tokenizer.hasMoreTokens() && token.indexOf('@') >= 0) { |
126 | 3689 | attribute = token.substring(token.indexOf('@') + 1); |
127 | 3689 | if (attribute.length() <= 0) { |
128 | 1 | throw new RuntimeException("empty attribute not permitted: " + xpath); |
129 | } | |
130 | 3688 | token = token.substring(0, token.indexOf('@')); |
131 | } | |
132 | 1788704 | if (token.indexOf('[') < 0) { |
133 | 1167433 | elements.add(token); |
134 | 1167433 | numbers.add(new Integer(1)); |
135 | } else { | |
136 | 621271 | final StringTokenizer getnu = new StringTokenizer(token, "[]"); |
137 | 621271 | elements.add(getnu.nextToken()); |
138 | 621271 | final Integer i; |
139 | 621271 | try { |
140 | 621271 | i = new Integer(getnu.nextToken()); |
141 | } catch (RuntimeException e) { | |
142 | 0 | throw new RuntimeException("not an integer: " + xpath, e); |
143 | } | |
144 | 621271 | if (i.intValue() <= 0) { |
145 | 1 | throw new RuntimeException("integer must be greater zero: " + xpath); |
146 | } | |
147 | 621270 | numbers.add(i); |
148 | } | |
149 | } | |
150 | } | |
151 | ||
152 | /** | |
153 | * Get number of collected exceptions. | |
154 | * | |
155 | * @return Number of collected exceptions. | |
156 | */ | |
157 | 294987284 | public final int size() { |
158 | 294987284 | return elements.size(); |
159 | } | |
160 | ||
161 | /** | |
162 | * Get <code>i</code>-th Element name. | |
163 | * | |
164 | * @param i Starts with 0 and must be smaller than {@link #size()}. | |
165 | * @return Wanted element name. | |
166 | */ | |
167 | 137703290 | public final String getElementName(final int i) { |
168 | 137703290 | return (String) elements.get(i); |
169 | } | |
170 | ||
171 | /** | |
172 | * Get <code>i</code>-th occurrence number. | |
173 | * | |
174 | * @param i Starts with 0 and must be smaller than {@link #size()}. | |
175 | * @return Wanted element occurrence number. | |
176 | */ | |
177 | 92137561 | public final int getElementOccurrence(final int i) { |
178 | 92137561 | return ((Integer) numbers.get(i)).intValue(); |
179 | } | |
180 | ||
181 | /** | |
182 | * Add new element to end of XPath. | |
183 | * | |
184 | * @param elementName element to add. | |
185 | */ | |
186 | 0 | public final void addElement(final String elementName) { |
187 | 0 | attribute = null; |
188 | 0 | elements.add(elementName); |
189 | 0 | numbers.add(new Integer(1)); |
190 | } | |
191 | ||
192 | /** | |
193 | * Add new element to end of XPath. | |
194 | * | |
195 | * @param elementName element to add. | |
196 | * @param occurrence Occurrence number of element. Starts with 1. | |
197 | */ | |
198 | 139543877 | public final void addElement(final String elementName, final int occurrence) { |
199 | 139543877 | attribute = null; |
200 | 139543877 | elements.add(elementName); |
201 | 139543877 | numbers.add(new Integer(occurrence)); |
202 | } | |
203 | ||
204 | /** | |
205 | * Get last XPath element name. | |
206 | * | |
207 | * @return Last element name. Could be <code>null</code> if no elements exist. | |
208 | */ | |
209 | 0 | public final String getLastElement() { |
210 | 0 | int size = elements.size(); |
211 | 0 | if (size <= 0) { |
212 | 0 | return null; |
213 | } | |
214 | 0 | return (String) elements.get(size - 1); |
215 | } | |
216 | ||
217 | /** | |
218 | * Get XPath element name before last. | |
219 | * | |
220 | * @return Before last element name. Could be <code>null</code> if no more than one element | |
221 | * exist. | |
222 | */ | |
223 | 0 | public final String getBeforeLastElement() { |
224 | 0 | int size = elements.size(); |
225 | 0 | if (size <= 1) { |
226 | 0 | return null; |
227 | } | |
228 | 0 | return (String) elements.get(size - 2); |
229 | } | |
230 | ||
231 | /** | |
232 | * Delete last XPath element if any. | |
233 | */ | |
234 | 139248532 | public void deleteLastElement() { |
235 | 139248532 | int size = elements.size(); |
236 | 139248532 | if (size > 0) { |
237 | 139248532 | elements.remove(size - 1); |
238 | 139248532 | numbers.remove(size - 1); |
239 | 139248532 | attribute = null; |
240 | } | |
241 | } | |
242 | ||
243 | /** | |
244 | * Set attribute. | |
245 | * | |
246 | * @param attribute Attribute, maybe <code>null</code>. | |
247 | */ | |
248 | 768215 | public final void setAttribute(final String attribute) { |
249 | 768215 | this.attribute = attribute; |
250 | } | |
251 | ||
252 | /** | |
253 | * Get attribute. | |
254 | * | |
255 | * @return Attribute, maybe <code>null</code>. | |
256 | */ | |
257 | 443934 | public final String getAttribute() { |
258 | 443934 | return attribute; |
259 | } | |
260 | ||
261 | /** | |
262 | * Set starting location of XPath. | |
263 | * | |
264 | * @param position Starting point of this XPath. | |
265 | */ | |
266 | 35974 | public final void setStartLocation(final SourcePosition position) { |
267 | 35974 | start = position; |
268 | } | |
269 | ||
270 | /** | |
271 | * Get start location. | |
272 | * | |
273 | * @return File position. | |
274 | */ | |
275 | 32705 | public final SourcePosition getStartLocation() { |
276 | 32705 | return start; |
277 | } | |
278 | ||
279 | /** | |
280 | * Set ending location of XPath. | |
281 | * | |
282 | * @param position Ending point of this XPath. | |
283 | */ | |
284 | 32555 | public final void setEndLocation(final SourcePosition position) { |
285 | 32555 | end = position; |
286 | } | |
287 | ||
288 | /** | |
289 | * Get end location. | |
290 | * | |
291 | * @return File position. | |
292 | */ | |
293 | 32569 | public final SourcePosition getEndLocation() { |
294 | 32569 | return end; |
295 | } | |
296 | ||
297 | 53 | public final boolean equals(final Object obj) { |
298 | 53 | if (!(obj instanceof SimpleXPath)) { |
299 | 0 | return false; |
300 | } | |
301 | 53 | final SimpleXPath other = (SimpleXPath) obj; |
302 | 53 | if (!EqualsUtility.equals(this.getAttribute(), other.getAttribute())) { |
303 | 19 | return false; |
304 | } | |
305 | 34 | final int size = this.size(); |
306 | 34 | if (size != other.size()) { |
307 | 15 | return false; |
308 | } | |
309 | ||
310 | 62 | for (int i = 0; i < size; i++) { |
311 | 51 | if (!EqualsUtility.equals(this.getElementName(i), other.getElementName(i))) { |
312 | 7 | return false; |
313 | } | |
314 | 44 | if (this.getElementOccurrence(i) != other.getElementOccurrence(i)) { |
315 | 1 | return false; |
316 | } | |
317 | } | |
318 | 11 | return true; |
319 | } | |
320 | ||
321 | /** | |
322 | * Are the elements and occurrences of this and another element equal? No special treatment | |
323 | * of "*" elements. | |
324 | * | |
325 | * @param other Compare with this object. | |
326 | * @return Are the elements of this and the parameter object equal? | |
327 | */ | |
328 | 0 | public final boolean equalsElements(final SimpleXPath other) { |
329 | 0 | final int size = this.size(); |
330 | 0 | if (size != other.size()) { |
331 | 0 | return false; |
332 | } | |
333 | ||
334 | 0 | for (int i = 0; i < size; i++) { |
335 | 0 | if (!EqualsUtility.equals(this.getElementName(i), other.getElementName(i))) { |
336 | 0 | return false; |
337 | } | |
338 | 0 | if (getElementOccurrence(i) != other.getElementOccurrence(i)) { |
339 | 0 | return false; |
340 | } | |
341 | } | |
342 | 0 | return true; |
343 | } | |
344 | ||
345 | /** | |
346 | * Match the elements and occurrences of this finder object and current elements? | |
347 | * This object may contain "*" elements. | |
348 | * | |
349 | * @param current Compare with this current elements. These elements should not | |
350 | * contain "*" elements. | |
351 | * @param currentSummary Contains only "*" elements. This parameter must be identify the same | |
352 | * XPath as <code>current</code> | |
353 | * @return Match the elements of this finder object and the parameter objects? | |
354 | */ | |
355 | 138657314 | public final boolean matchesElements(final SimpleXPath current, |
356 | final SimpleXPath currentSummary) { | |
357 | 138657314 | final int size = current.size(); |
358 | 138657314 | if (size != size()) { |
359 | 123144712 | return false; |
360 | } | |
361 | 15512602 | if (size != currentSummary.size()) { |
362 | 0 | throw new IllegalArgumentException("summary size doesn't match"); |
363 | } | |
364 | ||
365 | 45369954 | for (int i = 0; i < size; i++) { |
366 | 45304844 | if ("*".equals(getElementName(i))) { |
367 | 0 | if (getElementOccurrence(i) != currentSummary.getElementOccurrence(i)) { |
368 | 0 | return false; |
369 | } | |
370 | 0 | continue; |
371 | } | |
372 | 45304844 | if (!EqualsUtility.equals(current.getElementName(i), getElementName(i))) { |
373 | 441060 | return false; |
374 | } | |
375 | 44863784 | if (current.getElementOccurrence(i) != getElementOccurrence(i)) { |
376 | 15006432 | return false; |
377 | } | |
378 | } | |
379 | 65110 | return true; |
380 | } | |
381 | ||
382 | /** | |
383 | * Match the elements and occurrences of this finder object and current elements? | |
384 | * This object may contain "*" elements. Checks only to current.size(). | |
385 | * | |
386 | * @param current Compare with this current elements. These elements should not | |
387 | * contain "*" elements. | |
388 | * @param currentSummary Contains only "*" elements. This parameter must be identify the same | |
389 | * XPath as <code>current</code> | |
390 | * @return Match the elements of this finder object and the parameter objects? | |
391 | */ | |
392 | 0 | public final boolean matchesElementsBegining(final SimpleXPath current, |
393 | final SimpleXPath currentSummary) { | |
394 | 0 | final int size = current.size(); |
395 | 0 | if (size > size()) { |
396 | 0 | return false; |
397 | } | |
398 | 0 | if (size != currentSummary.size()) { |
399 | 0 | throw new IllegalArgumentException("summary size doesn't match"); |
400 | } | |
401 | ||
402 | 0 | for (int i = 0; i < size; i++) { |
403 | 0 | if ("*".equals(getElementName(i))) { |
404 | 0 | if (getElementOccurrence(i) != currentSummary.getElementOccurrence(i)) { |
405 | 0 | return false; |
406 | } | |
407 | 0 | continue; |
408 | } | |
409 | 0 | if (!EqualsUtility.equals(current.getElementName(i), getElementName(i))) { |
410 | 0 | return false; |
411 | } | |
412 | 0 | if (current.getElementOccurrence(i) != getElementOccurrence(i)) { |
413 | 0 | return false; |
414 | } | |
415 | } | |
416 | 0 | return true; |
417 | } | |
418 | ||
419 | 371299 | public final String toString() { |
420 | 371299 | final StringBuffer buffer = new StringBuffer(); |
421 | 2159771 | for (int i = 0; i < size(); i++) { |
422 | 1788472 | buffer.append("/"); |
423 | 1788472 | buffer.append(getElementName(i)); |
424 | 1788472 | if (getElementOccurrence(i) != 1) { |
425 | 621249 | buffer.append("["); |
426 | 621249 | buffer.append(getElementOccurrence(i)); |
427 | 621249 | buffer.append("]"); |
428 | } | |
429 | } | |
430 | 371299 | if (getAttribute() != null) { |
431 | 3667 | buffer.append("@"); |
432 | 3667 | buffer.append(getAttribute()); |
433 | } | |
434 | 371299 | return buffer.toString(); |
435 | } | |
436 | ||
437 | 46 | public final int hashCode() { |
438 | 46 | int code = 0; |
439 | 46 | if (attribute != null) { |
440 | 14 | code ^= attribute.hashCode(); |
441 | } | |
442 | 210 | for (int i = 0; i < size(); i++) { |
443 | 164 | code ^= i + 1; |
444 | 164 | code ^= getElementName(i).hashCode(); |
445 | 164 | code ^= getElementOccurrence(i); |
446 | } | |
447 | 46 | return code; |
448 | } | |
449 | ||
450 | } |
|