Clover coverage report - dom4j - 1.6.1 Coverage timestamp: ma mei 16 2005 14:23:01 GMT+01:00 FRAMES NO FRAMES |
file stats: | LOC: | 493 |  | Methods: | 35
| NCLOC: | 250 |  | Classes: | 1
Source file | Conditionals | Statements | Methods | TOTAL
AbstractBranch.java | 65% | 65,2% | 74,3% | 66,7% |

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.tree;
9 |  |
10 |  | import java.util.ArrayList;
11 |  | import java.util.Iterator;
12 |  | import java.util.List;
13 |  | import java.util.StringTokenizer;
14 |  |
15 |  | import org.dom4j.Branch;
16 |  | import org.dom4j.Comment;
17 |  | import org.dom4j.Element;
18 |  | import org.dom4j.IllegalAddException;
19 |  | import org.dom4j.Namespace;
20 |  | import org.dom4j.Node;
21 |  | import org.dom4j.ProcessingInstruction;
22 |  | import org.dom4j.QName;
23 |  |
24 |  | /**
25 |  | * <p>
26 |  | * <code>AbstractBranch</code> is an abstract base class for tree implementors
27 |  | * to use for implementation inheritence.
28 |  | * </p>
29 |  | *
30 |  | * @author <a href="mailto:jstrachan@apache.org">James Strachan </a>
31 |  | * @version $Revision: 1.44 $
32 |  | */
33 |  | public abstract class AbstractBranch extends AbstractNode implements Branch {
34 |  | protected static final int DEFAULT_CONTENT_LIST_SIZE = 5;
35 |  |
36 | 102292 | public AbstractBranch() {
37 |  | }
38 |  |
39 | 138 | public boolean isReadOnly() {
40 | 138 | return false;
41 |  | }
42 |  |
43 | 0 | public boolean hasContent() {
44 | 0 | return nodeCount() > 0;
45 |  | }
46 |  |
47 | 4891 | public List content() {
48 | 4891 | List backingList = contentList();
49 |  |
50 | 4891 | return new ContentListFacade(this, backingList);
51 |  | }
52 |  |
53 | 80 | public String getText() {
54 | 80 | List content = contentList();
55 |  |
56 | 80 | if (content != null) {
57 | 80 | int size = content.size();
58 |  |
59 | 80 | if (size >= 1) {
60 | 80 | Object first = content.get(0);
61 | 80 | String firstText = getContentAsText(first);
62 |  |
63 | 80 | if (size == 1) {
64 |  | // optimised to avoid StringBuffer creation
65 | 68 | return firstText;
66 |  | } else {
67 | 12 | StringBuffer buffer = new StringBuffer(firstText);
68 |  |
69 | 12 | for (int i = 1; i < size; i++) {
70 | 29 | Object node = content.get(i);
71 | 29 | buffer.append(getContentAsText(node));
72 |  | }
73 |  |
74 | 12 | return buffer.toString();
75 |  | }
76 |  | }
77 |  | }
78 |  |
79 | 0 | return "";
80 |  | }
81 |  |
82 |  | /**
83 |  | * DOCUMENT ME!
84 |  | *
85 |  | * @param content
86 |  | * DOCUMENT ME!
87 |  | *
88 |  | * @return the text value of the given content object as text which returns
89 |  | * the text value of CDATA, Entity or Text nodes
90 |  | */
91 | 202 | protected String getContentAsText(Object content) {
92 | 202 | if (content instanceof Node) {
93 | 202 | Node node = (Node) content;
94 |  |
95 | 202 | switch (node.getNodeType()) {
96 | 2 | case CDATA_SECTION_NODE:
97 |  |
98 |  | // case ENTITY_NODE:
99 | 0 | case ENTITY_REFERENCE_NODE:
100 | 195 | case TEXT_NODE:
101 | 197 | return node.getText();
102 |  |
103 | 5 | default:
104 | 5 | break;
105 |  | }
106 | 0 | } else if (content instanceof String) {
107 | 0 | return (String) content;
108 |  | }
109 |  |
110 | 5 | return "";
111 |  | }
112 |  |
113 |  | /**
114 |  | * DOCUMENT ME!
115 |  | *
116 |  | * @param content
117 |  | * DOCUMENT ME!
118 |  | *
119 |  | * @return the XPath defined string-value of the given content object
120 |  | */
121 | 13 | protected String getContentAsStringValue(Object content) {
122 | 13 | if (content instanceof Node) {
123 | 13 | Node node = (Node) content;
124 |  |
125 | 13 | switch (node.getNodeType()) {
126 | 0 | case CDATA_SECTION_NODE:
127 |  |
128 |  | // case ENTITY_NODE:
129 | 0 | case ENTITY_REFERENCE_NODE:
130 | 11 | case TEXT_NODE:
131 | 2 | case ELEMENT_NODE:
132 | 13 | return node.getStringValue();
133 |  |
134 | 0 | default:
135 | 0 | break;
136 |  | }
137 | 0 | } else if (content instanceof String) {
138 | 0 | return (String) content;
139 |  | }
140 |  |
141 | 0 | return "";
142 |  | }
143 |  |
144 | 77 | public String getTextTrim() {
145 | 77 | String text = getText();
146 |  |
147 | 77 | StringBuffer textContent = new StringBuffer();
148 | 77 | StringTokenizer tokenizer = new StringTokenizer(text);
149 |  |
150 | 77 | while (tokenizer.hasMoreTokens()) {
151 | 99 | String str = tokenizer.nextToken();
152 | 99 | textContent.append(str);
153 |  |
154 | 99 | if (tokenizer.hasMoreTokens()) {
155 | 23 | textContent.append(" "); // separator
156 |  | }
157 |  | }
158 |  |
159 | 77 | return textContent.toString();
160 |  | }
161 |  |
162 | 0 | public void setProcessingInstructions(List listOfPIs) {
163 | 0 | for (Iterator iter = listOfPIs.iterator(); iter.hasNext();) {
164 | 0 | ProcessingInstruction pi = (ProcessingInstruction) iter.next();
165 | 0 | addNode(pi);
166 |  | }
167 |  | }
168 |  |
169 | 0 | public Element addElement(String name) {
170 | 0 | Element node = getDocumentFactory().createElement(name);
171 | 0 | add(node);
172 |  |
173 | 0 | return node;
174 |  | }
175 |  |
176 | 2 | public Element addElement(String qualifiedName, String namespaceURI) {
177 | 2 | Element node = getDocumentFactory().createElement(qualifiedName,
178 |  | namespaceURI);
179 | 2 | add(node);
180 |  |
181 | 2 | return node;
182 |  | }
183 |  |
184 | 86007 | public Element addElement(QName qname) {
185 | 86007 | Element node = getDocumentFactory().createElement(qname);
186 | 86007 | add(node);
187 |  |
188 | 86007 | return node;
189 |  | }
190 |  |
191 | 0 | public Element addElement(String name, String prefix, String uri) {
192 | 0 | Namespace namespace = Namespace.get(prefix, uri);
193 | 0 | QName qName = getDocumentFactory().createQName(name, namespace);
194 |  |
195 | 0 | return addElement(qName);
196 |  | }
197 |  |
198 |  | // polymorphic node methods
199 | 14 | public void add(Node node) {
200 | 14 | switch (node.getNodeType()) {
201 | 14 | case ELEMENT_NODE:
202 | 14 | add((Element) node);
203 |  |
204 | 14 | break;
205 |  |
206 | 0 | case COMMENT_NODE:
207 | 0 | add((Comment) node);
208 |  |
209 | 0 | break;
210 |  |
211 | 0 | case PROCESSING_INSTRUCTION_NODE:
212 | 0 | add((ProcessingInstruction) node);
213 |  |
214 | 0 | break;
215 |  |
216 | 0 | default:
217 | 0 | invalidNodeTypeAddException(node);
218 |  | }
219 |  | }
220 |  |
221 | 2 | public boolean remove(Node node) {
222 | 2 | switch (node.getNodeType()) {
223 | 2 | case ELEMENT_NODE:
224 | 2 | return remove((Element) node);
225 |  |
226 | 0 | case COMMENT_NODE:
227 | 0 | return remove((Comment) node);
228 |  |
229 | 0 | case PROCESSING_INSTRUCTION_NODE:
230 | 0 | return remove((ProcessingInstruction) node);
231 |  |
232 | 0 | default:
233 | 0 | invalidNodeTypeAddException(node);
234 |  |
235 | 0 | return false;
236 |  | }
237 |  | }
238 |  |
239 |  | // typesafe versions using node classes
240 | 24 | public void add(Comment comment) {
241 | 24 | addNode(comment);
242 |  | }
243 |  |
244 | 6291 | public void add(Element element) {
245 | 6291 | addNode(element);
246 |  | }
247 |  |
248 | 25 | public void add(ProcessingInstruction pi) {
249 | 25 | addNode(pi);
250 |  | }
251 |  |
252 | 0 | public boolean remove(Comment comment) {
253 | 0 | return removeNode(comment);
254 |  | }
255 |  |
256 | 2 | public boolean remove(Element element) {
257 | 2 | return removeNode(element);
258 |  | }
259 |  |
260 | 0 | public boolean remove(ProcessingInstruction pi) {
261 | 0 | return removeNode(pi);
262 |  | }
263 |  |
264 | 13 | public Element elementByID(String elementID) {
265 | 13 | for (int i = 0, size = nodeCount(); i < size; i++) {
266 | 31 | Node node = node(i);
267 |  |
268 | 31 | if (node instanceof Element) {
269 | 12 | Element element = (Element) node;
270 | 12 | String id = elementID(element);
271 |  |
272 | 12 | if ((id != null) && id.equals(elementID)) {
273 | 1 | return element;
274 |  | } else {
275 | 11 | element = element.elementByID(elementID);
276 |  |
277 | 11 | if (element != null) {
278 | 2 | return element;
279 |  | }
280 |  | }
281 |  | }
282 |  | }
283 |  |
284 | 10 | return null;
285 |  | }
286 |  |
287 | 143 | public void appendContent(Branch branch) {
288 | 143 | for (int i = 0, size = branch.nodeCount(); i < size; i++) {
289 | 330 | Node node = branch.node(i);
290 | 330 | add((Node) node.clone());
291 |  | }
292 |  | }
293 |  |
294 | 435 | public Node node(int index) {
295 | 435 | Object object = contentList().get(index);
296 |  |
297 | 435 | if (object instanceof Node) {
298 | 435 | return (Node) object;
299 |  | }
300 |  |
301 | 0 | if (object instanceof String) {
302 | 0 | return getDocumentFactory().createText(object.toString());
303 |  | }
304 |  |
305 | 0 | return null;
306 |  | }
307 |  |
308 | 360 | public int nodeCount() {
309 | 360 | return contentList().size();
310 |  | }
311 |  |
312 | 0 | public int indexOf(Node node) {
313 | 0 | return contentList().indexOf(node);
314 |  | }
315 |  |
316 | 313 | public Iterator nodeIterator() {
317 | 313 | return contentList().iterator();
318 |  | }
319 |  |
320 |  | // Implementation methods
321 |  |
322 |  | /**
323 |  | * DOCUMENT ME!
324 |  | *
325 |  | * @param element
326 |  | * DOCUMENT ME!
327 |  | *
328 |  | * @return the ID of the given <code>Element</code>
329 |  | */
330 | 12 | protected String elementID(Element element) {
331 |  | // XXX: there will be other ways of finding the ID
332 |  | // XXX: should probably have an IDResolver or something
333 | 12 | return element.attributeValue("ID");
334 |  | }
335 |  |
336 |  | /**
337 |  | * DOCUMENT ME!
338 |  | *
339 |  | * @return the internal List used to manage the content
340 |  | */
341 |  | protected abstract List contentList();
342 |  |
343 |  | /**
344 |  | * A Factory Method pattern which creates a List implementation used to
345 |  | * store content
346 |  | *
347 |  | * @return DOCUMENT ME!
348 |  | */
349 | 57260 | protected List createContentList() {
350 | 57260 | return new ArrayList(DEFAULT_CONTENT_LIST_SIZE);
351 |  | }
352 |  |
353 |  | /**
354 |  | * A Factory Method pattern which creates a List implementation used to
355 |  | * store content
356 |  | *
357 |  | * @param size
358 |  | * DOCUMENT ME!
359 |  | *
360 |  | * @return DOCUMENT ME!
361 |  | */
362 | 3 | protected List createContentList(int size) {
363 | 3 | return new ArrayList(size);
364 |  | }
365 |  |
366 |  | /**
367 |  | * A Factory Method pattern which creates a BackedList implementation used
368 |  | * to store results of a filtered content query.
369 |  | *
370 |  | * @return DOCUMENT ME!
371 |  | */
372 | 24169 | protected BackedList createResultList() {
373 | 24169 | return new BackedList(this, contentList());
374 |  | }
375 |  |
376 |  | /**
377 |  | * A Factory Method pattern which creates a BackedList implementation which
378 |  | * contains a single result
379 |  | *
380 |  | * @param result
381 |  | * DOCUMENT ME!
382 |  | *
383 |  | * @return DOCUMENT ME!
384 |  | */
385 | 0 | protected List createSingleResultList(Object result) {
386 | 0 | BackedList list = new BackedList(this, contentList(), 1);
387 | 0 | list.addLocal(result);
388 |  |
389 | 0 | return list;
390 |  | }
391 |  |
392 |  | /**
393 |  | * A Factory Method pattern which creates an empty a BackedList
394 |  | * implementation
395 |  | *
396 |  | * @return DOCUMENT ME!
397 |  | */
398 | 2 | protected List createEmptyList() {
399 | 2 | return new BackedList(this, contentList(), 0);
400 |  | }
401 |  |
402 |  | protected abstract void addNode(Node node);
403 |  |
404 |  | protected abstract void addNode(int index, Node node);
405 |  |
406 |  | protected abstract boolean removeNode(Node node);
407 |  |
408 |  | /**
409 |  | * Called when a new child node has been added to me to allow any parent
410 |  | * relationships to be created or events to be fired.
411 |  | *
412 |  | * @param node
413 |  | * DOCUMENT ME!
414 |  | */
415 |  | protected abstract void childAdded(Node node);
416 |  |
417 |  | /**
418 |  | * Called when a child node has been removed to allow any parent
419 |  | * relationships to be deleted or events to be fired.
420 |  | *
421 |  | * @param node
422 |  | * DOCUMENT ME!
423 |  | */
424 |  | protected abstract void childRemoved(Node node);
425 |  |
426 |  | /**
427 |  | * Called when the given List content has been removed so each node should
428 |  | * have its parent and document relationships cleared
429 |  | */
430 | 8 | protected void contentRemoved() {
431 | 8 | List content = contentList();
432 |  |
433 | 8 | for (int i = 0, size = content.size(); i < size; i++) {
434 | 8 | Object object = content.get(i);
435 |  |
436 | 8 | if (object instanceof Node) {
437 | 8 | childRemoved((Node) object);
438 |  | }
439 |  | }
440 |  | }
441 |  |
442 |  | /**
443 |  | * Called when an invalid node has been added. Throws an {@link
444 |  | * IllegalAddException}.
445 |  | *
446 |  | * @param node
447 |  | * DOCUMENT ME!
448 |  | *
449 |  | * @throws IllegalAddException
450 |  | * DOCUMENT ME!
451 |  | */
452 | 0 | protected void invalidNodeTypeAddException(Node node) {
453 | 0 | throw new IllegalAddException("Invalid node type. Cannot add node: "
454 |  | + node + " to this branch: " + this);
455 |  | }
456 |  | }
457 |  |
458 |  | /*
459 |  | * Redistribution and use of this software and associated documentation
460 |  | * ("Software"), with or without modification, are permitted provided that the
461 |  | * following conditions are met:
462 |  | *
463 |  | * 1. Redistributions of source code must retain copyright statements and
464 |  | * notices. Redistributions must also contain a copy of this document.
465 |  | *
466 |  | * 2. Redistributions in binary form must reproduce the above copyright notice,
467 |  | * this list of conditions and the following disclaimer in the documentation
468 |  | * and/or other materials provided with the distribution.
469 |  | *
470 |  | * 3. The name "DOM4J" must not be used to endorse or promote products derived
471 |  | * from this Software without prior written permission of MetaStuff, Ltd. For
472 |  | * written permission, please contact dom4j-info@metastuff.com.
473 |  | *
474 |  | * 4. Products derived from this Software may not be called "DOM4J" nor may
475 |  | * "DOM4J" appear in their names without prior written permission of MetaStuff,
476 |  | * Ltd. DOM4J is a registered trademark of MetaStuff, Ltd.
477 |  | *
478 |  | * 5. Due credit should be given to the DOM4J Project - http://www.dom4j.org
479 |  | *
480 |  | * THIS SOFTWARE IS PROVIDED BY METASTUFF, LTD. AND CONTRIBUTORS ``AS IS'' AND
481 |  | * ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
482 |  | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
483 |  | * ARE DISCLAIMED. IN NO EVENT SHALL METASTUFF, LTD. OR ITS CONTRIBUTORS BE
484 |  | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
485 |  | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
486 |  | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
487 |  | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
488 |  | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
489 |  | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
490 |  | * POSSIBILITY OF SUCH DAMAGE.
491 |  | *
492 |  | * Copyright 2001-2005 (C) MetaStuff, Ltd. All Rights Reserved.
493 |  | */