001: /*
002: * (C) Copyright 2003 Nabh Information Systems, Inc.
003: *
004: * All copyright notices regarding Nabh's products MUST remain
005: * intact in the scripts and in the outputted HTML.
006: * This program is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public License
008: * as published by the Free Software Foundation; either version 2.1
009: * of the License, or (at your option) any later version.
010: *
011: * This program is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014: * GNU Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public License
017: * along with this program; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
019: *
020: */
021:
022: package com.nabhinc.util;
023:
024: import org.w3c.dom.Document;
025: import java.net.URL;
026: import java.io.*;
027: import org.xml.sax.InputSource;
028: import org.w3c.dom.CharacterData;
029: import org.w3c.dom.Node;
030: import org.w3c.dom.Element;
031: import org.w3c.dom.NodeList;
032: import java.util.*;
033:
034: import javax.xml.parsers.DocumentBuilder;
035: import javax.xml.parsers.DocumentBuilderFactory;
036: import javax.xml.parsers.FactoryConfigurationError;
037: import javax.xml.parsers.ParserConfigurationException;
038:
039: /**
040: * Miscelleneous XML utility methods that help extract text and elements from a
041: * DOM tree.
042: *
043: * @author Padmanabh Dabke (c) 2001,2003 Nabh Information Systems, Inc. All
044: * Rights Reserved.
045: */
046: public abstract class XMLUtil {
047:
048: /**
049: * Line feed string. Useful in writing multiline text files.
050: */
051: public static String LINE_FEED = (String) System
052: .getProperty("line.separator");
053:
054: /**
055: * Concat all the text and cdata node children of this elem and return the
056: * resulting text.
057: *
058: * @param parentEl
059: * the element whose cdata/text node values are to be combined.
060: * @return the concatanated string.
061: */
062: static public String getChildCharacterData(Element parentEl) {
063: if (parentEl == null) {
064: return null;
065: }
066: Node tempNode = parentEl.getFirstChild();
067: StringBuffer strBuf = new StringBuffer();
068: CharacterData charData;
069:
070: while (tempNode != null) {
071: switch (tempNode.getNodeType()) {
072: case Node.TEXT_NODE:
073: case Node.CDATA_SECTION_NODE:
074: charData = (CharacterData) tempNode;
075: strBuf.append(charData.getData());
076: break;
077: }
078: tempNode = tempNode.getNextSibling();
079: }
080: return strBuf.toString();
081: }
082:
083: /**
084: * Reads XML data from the given URL, parses it, and returns the document
085: * root element.
086: *
087: * @return Root element within the document
088: * @param urlStr
089: * URL string pointing to an XML document
090: */
091: public static Element getRootElementFromURL(String urlStr)
092: throws IOException, org.xml.sax.SAXException,
093: ParserConfigurationException, FactoryConfigurationError {
094: InputSource source = null;
095:
096: Element root = null;
097:
098: // try {
099: source = new InputSource(new URL(urlStr).openStream());
100: DocumentBuilder parser = DocumentBuilderFactory.newInstance()
101: .newDocumentBuilder();
102: Document d = parser.parse(source);
103: root = d.getDocumentElement();
104: return root;
105:
106: // } catch (Exception ex) {
107: // throw new ServletException("Invalid services configuration file: "
108: // + ex.getMessage());
109: // }
110: }
111:
112: /**
113: * Parses given XML string and returns the document root element.
114: *
115: * @return Root element within the document
116: * @param xmlSpec
117: * A string containing an XML doc
118: */
119: public static Element getRootElementFromString(String xmlSpec)
120: throws IOException, org.xml.sax.SAXException,
121: ParserConfigurationException, FactoryConfigurationError {
122: InputSource source = null;
123: Element root = null;
124:
125: source = new InputSource(new StringReader(xmlSpec));
126: DocumentBuilder parser = DocumentBuilderFactory.newInstance()
127: .newDocumentBuilder();
128: Document d = parser.parse(source);
129: root = d.getDocumentElement();
130: return root;
131:
132: }
133:
134: /**
135: * Returns first direct child element with the given tag.
136: *
137: * @return Firstirect child with the given tag or null
138: * @param el
139: * Parent element
140: * @param tag
141: * Subelement tag to look for
142: */
143: public static Element getSubElement(Element el, String tag) {
144: if (el == null)
145: return null;
146: NodeList nodes = el.getChildNodes();
147: int len = nodes.getLength();
148: for (int i = 0; i < len; i++) {
149: Node n = nodes.item(i);
150: if (n.getNodeName().equals(tag))
151: return (Element) n;
152: }
153:
154: return null;
155: }
156:
157: /**
158: * Returns first direct child that is an XML element.
159: *
160: * @return First child that is an XML element
161: * @param el
162: * Parent element
163: */
164: public static Element getFirstSubElement(Element el) {
165: if (el == null)
166: return null;
167: NodeList nodes = el.getChildNodes();
168: int len = nodes.getLength();
169: for (int i = 0; i < len; i++) {
170: Node n = nodes.item(i);
171: if (n instanceof Element)
172: return (Element) n;
173: }
174:
175: return null;
176: }
177:
178: /**
179: * Returns first direct child element with the given tag.
180: *
181: * @return Firstirect child with the given tag or null
182: * @param el
183: * Parent element
184: * @param tag
185: * Subelement tag to look for
186: */
187: public static Element getSubElementRecursive(Element el, String tag) {
188: if (el == null)
189: return null;
190: NodeList nodes = el.getChildNodes();
191: int len = nodes.getLength();
192: for (int i = 0; i < len; i++) {
193: Node n = nodes.item(i);
194: if (n.getNodeName().equals(tag))
195: return (Element) n;
196: }
197:
198: try {
199: Element parent = (Element) el.getParentNode();
200: if (parent != null)
201: return getSubElementRecursive(parent, tag);
202: else
203: return null;
204: } catch (ClassCastException ex1) {
205: // The reason for catching ClassCastException
206: // is that if the tag being searched is not
207: // present in the document, at some point the
208: // parent will not be an Element.
209: return null;
210: }
211: }
212:
213: /**
214: * Returns all direct child element with the given tag.
215: *
216: * @return Direct children with the given tag
217: * @param el
218: * Parent element
219: * @param tag
220: * Subelement tag to look for
221: */
222:
223: @SuppressWarnings("unchecked")
224: public static Element[] getSubElements(Element el, String tag) {
225: if (el == null)
226: return new Element[0];
227: NodeList nodes = el.getChildNodes();
228: Vector v = new Vector();
229: int len = nodes.getLength();
230: for (int i = 0; i < len; i++) {
231: Node n = nodes.item(i);
232: if (n.getNodeName().equals(tag))
233: v.addElement(n);
234: }
235: Element[] result = new Element[v.size()];
236: v.copyInto(result);
237: return result;
238: }
239:
240: /**
241: * Returns the text body of the first subelement with given tag. Returns
242: * null if it does not find a node with the given tag.
243: *
244: * @return Direct children with the given tag
245: * @param el
246: * Parent element
247: * @param tag
248: * Subelement tag to look for
249: */
250: public static String getSubElementText(Element el, String tag) {
251: if (el == null)
252: return null;
253: NodeList nodes = el.getChildNodes();
254: int len = nodes.getLength();
255: for (int i = 0; i < len; i++) {
256: Node n = nodes.item(i);
257: if (n.getNodeName().equals(tag)) {
258: try {
259: if (n.getFirstChild() == null) {
260: return null;
261: } else {
262: if (n.getFirstChild().getNodeValue() == null)
263: return null;
264: else
265: return n.getFirstChild().getNodeValue()
266: .trim();
267: }
268: } catch (NullPointerException npe) {
269: return null;
270: }
271: }
272: }
273:
274: return null;
275: }
276:
277: /**
278: * Returns the text body of the element. Returns
279: * null if there is no body.
280: *
281: * @return Direct children with the given tag
282: * @param el
283: * Parent element
284: * @param tag
285: * Subelement tag to look for
286: */
287: public static String getElementText(Element n) {
288: if (n == null)
289: return null;
290: try {
291: if (n.getFirstChild() == null) {
292: return null;
293: } else {
294: if (n.getFirstChild().getNodeValue() == null)
295: return null;
296: else
297: return n.getFirstChild().getNodeValue().trim();
298: }
299: } catch (NullPointerException npe) {
300: return null;
301: }
302:
303: }
304:
305: /**
306: * Returns the text body of the first subelement with given tag with any XML
307: * scope.
308: *
309: * @return Direct children with the given tag
310: * @param el
311: * Parent element
312: * @param tag
313: * Subelement tag to look for
314: */
315: public static String getSubElementTextGlobal(Element el, String tag) {
316: if (el == null)
317: return null;
318: NodeList nodes = el.getChildNodes();
319: int len = nodes.getLength();
320: for (int i = 0; i < len; i++) {
321: Node n = nodes.item(i);
322: if (n.getNodeName().equals(tag)
323: || n.getNodeName().endsWith(":" + tag)) {
324: try {
325: if (n.getFirstChild() == null) {
326: return null;
327: } else {
328: if (n.getFirstChild().getNodeValue() == null)
329: return null;
330: else
331: return n.getFirstChild().getNodeValue()
332: .trim();
333: }
334: } catch (NullPointerException npe) {
335: return null;
336: }
337: }
338: }
339:
340: return null;
341: }
342:
343: /**
344: * Returns the text body of the first subelement with given tag. Returns
345: * supplied default if it does not find a node with the given tag.
346: *
347: * @return Direct children with the given tag
348: * @param el
349: * Parent element
350: * @param tag
351: * Subelement tag to look for
352: * @param default
353: * Default string to return in case an element with the specified
354: * tag does not exist.
355: */
356: public static String getSubElementText(Element el, String tag,
357: String defaul) {
358: if (el == null)
359: return defaul;
360: String result = getSubElementText(el, tag);
361: if (result == null)
362: return defaul;
363: else
364: return result;
365: }
366:
367: /**
368: * Uses getSubElementText to get the value of a subnode, converts it to int
369: * and returns it.
370: *
371: * @return int value stored in the subelement text
372: * @param el
373: * Parent element
374: * @param tag
375: * Tag to look for
376: */
377: public static int getSubElementTextAsInt(Element el, String tag) {
378: String value = getSubElementText(el, tag);
379: if (value == null)
380: throw new NullPointerException("Null body for tag " + tag);
381: return Integer.parseInt(value.trim());
382: }
383:
384: /**
385: * Returns the text body of the first subelement with given tag. Returns
386: * null if it does not find a node with the given tag.
387: *
388: * @return Direct children with the given tag
389: * @param el
390: * Parent element
391: * @param tag
392: * Subelement tag to look for
393: */
394: public static String getSubElementTextRecursive(Element el,
395: String tag) {
396: NodeList nodes = el.getChildNodes();
397: int len = nodes.getLength();
398: for (int i = 0; i < len; i++) {
399: Node n = nodes.item(i);
400: if (n.getNodeName().equals(tag)) {
401: try {
402: return n.getFirstChild().getNodeValue().trim();
403: } catch (NullPointerException npe) {
404: break;
405: }
406: }
407: }
408:
409: try {
410: Element parent = (Element) el.getParentNode();
411: if (parent != null)
412: return getSubElementTextRecursive(parent, tag);
413: else
414: return null;
415: } catch (ClassCastException ex1) {
416: // The reason for catching ClassCastException
417: // is that if the tag being searched is not
418: // present in the document, at some point the
419: // parent will not be an Element.
420: return null;
421: }
422: }
423:
424: /**
425: * Returns the text body of the first subelement with given tag. Returns
426: * supplied default if it does not find a node with the given tag.
427: *
428: * @return Direct children with the given tag
429: * @param el
430: * Parent element
431: * @param tag
432: * Subelement tag to look for
433: * @param default
434: * Default string to return in case an element with the specified
435: * tag does not exist.
436: */
437: public static String getSubElementTextRecursive(Element el,
438: String tag, String defaul) {
439: String result = getSubElementTextRecursive(el, tag);
440: if (result == null)
441: return defaul;
442: else
443: return result;
444: }
445:
446: /**
447: * Writes an XML element with the given tag.
448: *
449: * @param elem
450: * Element value
451: * @param tag
452: * Element tag.
453: * @param w
454: * Writer
455: * @exception java.io.IOException
456: * I/O exception.
457: */
458: public static void writeElement(Object elem, String tag,
459: java.io.Writer w) throws java.io.IOException {
460: w.write("<" + tag + ">");
461: if (elem != null)
462: w.write(StringUtil.encodeXML(elem.toString()));
463: w.write("</" + tag + ">" + LINE_FEED);
464: }
465:
466: public static void writeElement(String indent, String tag,
467: String value, Writer w) throws IOException {
468: if (value == null)
469: return;
470:
471: w.write(indent);
472: w.write("<");
473: w.write(tag);
474: w.write(">");
475: w.write(StringUtil.encodeXML(value));
476: w.write("</");
477: w.write(tag);
478: w.write(">\n");
479:
480: }
481:
482: public static void writeEmptyElement(String indent, String tag,
483: Writer w) throws IOException {
484:
485: w.write(indent);
486: w.write("<");
487: w.write(tag);
488: w.write("/>\n");
489:
490: }
491:
492: public static void writeElementStart(String indent, String tag,
493: Writer w) throws IOException {
494: w.write(indent);
495: w.write("<");
496: w.write(tag);
497: w.write(">\n");
498: }
499:
500: public static void writeElementEnd(String indent, String tag,
501: Writer w) throws IOException {
502: w.write(indent);
503: w.write("</");
504: w.write(tag);
505: w.write(">\n");
506: }
507:
508: }
|