001: /*
002: * The contents of this file are subject to the terms
003: * of the Common Development and Distribution License
004: * (the "License"). You may not use this file except
005: * in compliance with the License.
006: *
007: * You can obtain a copy of the license at
008: * https://open-esb.dev.java.net/public/CDDLv1.0.html.
009: * See the License for the specific language governing
010: * permissions and limitations under the License.
011: *
012: * When distributing Covered Code, include this CDDL
013: * HEADER in each file and include the License file at
014: * https://open-esb.dev.java.net/public/CDDLv1.0.html.
015: * If applicable add the following below this CDDL HEADER,
016: * with the fields enclosed by brackets "[]" replaced with
017: * your own identifying information: Portions Copyright
018: * [year] [name of copyright owner]
019: */
020:
021: /*
022: * @(#)XmlUtil.java - ver 1.1 - 01/04/2006
023: *
024: * Copyright 2004-2006 Sun Microsystems, Inc. All Rights Reserved.
025: */
026:
027: package com.sun.jbi.framework;
028:
029: import java.net.URLDecoder;
030:
031: import java.util.ArrayList;
032: import java.util.List;
033:
034: import org.w3c.dom.DocumentFragment;
035: import org.w3c.dom.Element;
036: import org.w3c.dom.Node;
037: import org.w3c.dom.NodeList;
038: import org.w3c.dom.Text;
039:
040: /**
041: * This class provides utility methods for accessing data from XML documents.
042: *
043: * @author Sun Microsystems, Inc.
044: */
045: public class XmlUtil {
046: /**
047: * The StringTranslator to be used for constructing messages.
048: */
049: private static StringTranslator sTranslator;
050:
051: /**
052: * Constant for character set for URLDecoder.
053: */
054: private static final String VALUE_UTF8 = "UTF-8";
055:
056: /**
057: * Static initializer.
058: */
059: static {
060: EnvironmentContext ec = EnvironmentContext.getInstance();
061: sTranslator = (StringTranslator) ec.getStringTranslatorFor(ec);
062: }
063:
064: /**
065: * Get the named element from the specified node. If isRequired is true,
066: * there must be exactly one element of the specified type; if no element
067: * is found, an exception is thrown. If isRequired is false, and there
068: * is no element of the specified type, null is returned. In either case,
069: * if multiple elements are found, an exception is thrown.
070: * @param node - the node to be processed.
071: * @param tag - the type of the element to be returned.
072: * @param isRequired - true if the element is required, false if not.
073: * @return A Node representing the requested element, or null if no element
074: * was found and isRequired is false.
075: * @throws com.sun.jbi.framework.XmlParseException if a required element is
076: * not found or if a parse error occurs.
077: */
078: static Node getElement(Node node, String tag, boolean isRequired)
079: throws com.sun.jbi.framework.XmlParseException {
080: Node retNode = null;
081: NodeList nodeList = getElements(node, tag, isRequired);
082: int n = nodeList.getLength();
083: if (n > 1) {
084: throw new com.sun.jbi.framework.XmlParseException(
085: sTranslator.getString(
086: LocalStringKeys.XML_EXTRA_ELEMENTS,
087: new Integer(n), tag));
088: }
089: if (n > 0) {
090: retNode = nodeList.item(0);
091: }
092: return retNode;
093: }
094:
095: /**
096: * Get the named elements from the specified node. If isRequired is true,
097: * there must be at least one element of the specified type; if no element
098: * is found, an exception is thrown. If isRequired is false, and there
099: * are no elements of the specified type, an empty NodeList is returned.
100: *
101: * @param node - the node to be processed.
102: * @param tag - the type of the elements to be returned.
103: * @param isRequired - true if the element is required, false if not.
104: * @return A NodeList representing the requested elements, or null if the
105: * input node is null.
106: * @throws com.sun.jbi.framework.XmlParseException if a required element is
107: * not found or if a parse error occurs.
108: */
109: static NodeList getElements(Node node, String tag,
110: boolean isRequired)
111: throws com.sun.jbi.framework.XmlParseException {
112: NodeList nodeList = null;
113: if (null != node) {
114: try {
115: node = node.cloneNode(true); // Make this non-destructive
116: nodeList = node.getChildNodes();
117: for (int n = 0; n < nodeList.getLength(); n++) {
118: if (!nodeList.item(n).getNodeName().equals(tag)) {
119: node.removeChild(nodeList.item(n));
120: n--; // to account for the removal of the node
121: }
122: }
123: nodeList = node.getChildNodes();
124: if (isRequired && 0 == nodeList.getLength()) {
125: throw new com.sun.jbi.framework.XmlParseException(
126: sTranslator
127: .getString(
128: LocalStringKeys.XML_MISSING_ELEMENT,
129: tag, node.getNodeName()));
130: }
131: } catch (org.w3c.dom.DOMException domEx) {
132: throw new com.sun.jbi.framework.XmlParseException(
133: sTranslator.getString(
134: LocalStringKeys.XML_DOM_EXCEPTION,
135: domEx.getMessage()));
136: }
137: }
138: return nodeList;
139: }
140:
141: /**
142: * Get a single attribute value from a node. If the attribute is not present
143: * an empty string value is returned.
144: *
145: * @param node the Node to be processed.
146: * @param attrName the name of the attribute to be retrieved.
147: * @return A String representing the value of the attribute. If the
148: * attribute is not present, its value is set to an empty string.
149: */
150: static String getAttribute(Node node, String attrName) {
151: if (null == node) {
152: throw new java.lang.IllegalArgumentException(sTranslator
153: .getString(LocalStringKeys.NULL_ARGUMENT, "node"));
154: }
155: if (null == attrName) {
156: throw new java.lang.IllegalArgumentException(sTranslator
157: .getString(LocalStringKeys.NULL_ARGUMENT,
158: "attrName"));
159: }
160:
161: String value;
162: Element elem = (Element) node;
163: try {
164: value = URLDecoder.decode(elem.getAttribute(attrName),
165: VALUE_UTF8).trim();
166: } catch (java.io.UnsupportedEncodingException ueEx) {
167: value = elem.getAttribute(attrName);
168: }
169: return value;
170: }
171:
172: /**
173: * Get a boolean value from a named element in the specified node.
174: * @param node - the node to be processed.
175: * @param tag - the element to be processed.
176: * @param isRequired - true if the element is required, false if not.
177: * @return A boolean set based on the text value from the specified element:
178: * "true" returns true; "false" returns false. If the element is not present
179: * and isRequired is false, returns a null.
180: * @throws com.sun.jbi.framework.XmlParseException if the node list is
181: * null or if any node is missing its text node.
182: */
183: static Boolean getBooleanValue(Node node, String tag,
184: boolean isRequired)
185: throws com.sun.jbi.framework.XmlParseException {
186: Boolean value = null;
187: NodeList nl = getElements(node, tag, isRequired);
188: if (0 != nl.getLength()) {
189: String s = getStringValue(nl);
190: if (null != s) {
191: value = Boolean.valueOf(s);
192: }
193: }
194: return value;
195: }
196:
197: /**
198: * Get a String value from the specified node. The node can have child nodes
199: * but must have one and only one child node that is a text node containing
200: * the value.
201: * @param node the node to be processed.
202: * @return A String containing the text value from the specified node.
203: * @throws com.sun.jbi.framework.XmlParseException if the node is missing
204: * its text node.
205: */
206: static String getStringValue(Node node)
207: throws com.sun.jbi.framework.XmlParseException {
208: // Check for null argument
209: if (null == node) {
210: throw new java.lang.IllegalArgumentException(sTranslator
211: .getString(LocalStringKeys.NULL_ARGUMENT, "node"));
212: }
213:
214: // Check for empty node
215: NodeList nodes = node.getChildNodes();
216: int nodeCount = nodes.getLength();
217: if (0 == nodeCount) {
218: throw new com.sun.jbi.framework.XmlParseException(
219: sTranslator.getString(
220: LocalStringKeys.XML_EMPTY_ELEMENT, node
221: .getNodeName()));
222: }
223:
224: // Get the text node
225: Node textNode = null;
226: for (int n = 0; n < nodeCount; n++) {
227: if (nodes.item(n).getNodeType() == Node.TEXT_NODE) {
228: textNode = nodes.item(n);
229: break;
230: }
231: }
232: if (null == textNode) {
233: throw new com.sun.jbi.framework.XmlParseException(
234: sTranslator.getString(
235: LocalStringKeys.XML_MISSING_ELEMENT,
236: "TEXT", node.getNodeName()));
237: }
238: String value;
239: try {
240: value = URLDecoder.decode(((Text) textNode).getData(),
241: VALUE_UTF8).trim();
242: } catch (java.io.UnsupportedEncodingException ueEx) {
243: value = ((Text) textNode).getData();
244: }
245: return value;
246: }
247:
248: /**
249: * Get a String value from a named element in the specified node.
250: * @param node - the node to be processed.
251: * @param tag - the element to be processed.
252: * @param isRequired - true if the element is required, false if not.
253: * @return A String containing the text value from the specified element,
254: * or null if the element is not present and isRequired is false.
255: * @throws com.sun.jbi.framework.XmlParseException if the node list is
256: * null or if any node is missing its text node.
257: */
258: static String getStringValue(Node node, String tag,
259: boolean isRequired)
260: throws com.sun.jbi.framework.XmlParseException {
261: String value = null;
262: NodeList nl = getElements(node, tag, isRequired);
263: if (0 != nl.getLength()) {
264: value = getStringValue(nl);
265: }
266: return value;
267: }
268:
269: /**
270: * Get a single String value from a node list. The node list is expected
271: * to contain exactly one node, which in turn is expected to contain
272: * exactly one text node. If the node list is null or has multiple elements,
273: * an exception is thrown.
274: * @param nodeList - the node list to be processed.
275: * @return The String value from the node.
276: * @throws com.sun.jbi.framework.XmlParseException if the node list is
277: * null or has multiple elements, or if the node is missing its text
278: * element.
279: */
280: static String getStringValue(NodeList nodeList)
281: throws com.sun.jbi.framework.XmlParseException {
282: if (null == nodeList) {
283: throw new java.lang.IllegalArgumentException(sTranslator
284: .getString(LocalStringKeys.NULL_ARGUMENT,
285: "nodeList"));
286: }
287: if (0 == nodeList.getLength()) {
288: throw new java.lang.IllegalArgumentException(sTranslator
289: .getString(LocalStringKeys.EMPTY_LIST_ARGUMENT,
290: "nodeList"));
291: }
292: Node node = nodeList.item(0);
293: if (1 != nodeList.getLength()) {
294: throw new com.sun.jbi.framework.XmlParseException(
295: sTranslator.getString(
296: LocalStringKeys.XML_EXTRA_ELEMENTS,
297: new Integer(nodeList.getLength()), node
298: .getNodeName()));
299: }
300: Node textNode = node.getFirstChild();
301: if (null == textNode) {
302: throw new com.sun.jbi.framework.XmlParseException(
303: sTranslator.getString(
304: LocalStringKeys.XML_EMPTY_ELEMENT, node
305: .getNodeName()));
306: }
307: if (!(textNode instanceof Text)) {
308: throw new com.sun.jbi.framework.XmlParseException(
309: sTranslator.getString(
310: LocalStringKeys.XML_INVALID_ELEMENT, node
311: .getNodeName()));
312: }
313: String value;
314: try {
315: value = URLDecoder.decode(((Text) textNode).getData(),
316: VALUE_UTF8).trim();
317: } catch (java.io.UnsupportedEncodingException ueEx) {
318: value = ((Text) textNode).getData();
319: }
320: return value;
321: }
322:
323: /**
324: * Get a list of String values from a named element in the specified node.
325: * @param node - the node to be processed.
326: * @param tag - the element to be processed.
327: * @param isRequired - true if the element is required, false if not.
328: * @return A list of Strings containing the text values from the specified
329: * elements. The list is empty if no elements were found and isRequired is
330: * false.
331: * @throws com.sun.jbi.framework.XmlParseException if the node list is
332: * null or if any node is missing its text node, or if a required element
333: * is not found.
334: */
335: static List<String> getStringValueArray(Node node, String tag,
336: boolean isRequired)
337: throws com.sun.jbi.framework.XmlParseException {
338: NodeList nl = getElements(node, tag, isRequired);
339: if ((null == nl) && !isRequired) {
340: return new ArrayList();
341: } else {
342: return getStringValueArray(nl);
343: }
344: }
345:
346: /**
347: * Get a list of String values from a named element in the specified node.
348: * @param node - the node to be processed.
349: * @param tag1 - the parent element to be processed.
350: * @param tag2 - the child element to be processed.
351: * @param isRequired - true if the element is required, false if not.
352: * @return A list of Strings containing the text values from the specified
353: * elements. The list is empty if no elements were found and isRequired is
354: * false.
355: * @throws com.sun.jbi.framework.XmlParseException if the node list is
356: * null or if any node is missing its text node, or if a required element
357: * is not found.
358: */
359: static List<String> getStringValueArray(Node node, String tag1,
360: String tag2, boolean isRequired)
361: throws com.sun.jbi.framework.XmlParseException {
362: NodeList nl = getElements(node, tag1, isRequired);
363: if (nl.getLength() > 1) {
364: throw new com.sun.jbi.framework.XmlParseException(
365: sTranslator.getString(
366: LocalStringKeys.XML_EXTRA_ELEMENTS,
367: new Integer(nl.getLength()), tag1));
368: }
369: NodeList nl2 = getElements(nl.item(0), tag2, isRequired);
370: if ((null == nl2) && !isRequired) {
371: return new ArrayList();
372: } else {
373: return getStringValueArray(nl2);
374: }
375: }
376:
377: /**
378: * Get a list of String values from a node list. The node list can have
379: * any number of nodes, each of which must have a single Text node. For
380: * example, given the following XML fragment defined by a node list:
381: *
382: * <PRE><CODE>
383: * <sharedNamespaceId>shared-namespace-1</sharedNamespaceId>
384: * <sharedNamespaceId>shared-namespace-2</sharedNamespaceId>
385: * <sharedNamespaceId>shared-namespace-3</sharedNamespaceId>
386: * </CODE></PRE>
387: *
388: * The returned ArrayList for this node list would contain three String
389: * instances with values "shared-namespace-1", "shared-namespace-2", and
390: * "shared-namespace-3".
391: *
392: * @param nodeList - the node list to be processed.
393: * @return An array list containing String values from the Text nodes, or
394: * null if there were none.
395: * @throws java.lang.IllegalArgumentException if the node list is null.
396: * @throws com.sun.jbi.framework.XmlParseException if any node in the
397: * list is missing a text node.
398: */
399: static List<String> getStringValueArray(NodeList nodeList)
400: throws com.sun.jbi.framework.XmlParseException {
401: if (null == nodeList) {
402: throw new java.lang.IllegalArgumentException(sTranslator
403: .getString(LocalStringKeys.NULL_ARGUMENT,
404: "nodeList"));
405: }
406:
407: ArrayList elements = new ArrayList();
408: for (int i = 0; i < nodeList.getLength(); ++i) {
409: Node node = nodeList.item(i);
410: Node textNode = node.getFirstChild();
411: if (null == textNode) {
412: throw new com.sun.jbi.framework.XmlParseException(
413: sTranslator.getString(
414: LocalStringKeys.XML_EMPTY_ELEMENT, node
415: .getNodeName()));
416: }
417: if (!(textNode instanceof Text)) {
418: throw new com.sun.jbi.framework.XmlParseException(
419: sTranslator.getString(
420: LocalStringKeys.XML_INVALID_ELEMENT,
421: node.getNodeName()));
422: }
423: String value;
424: try {
425: value = URLDecoder.decode(((Text) textNode).getData(),
426: VALUE_UTF8).trim();
427: } catch (java.io.UnsupportedEncodingException ueEx) {
428: value = ((Text) textNode).getData();
429: }
430: elements.add(value);
431: }
432: return elements;
433: }
434:
435: }
|