View Javadoc

1   /*
2    * Copyright 2001-2004 (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    * $Id: IndexedElement.java,v 1.8 2004/06/25 08:03:41 maartenc Exp $
8    */
9   
10  package org.dom4j.util;
11  
12  import java.util.ArrayList;
13  import java.util.HashMap;
14  import java.util.Iterator;
15  import java.util.List;
16  import java.util.Map;
17  
18  import org.dom4j.Attribute;
19  import org.dom4j.Element;
20  import org.dom4j.Node;
21  import org.dom4j.QName;
22  import org.dom4j.tree.BackedList;
23  import org.dom4j.tree.DefaultElement;
24  
25  /*** <p><code>IndexedElement</code> is an implementation of {@link Element}
26    * which maintains an index of the attributes and elements it contains to
27    * optimise lookups via name.</p>
28    *
29    * @author <a href="mailto:james.strachan@metastuff.com">James Strachan</a>
30    * @version $Revision: 1.8 $
31    */
32  public class IndexedElement extends DefaultElement {
33  
34      /*** Lazily constructed index for elements */
35      private Map elementIndex;
36  
37      /*** Lazily constructed index for attributes */
38      private Map attributeIndex;
39  
40      
41      public IndexedElement(String name) { 
42          super(name);
43      }
44  
45      public IndexedElement(QName qname) { 
46          super(qname);
47      }
48  
49      public IndexedElement(QName qname, int attributeCount) { 
50          super(qname, attributeCount);
51      }
52      
53      public Attribute attribute(String name) {
54          return (Attribute) attributeIndex().get(name);
55      }
56  
57      public Attribute attribute(QName qName) {
58          return (Attribute) attributeIndex().get(qName);
59      }
60  
61      public Element element(String name) {
62          return asElement( elementIndex().get(name) );
63      }
64      
65      public Element element(QName qName) {
66          return asElement( elementIndex().get(qName) );
67      }
68          
69      public List elements(String name) {
70          return asElementList( elementIndex().get(name) );
71      }
72      
73      public List elements(QName qName) {
74          return asElementList( elementIndex().get(qName) );
75      }
76          
77      
78      // Implementation methods
79      //-------------------------------------------------------------------------    
80      
81      protected Element asElement(Object object) {
82          if ( object instanceof Element ) {
83              return (Element) object;
84          }
85          else if ( object != null ) {
86              List list = (List) object;
87              if ( list.size() >= 1 ) {
88                  return (Element) list.get(0);
89              }
90          }
91          return null;
92      }
93      
94      protected List asElementList(Object object) {
95          if ( object instanceof Element ) {
96              return createSingleResultList( object );
97          }
98          else if ( object != null ) {
99              List list = (List) object;
100             BackedList answer = createResultList();
101             for ( int i = 0, size = list.size(); i < size; i++ ) {
102                 answer.addLocal( list.get(i) );
103             }
104             return answer;
105         }
106         return createEmptyList();
107     }
108     
109     /***
110      * @deprecated  WILL BE REMOVED IN dom4j-1.6 !!
111      */
112     protected Iterator asElementIterator(Object object) {
113         return asElementList(object).iterator();
114     }
115     
116     
117     // #### could we override the add(Element) remove(Element methods?
118     
119     protected void addNode(Node node) {
120         super.addNode(node);
121         if ( elementIndex != null && node instanceof Element ) {
122             addToElementIndex( (Element) node );
123         }
124         else if ( attributeIndex != null && node instanceof Attribute ) {
125             addToAttributeIndex( (Attribute) node );
126         }
127     }
128     
129     protected boolean removeNode(Node node) {
130         if ( super.removeNode(node) ) {
131             if ( elementIndex != null && node instanceof Element ) {
132                 removeFromElementIndex( (Element) node );
133             }
134             else if ( attributeIndex != null && node instanceof Attribute ) {
135                 removeFromAttributeIndex( (Attribute) node );
136             }
137             return true;
138         }
139         return false;
140     }
141 
142     protected Map attributeIndex() {
143         if ( attributeIndex == null ) {
144             attributeIndex = createAttributeIndex();
145             for (Iterator iter = attributeIterator(); iter.hasNext(); ) {
146                 addToAttributeIndex( (Attribute) iter.next() );
147             }
148         }
149         return attributeIndex;
150     }
151     
152     protected Map elementIndex() {
153         if ( elementIndex == null ) {
154             elementIndex = createElementIndex();
155             for (Iterator iter = elementIterator(); iter.hasNext(); ) {
156                 addToElementIndex( (Element) iter.next() );
157             }
158         }
159         return elementIndex;
160     }
161     
162     /*** A Factory Method to create the index for attributes
163       */
164     protected Map createAttributeIndex() {
165         Map answer = createIndex();
166         return answer;
167     }
168     
169     /*** A Factory Method to create the index for elements
170       */
171     protected Map createElementIndex() {
172         Map answer = createIndex();
173         return answer;
174     }
175 
176     protected void addToElementIndex(Element element) {
177         QName qName = element.getQName();
178         String name = qName.getName();
179         addToElementIndex(qName, element);
180         addToElementIndex(name, element);
181     }
182     
183     protected void addToElementIndex(Object key, Element value) {
184         Object oldValue = elementIndex.get(key);
185         if (oldValue == null) {
186             elementIndex.put(key, value);
187         }
188         else {
189             if ( oldValue instanceof List ) {
190                 List list = (List) oldValue;
191                 list.add(value);
192             }
193             else {
194                 List list = createList();
195                 list.add(oldValue);
196                 list.add(value);
197                 elementIndex.put(key, list);
198             }
199         }
200     }
201     
202     protected void removeFromElementIndex(Element element) {
203         QName qName = element.getQName();
204         String name = qName.getName();
205         removeFromElementIndex(qName, element);
206         removeFromElementIndex(name, element);
207     }
208     
209     protected void removeFromElementIndex(Object key, Element value) {
210         Object oldValue = elementIndex.get(key);
211         if ( oldValue instanceof List ) {
212             List list = (List) oldValue;
213             list.remove(value);
214         }
215         else {
216             elementIndex.remove(key);
217         }
218     }
219 
220     
221     protected void addToAttributeIndex(Attribute attribute) {
222         QName qName = attribute.getQName();
223         String name = qName.getName();
224         addToAttributeIndex(qName, attribute);
225         addToAttributeIndex(name, attribute);
226     }
227     
228     protected void addToAttributeIndex(Object key, Attribute value) {
229         Object oldValue = attributeIndex.get(key);
230         if (oldValue != null) {
231             attributeIndex.put(key, value);
232         }
233     }
234     
235     protected void removeFromAttributeIndex(Attribute attribute) {
236         QName qName = attribute.getQName();
237         String name = qName.getName();
238         removeFromAttributeIndex(qName, attribute);
239         removeFromAttributeIndex(name, attribute);
240     }
241     
242     protected void removeFromAttributeIndex(Object key, Attribute value) {
243         Object oldValue = attributeIndex.get(key);
244         if ( oldValue != null && oldValue.equals( value ) ) {
245             attributeIndex.remove(key);
246         }
247     }
248 
249     /*** Factory method to return a new map implementation for indices
250       */
251     protected Map createIndex() {
252         return new HashMap();
253     }
254     
255     /*** Factory method to return a list implementation for indices
256       */
257     protected List createList() {
258         return new ArrayList();
259     }
260 }
261 
262 
263 
264 
265 /*
266  * Redistribution and use of this software and associated documentation
267  * ("Software"), with or without modification, are permitted provided
268  * that the following conditions are met:
269  *
270  * 1. Redistributions of source code must retain copyright
271  *    statements and notices.  Redistributions must also contain a
272  *    copy of this document.
273  *
274  * 2. Redistributions in binary form must reproduce the
275  *    above copyright notice, this list of conditions and the
276  *    following disclaimer in the documentation and/or other
277  *    materials provided with the distribution.
278  *
279  * 3. The name "DOM4J" must not be used to endorse or promote
280  *    products derived from this Software without prior written
281  *    permission of MetaStuff, Ltd.  For written permission,
282  *    please contact dom4j-info@metastuff.com.
283  *
284  * 4. Products derived from this Software may not be called "DOM4J"
285  *    nor may "DOM4J" appear in their names without prior written
286  *    permission of MetaStuff, Ltd. DOM4J is a registered
287  *    trademark of MetaStuff, Ltd.
288  *
289  * 5. Due credit should be given to the DOM4J Project - 
290  *    http://www.dom4j.org
291  *
292  * THIS SOFTWARE IS PROVIDED BY METASTUFF, LTD. AND CONTRIBUTORS
293  * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
294  * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
295  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
296  * METASTUFF, LTD. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
297  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
298  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
299  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
300  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
301  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
302  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
303  * OF THE POSSIBILITY OF SUCH DAMAGE.
304  *
305  * Copyright 2001-2004 (C) MetaStuff, Ltd. All Rights Reserved.
306  *
307  * $Id: IndexedElement.java,v 1.8 2004/06/25 08:03:41 maartenc Exp $
308  */