KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jivesoftware > util > ElementUtil


1 package org.jivesoftware.util;
2
3 import java.util.ArrayList JavaDoc;
4 import java.util.Arrays JavaDoc;
5 import java.util.Iterator JavaDoc;
6 import java.util.List JavaDoc;
7 import java.util.StringTokenizer JavaDoc;
8 import org.dom4j.Element;
9 import org.dom4j.Node;
10
11 /**
12  * <p>We use a simple
13  * naming convention of meta-data key names: data is stored
14  * heirarchically separated by dots. The last name may contain
15  * a colon ':' character that is read as name:attribute.
16  * For example setting X.Y.Z to someValue, would map to an XML snippet of:</p>
17  * <pre>
18  * &lt;X&gt;
19  * &lt;Y&gt;
20  * &lt;Z&gt;someValue&lt;/Z&gt;
21  * &lt;/Y&gt;
22  * &lt;/X&gt;
23  * </pre>
24  * And X.Y.Z:key to anotherValue as:</p>
25  * <pre>
26  * &lt;X&gt;
27  * &lt;Y&gt;
28  * &lt;Z key="anotherValue" /&gt;
29  * &lt;/Y&gt;
30  * &lt;/X&gt;
31  * </pre>
32  * <p>Some XML cannot be built or accessed using this naming
33  * convention (e.g. a typical Roster reset packet). More complex XML
34  * packet should be represented using the XMPPDOMFragment. The
35  * Element class is designed to provide 80% of XML
36  * manipulation capabilities with the simplest 20% of code and API size
37  * making it convenient for meta-data, simple IQ packets, etc.</p>
38  */

