001: //
002: // Informa -- RSS Library for Java
003: // Copyright (c) 2002 by Niko Schmuck
004: //
005: // Niko Schmuck
006: // http://sourceforge.net/projects/informa
007: // mailto:niko_schmuck@users.sourceforge.net
008: //
009: // This library is free software.
010: //
011: // You may redistribute it and/or modify it under the terms of the GNU
012: // Lesser General Public License as published by the Free Software Foundation.
013: //
014: // Version 2.1 of the license should be included with this distribution in
015: // the file LICENSE. If the license is not included with this distribution,
016: // you may find a copy at the FSF web site at 'www.gnu.org' or 'www.fsf.org',
017: // or you may write to the Free Software Foundation, 675 Mass Ave, Cambridge,
018: // MA 02139 USA.
019: //
020: // This library is distributed in the hope that it will be useful,
021: // but WITHOUT ANY WARRANTY; without even the implied waranty of
022: // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
023: // Lesser General Public License for more details.
024: //
025:
026: // $Id: XmlPathUtils.java,v 1.4 2006/12/04 23:43:27 italobb Exp $
027:
028: package de.nava.informa.utils;
029:
030: import java.util.ArrayList;
031: import java.util.Iterator;
032: import java.util.List;
033: import java.util.StringTokenizer;
034:
035: import org.jdom.Element;
036: import org.jdom.Namespace;
037:
038: /**
039: * Utility class providing methods access XML attributes and elements using
040: * a path.
041: *
042: * @author Michael Harhen
043: */
044: public class XmlPathUtils {
045:
046: private XmlPathUtils() {
047: }
048:
049: private static final String elementDelim = "/";
050: private static final String prefixDelim = ":";
051:
052: /**
053: * Returns the value of an element's child element reached by the given path.
054: * Traverses the DOM tree from the parent until the child is reached.
055: *
056: * @param parent the parent <code>Element</code>
057: * @param childPath a path to the root of the elements.
058: * Paths are specified as element names, separated by a "/".
059: * Namespaces are allowed. e.g. "aaa:bbb/ccc:ddd/eee".
060: *
061: * @return the value of the child. <br>If <code>parent</code> is
062: * <code>null</code>, returns <code>null</code>. If
063: * <code>childPath</code> is null, returns the value of the parent.
064: */
065: public static String getElementValue(final Element parent,
066: final String childPath) {
067:
068: if (parent == null) {
069: return null;
070: } else {
071: Element child = getLeafChild(parent, childPath);
072: return (child == null) ? null : child.getTextTrim();
073: }
074: }
075:
076: /**
077: * Returns the values of the specified sub-elements of the child element
078: * reached by the given path. This is useful in cases where a child has
079: * several children. Traverses the DOM tree from the parent until the root
080: * is reached, then reads the specified elements.
081: *
082: * @param parent the parent <code>Element</code>
083: * @param childPath a path to the root of the elements.
084: * Paths are specified as element names, separated by a "/".
085: * Namespaces are allowed. e.g. "aaa:bbb/ccc:ddd/eee".
086: * @param elements An array of element names. May contain namespace specifiers.
087: *
088: * @return an array containing the value of each element.
089: * <br>If <code>parent</code> or <code>elements</code> is
090: * <code>null</code>, returns <code>null</code>. If
091: * <code>childPath</code> is null, returns the specified sub-elements
092: * of the parent.
093: */
094: public static String[] getElementValues(final Element parent,
095: final String childPath, final String[] elements) {
096:
097: if (parent == null) {
098: return null;
099: } else {
100: Element child = getLeafChild(parent, childPath);
101: return getElementValues(child, elements);
102: }
103: }
104:
105: /**
106: * Returns the values of the specified sub-elements of the child parent element.
107: * This is useful in cases where an element has several children.
108: *
109: * @param parent the parent <code>Element</code>
110: * @param children An array of child element names. May contain namespace specifiers.
111: *
112: * @return an array containing the value of each child element.
113: * <br>If <code>parent</code> or <code>children</code>
114: * is <code>null</code>, returns <code>null</code>.
115: */
116: public static String[] getElementValues(final Element parent,
117: final String[] children) {
118: if ((parent == null) || (children == null)) {
119: return null;
120: } else {
121: int numValues = children.length;
122: String[] elementValues = new String[numValues];
123: for (int i = 0; i < numValues; ++i) {
124: Element child = getChild(parent, children[i]);
125: elementValues[i] = (child == null) ? null : child
126: .getTextTrim();
127: }
128: return elementValues;
129: }
130: }
131:
132: /**
133: * Returns the value of the attribute of the child element reached by the
134: * given path. Traverses the DOM tree from the parent until the child is
135: * reached, then reads the given attribute.
136: *
137: * @param parent the parent <code>Element</code>
138: * @param childPath a path to the root of the elements.
139: * Paths are specified as element names, separated by a "/".
140: * @param attribute the attribute.
141: * May contain a namespace specifier e.g. "rdf:resource".
142: *
143: * @return the value of the attribute.
144: * <br>If <code>parent</code> or <code>attribute</code> is
145: * <code>null</code>, returns <code>null</code> .
146: * If <code>childPath</code> is null, returns the specified
147: * attribute of the parent.
148: *
149: */
150: public static String getAttributeValue(final Element parent,
151: final String childPath, final String attribute) {
152:
153: if ((parent == null) || (attribute == null)) {
154: return null;
155: } else {
156: Element child = getLeafChild(parent, childPath);
157: return getAttributeValue(child, attribute);
158: }
159: }
160:
161: /**
162: * Returns the value of the child element reached by the given path.
163: * This is useful in cases where a child has several attributes.
164: * Traverses the DOM tree from the parent until the child is reached.
165: *
166: * @param parent the parent <code>Element</code>
167: * @param childPath a path to the root of the elements. Paths are specified
168: * as element names, separated by a "/". Namespaces are allowed.
169: * e.g. "aaa:bbb/ccc:ddd/eee".
170: * @param attributes - An array of element names. May contain namespace
171: * specifiers.
172: *
173: * @return the value of the child. <br>If <code>parent</code> or
174: * <code>attributes</code> is <code>null</code>, returns
175: * <code>null</code>. If <code>childPath</code> is null, returns
176: * the specified attributes of the parent.
177: */
178: public static String[] getAttributeValues(final Element parent,
179: final String childPath, final String[] attributes) {
180:
181: if ((parent == null) || (attributes == null)) {
182: return null;
183: } else {
184: Element child = getLeafChild(parent, childPath);
185: return getAttributeValues(child, attributes);
186: }
187: }
188:
189: /**
190: * Returns the values of the attributes of given element.
191: * This is useful in cases where an element has several attributes.
192: *
193: * @param element the <code>Element</code>
194: * @param attributes An array of attribute names.
195: * May contain namespace specifiers.
196: *
197: * @return an array containing the values of the element's attributes.
198: * <br>If <code>element</code> or <code>attributes</code>
199: * is <code>null</code>, returns <code>null</code> .
200: */
201: public static String[] getAttributeValues(final Element element,
202: final String[] attributes) {
203:
204: if ((element == null) || (attributes == null)) {
205: return null;
206: } else {
207: int numAttributes = attributes.length;
208: String[] attributeValues = new String[numAttributes];
209: for (int i = 0; i < numAttributes; ++i) {
210: attributeValues[i] = getAttributeValue(element,
211: attributes[i]);
212: }
213: return attributeValues;
214: }
215: }
216:
217: /**
218: * Returns an <code>Element's</code> child corresponding to the given path.
219: * Traverses the DOM tree from the parent until the child is reached.
220: *
221: * @param parent the parent <code>Element</code>
222: * @param childPath a path to the root of the elements.
223: * Paths are specified as element names, separated by a "/".
224: * @return the child.
225: * <br>If <code>childPath</code> is null, return <code>parent</code>.
226: */
227: private static Element getLeafChild(final Element parent,
228: final String childPath) {
229:
230: if (childPath == null)
231: return parent;
232:
233: List elementNames = getElementNames(childPath);
234: Iterator iterator = elementNames.iterator();
235: Element nextChild = parent;
236:
237: while (iterator.hasNext() && (nextChild != null)) {
238: String elementName = (String) iterator.next();
239: nextChild = getChild(nextChild, elementName);
240: }
241:
242: return nextChild;
243: }
244:
245: /**
246: * Returns an <code>Element's</code> child corresponding to the given child
247: * name.
248: *
249: * @param parent the parent <code>Element</code>
250: * @param childName the child's name.
251: * May contain a namespace specifier.
252: *
253: * @return the child.
254: */
255: private static Element getChild(final Element parent,
256: final String childName) {
257:
258: int prefixPos = childName.indexOf(prefixDelim);
259: if ((prefixPos == 0) || (prefixPos >= childName.length() - 1)) {
260: return null;
261: } else {
262: if (prefixPos == -1) {
263: return parent.getChild(childName, getNamespace(parent,
264: null));
265: } else {
266: String prefix = childName.substring(0, prefixPos);
267: String childElementName = childName
268: .substring(prefixPos + 1);
269: return parent.getChild(childElementName, getNamespace(
270: parent, prefix));
271: }
272: }
273: }
274:
275: /**
276: * Get the value corresponding to an <code>Element</code> and an attribute.
277: *
278: * @param element the <code>Element</code>.
279: * <code>null</code> is not acceptable.
280: * @param attribute the attribute.
281: * May contain a namespace specifier e.g. "rdf:resource".
282: * <code>null</code> is not acceptable.
283: * @return the value. The value of the <code>Element's</code> attribute,
284: * or <code>null</code> if element is <code>null</code>.
285: */
286: private static String getAttributeValue(Element element,
287: String attribute) {
288:
289: if (element == null)
290: return null;
291: int prefixPos = attribute.indexOf(prefixDelim);
292:
293: if ((prefixPos == 0) || (prefixPos >= attribute.length() - 1)) {
294: return null;
295: } else if (prefixPos == -1) { // no prefix
296: return element.getAttributeValue(attribute);
297: } else {
298: String prefix = attribute.substring(0, prefixPos);
299: String attributeName = attribute.substring(prefixPos + 1);
300: return element.getAttributeValue(attributeName,
301: getNamespace(element, prefix));
302: }
303: }
304:
305: /**
306: * Converts a path into a <code>List</code> of element names.
307: *
308: * @param childPath a path. e.g. "aaa:bbb/ccc:ddd/eee"
309: *
310: * @return a <code>List</code> of element names.
311: * e.g. "aaa:bbb", "ccc:ddd", "eee".
312: */
313: private static List getElementNames(final String childPath) {
314:
315: List<String> strArray = new ArrayList<String>();
316: if (childPath != null) {
317: StringTokenizer st = new StringTokenizer(childPath,
318: elementDelim);
319: while (st.hasMoreTokens()) {
320: String token = st.nextToken();
321: if (token.length() > 0) {
322: strArray.add(token);
323: }
324: }
325: }
326: return strArray;
327: }
328:
329: /**
330: * Returns the Namespace corresponding to an element and a prefix.
331: *
332: * @param element the element.
333: * @param prefix the prefix.
334: *
335: * @return the Namespace.
336: */
337: private static Namespace getNamespace(final Element element,
338: final String prefix) {
339: Namespace namespace = (prefix == null) ? element
340: .getNamespace("") : element.getNamespace(prefix);
341: return (namespace == null) ? Namespace.NO_NAMESPACE : namespace;
342: }
343:
344: }
|