39 public class ElementUtil {
40
41
42     private ElementUtil() {
43     }
44
45
46     /**
47      * Returns the value of the specified property. A <tt>null</tt> answer does not necessarily mean
48      * that the property does not exist.
49      *
50      * @param name the name of the property to get.
51      * @return the value of the specified property.
52      */

53     public static String JavaDoc getProperty(Element element, String JavaDoc name) {
54         String JavaDoc value = null;
55         String JavaDoc[] propName = parsePropertyName(name);
56
57         // Grab the attribute if there is one
58
String JavaDoc lastName = propName[propName.length - 1];
59         String JavaDoc attName = null;
60         int attributeIndex = lastName.indexOf(':');
61         if (attributeIndex >= 0) {
62             propName[propName.length - 1] = lastName.substring(0, attributeIndex);
63             attName = lastName.substring(attributeIndex + 1);
64         }
65
66         // Search for this property by traversing down the XML hierarchy.
67
int i = propName[0].equals(element.getName()) ? 1 : 0;
68         for (; i < propName.length; i++) {
69             element = element.element(propName[i]);
70             if (element == null) {
71                 break;
72             }
73         }
74         if (element != null) {
75             if (attName == null) {
76                 value = element.getTextTrim();
77             }
78             else {
79                 value = element.attributeValue(attName);
80             }
81         }
82
83         return value;
84     }
85
86     /**
87      * Returns true if the specified property is included in the XML hierarchy. A property could
88      * have a value associated or not. If the property has an associated value then
89      *
90      * @param name the name of the property to find out.
91      * @return true if the specified property is included in the XML hierarchy.
92      */

93     public static boolean includesProperty(Element element, String JavaDoc name) {
94         String JavaDoc value = null;
95
96         if (value == null) {
97             String JavaDoc[] propName = parsePropertyName(name);
98
99             // Grab the attribute if there is one
100
String JavaDoc lastName = propName[propName.length - 1];
101             String JavaDoc attName = null;
102             int attributeIndex = lastName.indexOf(':');
103             if (attributeIndex >= 0) {
104                 propName[propName.length - 1] = lastName.substring(0, attributeIndex);
105                 attName = lastName.substring(attributeIndex + 1);
106             }
107
108             // Search for this property by traversing down the XML hierarchy.
109
int i = propName[0].equals(element.getName()) ? 1 : 0;
110             for (; i < propName.length; i++) {
111                 element = element.element(propName[i]);
112                 if (element == null) {
113                     break;
114                 }
115             }
116
117             if (element != null) {
118                 if (attName == null){
119                     // The property exists so return true
120
return true;
121                 } else {
122                     // The property exists if the attribute exists in the element
123
return element.attribute(attName) != null;
124                 }
125             }
126             else {
127                 // The property does not exist so return false
128
return false;
129             }
130         }
131         return true;
132     }
133
134     /**
135      * Return all values who's path matches the given property name as a String array,
136      * or an empty array if the if there are no children. You MAY NOT use the atttribute
137      * markup (using a ':' in the last element name) with this call.
138      * <p/>
139      * getProperties() allows you to retrieve several values with the same property name.
140      * For example, consider the XML file entry:
141      * <pre>
142      * &lt;foo&gt;
143      * &lt;bar&gt;
144      * &lt;prop&gt;some value&lt;/prop&gt;
145      * &lt;prop&gt;other value&lt;/prop&gt;
146      * &lt;prop&gt;last value&lt;/prop&gt;
147      * &lt;/bar&gt;
148      * &lt;/foo&gt;
149      * </pre>
150      * If you call getProperties("foo.bar.prop") will return a string array containing
151      * {"some value", "other value", "last value"}.
152      *
153      * @param name the name of the property to retrieve
154      * @return all child property values for the given node name.
155      */

156     public String JavaDoc[] getProperties(Element element, String JavaDoc name) {
157         String JavaDoc[] propName = parsePropertyName(name);
158
159         // Search for this property by traversing down the XML heirarchy, stopping one short.
160
int i = propName[0].equals(element.getName()) ? 1 : 0;
161         for (; i < propName.length - 1; i++) {
162             element = element.element(propName[i]);
163             if (element == null) {
164                 // This node doesn't match this part of the property name which
165
// indicates this property doesn't exist so return empty array.
166
return new String JavaDoc[]{};
167             }
168         }
169         // We found matching property, return names of children.
170
Iterator JavaDoc iter = element.elementIterator(propName[propName.length - 1]);
171         ArrayList JavaDoc props = new ArrayList JavaDoc();
172         while (iter.hasNext()) {
173             Element e = (Element) iter.next();
174             props.add(e.getName());
175         }
176         String JavaDoc[] childrenNames = new String JavaDoc[props.size()];
177         return (String JavaDoc[]) props.toArray(childrenNames);
178     }
179
180     /**
181      * Sets a property to an array of values. You MAY NOT use the atttribute
182      * markup (using a ':' in the last element name) with this call. Multiple values matching the
183      * same property is mapped to an XML file as multiple elements containing each value.
184      * For example, using the name "foo.bar.prop", and the value string array containing
185      * {"some value", "other value", "last value"} would produce the following XML:
186      * <pre>
187      * &lt;foo&gt;
188      * &lt;bar&gt;
189      * &lt;prop&gt;some value&lt;/prop&gt;
190      * &lt;prop&gt;other value&lt;/prop&gt;
191      * &lt;prop&gt;last value&lt;/prop&gt;
192      * &lt;/bar&gt;
193      * &lt;/foo&gt;
194      * </pre>
195      *
196      * @param name the name of the property.
197      * @param values The array of values for the property (can be empty but not null)
198      */

199     public static void setProperties(Element element, String JavaDoc name, String JavaDoc[] values) {
200         String JavaDoc[] propName = parsePropertyName(name);
201         setProperty(element, name, values[0]);
202
203         // Search for this property by traversing down the XML heirarchy, stopping one short.
204
int i = propName[0].equals(element.getName()) ? 1 : 0;
205         for (; i < propName.length - 1; i++) {
206             element = element.element(propName[i]);
207             if (element == null) {
208                 // This node doesn't match this part of the property name which
209
// indicates this property doesn't exist so return empty array.
210
return;
211             }
212         }
213         String JavaDoc childName = propName[propName.length - 1];
214         // We found matching property, clear all children.
215
Iterator JavaDoc iter = element.elementIterator(childName);
216         while (iter.hasNext()) {
217             ((Node) iter.next()).detach();
218         }
219         for (int j = 0; i < values.length; i++) {
220             if (values[j] != null) {
221                 element.addElement(childName).setText(values[j]);
222             }
223         }
224     }
225
226     /**
227      * Return all children property names of a parent property as a String array,
228      * or an empty array if the if there are no children. You MAY NOT use the atttribute
229      * markup (using a ':' in the last element name) with this call.
230      * For example, given the properties <tt>X.Y.A</tt>, <tt>X.Y.B</tt>, and <tt>X.Y.C</tt>, then
231      * the child properties of <tt>X.Y</tt> are <tt>A</tt>, <tt>B</tt>, and
232      * <tt>C</tt>.
233      *
234      * @param parent the name of the parent property.
235      * @return all child property values for the given parent.
236      */

237     public static String JavaDoc[] getChildrenProperties(Element element, String JavaDoc parent) {
238         String JavaDoc[] propName = parsePropertyName(parent);
239
240         // Search for this property by traversing down the XML heirarchy.
241
int i = propName[0].equals(element.getName()) ? 1 : 0;
242         for (; i < propName.length; i++) {
243             element = element.element(propName[i]);
244             if (element == null) {
245                 // This node doesn't match this part of the property name which
246
// indicates this property doesn't exist so return empty array.
247
return new String JavaDoc[]{};
248             }
249         }
250         // We found matching property, return names of children.
251
List JavaDoc children = element.elements();
252         int childCount = children.size();
253         String JavaDoc[] childrenNames = new String JavaDoc[childCount];
254         for (int j = 0; i < childCount; i++) {
255             childrenNames[j] = ((Element) children.get(j)).getName();
256         }
257         return childrenNames;
258     }
259
260     /**
261      * Returns all recursive children of the given parent property or an empty string array
262      * if no children exist. The list of children is depth-first so the array is optimized
263      * for easy displaying.
264      *
265      * @param parent the parent property.
266      * @return all recursive children of the given property in depth-first order or an empty
267      * string array if no children exist.
268      */

269     public static String JavaDoc[] getRecursiveChildrenProperties(Element element, String JavaDoc parent) {
270         String JavaDoc[] properties = getChildrenProperties(element, parent);
271         if (properties.length == 0) {
272             return properties;
273         }
274         else {
275             List JavaDoc list = new ArrayList JavaDoc(15);
276             for (int i = 0; i < properties.length; i++) {
277                 String JavaDoc propName = parent + "." + properties[i];
278                 list.add(propName);
279                 list.addAll(Arrays.asList(getRecursiveChildrenProperties(element, propName)));
280             }
281             return (String JavaDoc[]) list.toArray(new String JavaDoc[]{});
282         }
283     }
284
285     /**
286      * Sets the value of the specified property. If the property doesn't
287      * currently exist, it will be automatically created.
288      *
289      * @param name the name of the property to set.
290      * @param value the new value for the property.
291      */

292     public static void setProperty(Element element, String JavaDoc name, String JavaDoc value) {
293         if (name == null || name.length() == 0) return;
294         if (value == null) value = "";
295
296         String JavaDoc[] propName = parsePropertyName(name);
297
298         // Search for this property by traversing down the XML heirarchy.
299
int i = propName[0].equals(element.getName()) ? 1 : 0;
300         for (; i < propName.length - 1; i++) {
301             // If we don't find this part of the property in the XML heirarchy
302
// we add it as a new node
303
if (element.element(propName[i]) == null) {
304                 element.addElement(propName[i]);
305             }
306             element = element.element(propName[i]);
307         }
308         String JavaDoc lastName = propName[propName.length - 1];
309         int attributeIndex = lastName.indexOf(':');
310         if (attributeIndex >= 0) {
311             String JavaDoc eleName = lastName.substring(0, attributeIndex);
312             String JavaDoc attName = lastName.substring(attributeIndex + 1);
313             // If we don't find this part of the property in the XML heirarchy
314
// we add it as a new node
315
if (element.element(eleName) == null) {
316                 element.addElement(eleName);
317             }
318             element.element(eleName).addAttribute(attName, value);
319         }
320         else {
321             // If we don't find this part of the property in the XML heirarchy
322
// we add it as a new node
323
if (element.element(lastName) == null) {
324                 element.addElement(lastName);
325             }
326             // Set the value of the property in this node.
327
element.element(lastName).setText(value);
328         }
329     }
330
331     /**
332      * <p>Deletes the specified property.</p>
333      * <p>You MAY NOT use the atttribute
334      * markup (using a ':' in the last element name) with this call.
335      * deleteProperty() removes both the containing text, and the element itself along with
336      * any attributes associated with that element.</p>
337      *
338      * @param name the property to delete.
339      */

340     public static void deleteProperty(Element element, String JavaDoc name) {
341         // Remove property from cache.
342
String JavaDoc[] propName = parsePropertyName(name);
343
344         // Search for this property by traversing down the XML heirarchy.
345
for (int i = 0; i < propName.length - 1; i++) {
346             element = element.element(propName[i]);
347             // Can't find the property so return.
348
if (element == null) {
349                 return;
350             }
351         }
352         // Found the correct element to remove, so remove it...
353
element.remove(element.element(propName[propName.length - 1]));
354     }
355
356     /**
357      * Returns an array representation of the given Jive property. Jive
358      * properties are always in the format "prop.name.is.this" which would be
359      * represented as an array of four Strings.
360      *
361      * @param name the name of the Jive property.
362      * @return an array representation of the given Jive property.
363      */

364     private static String JavaDoc[] parsePropertyName(String JavaDoc name) {
365         List JavaDoc propName = new ArrayList JavaDoc(5);
366         // Use a StringTokenizer to tokenize the property name.
367
StringTokenizer JavaDoc tokenizer = new StringTokenizer JavaDoc(name, ".");
368         while (tokenizer.hasMoreTokens()) {
369             propName.add(tokenizer.nextToken());
370         }
371         return (String JavaDoc[]) propName.toArray(new String JavaDoc[propName.size()]);
372     }
373
374
375 }
376
Popular Tags