001: /*
002: * $Id: UtilXml.java,v 1.3 2003/12/06 16:00:29 ajzeneski Exp $
003: *
004: * Copyright (c) 2001, 2002 The Open For Business Project - www.ofbiz.org
005: *
006: * Permission is hereby granted, free of charge, to any person obtaining a
007: * copy of this software and associated documentation files (the "Software"),
008: * to deal in the Software without restriction, including without limitation
009: * the rights to use, copy, modify, merge, publish, distribute, sublicense,
010: * and/or sell copies of the Software, and to permit persons to whom the
011: * Software is furnished to do so, subject to the following conditions:
012: *
013: * The above copyright notice and this permission notice shall be included
014: * in all copies or substantial portions of the Software.
015: *
016: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
017: * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
018: * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
019: * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
020: * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
021: * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
022: * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
023: */
024: package org.ofbiz.base.util;
025:
026: import java.io.ByteArrayInputStream;
027: import java.io.ByteArrayOutputStream;
028: import java.io.File;
029: import java.io.FileOutputStream;
030: import java.io.IOException;
031: import java.io.InputStream;
032: import java.io.OutputStream;
033: import java.net.URL;
034: import java.util.LinkedList;
035: import java.util.List;
036:
037: import javax.xml.parsers.DocumentBuilder;
038: import javax.xml.parsers.DocumentBuilderFactory;
039: import javax.xml.parsers.ParserConfigurationException;
040:
041: import org.apache.xml.serialize.OutputFormat;
042: import org.apache.xml.serialize.XMLSerializer;
043: import org.w3c.dom.Document;
044: import org.w3c.dom.Element;
045: import org.w3c.dom.Node;
046: import org.xml.sax.EntityResolver;
047: import org.xml.sax.ErrorHandler;
048: import org.xml.sax.InputSource;
049: import org.xml.sax.SAXException;
050: import org.xml.sax.SAXParseException;
051: import org.xml.sax.helpers.DefaultHandler;
052:
053: /**
054: * Utilities methods to simplify dealing with JAXP & DOM XML parsing
055: *
056: * @author <a href="mailto:jonesde@ofbiz.org">David E. Jones</a>
057: * @version $Revision: 1.3 $
058: * @since 2.0
059: */
060: public class UtilXml {
061:
062: public static final String module = UtilXml.class.getName();
063:
064: public static String writeXmlDocument(Document document)
065: throws java.io.IOException {
066: if (document == null) {
067: Debug
068: .logWarning(
069: "[UtilXml.writeXmlDocument] Document was null, doing nothing",
070: module);
071: return null;
072: }
073:
074: ByteArrayOutputStream bos = new ByteArrayOutputStream();
075: writeXmlDocument(bos, document);
076: String outString = bos.toString("UTF-8");
077:
078: if (bos != null)
079: bos.close();
080: return outString;
081: }
082:
083: public static void writeXmlDocument(String filename,
084: Document document) throws java.io.FileNotFoundException,
085: java.io.IOException {
086: if (document == null) {
087: Debug
088: .logWarning(
089: "[UtilXml.writeXmlDocument] Document was null, doing nothing",
090: module);
091: return;
092: }
093: if (filename == null) {
094: Debug
095: .logWarning(
096: "[UtilXml.writeXmlDocument] Filename was null, doing nothing",
097: module);
098: return;
099: }
100:
101: File outFile = new File(filename);
102: FileOutputStream fos = null;
103: fos = new FileOutputStream(outFile);
104:
105: try {
106: writeXmlDocument(fos, document);
107: } finally {
108: if (fos != null)
109: fos.close();
110: }
111: }
112:
113: public static void writeXmlDocument(OutputStream os,
114: Document document) throws java.io.IOException {
115: if (document == null) {
116: Debug
117: .logWarning(
118: "[UtilXml.writeXmlDocument] Document was null, doing nothing",
119: module);
120: return;
121: }
122: if (os == null) {
123: Debug
124: .logWarning(
125: "[UtilXml.writeXmlDocument] OutputStream was null, doing nothing",
126: module);
127: return;
128: }
129:
130: // if(document instanceof XmlDocument) {
131: // Crimson writer
132: // XmlDocument xdoc = (XmlDocument) document;
133: // xdoc.write(os);
134: // }
135: // else {
136: // Xerces writer
137: OutputFormat format = new OutputFormat(document);
138: format.setIndent(2);
139:
140: XMLSerializer serializer = new XMLSerializer(os, format);
141: serializer.asDOMSerializer();
142: serializer.serialize(document.getDocumentElement());
143: // }
144: }
145:
146: public static Document readXmlDocument(String content)
147: throws SAXException, ParserConfigurationException,
148: java.io.IOException {
149: return readXmlDocument(content, true);
150: }
151:
152: public static Document readXmlDocument(String content,
153: boolean validate) throws SAXException,
154: ParserConfigurationException, java.io.IOException {
155: if (content == null) {
156: Debug
157: .logWarning(
158: "[UtilXml.readXmlDocument] content was null, doing nothing",
159: module);
160: return null;
161: }
162: ByteArrayInputStream bis = new ByteArrayInputStream(content
163: .getBytes("UTF-8"));
164: return readXmlDocument(bis, validate, "Internal Content");
165: }
166:
167: public static Document readXmlDocument(URL url)
168: throws SAXException, ParserConfigurationException,
169: java.io.IOException {
170: return readXmlDocument(url, true);
171: }
172:
173: public static Document readXmlDocument(URL url, boolean validate)
174: throws SAXException, ParserConfigurationException,
175: java.io.IOException {
176: if (url == null) {
177: Debug
178: .logWarning(
179: "[UtilXml.readXmlDocument] URL was null, doing nothing",
180: module);
181: return null;
182: }
183: return readXmlDocument(url.openStream(), validate, url
184: .toString());
185: }
186:
187: public static Document readXmlDocument(InputStream is)
188: throws SAXException, ParserConfigurationException,
189: java.io.IOException {
190: return readXmlDocument(is, true, null);
191: }
192:
193: public static Document readXmlDocument(InputStream is,
194: boolean validate, String docDescription)
195: throws SAXException, ParserConfigurationException,
196: java.io.IOException {
197: if (is == null) {
198: Debug
199: .logWarning(
200: "[UtilXml.readXmlDocument] InputStream was null, doing nothing",
201: module);
202: return null;
203: }
204:
205: Document document = null;
206: DocumentBuilderFactory factory = DocumentBuilderFactory
207: .newInstance();
208:
209: factory.setValidating(validate);
210: factory.setNamespaceAware(true);
211: DocumentBuilder builder = factory.newDocumentBuilder();
212: if (validate) {
213: LocalResolver lr = new LocalResolver(new DefaultHandler());
214: ErrorHandler eh = new LocalErrorHandler(docDescription, lr);
215:
216: builder.setEntityResolver(lr);
217: builder.setErrorHandler(eh);
218: }
219:
220: document = builder.parse(is);
221: return document;
222: }
223:
224: public static Document makeEmptyXmlDocument() {
225: return makeEmptyXmlDocument(null);
226: }
227:
228: public static Document makeEmptyXmlDocument(String rootElementName) {
229: Document document = null;
230: DocumentBuilderFactory factory = DocumentBuilderFactory
231: .newInstance();
232:
233: factory.setValidating(true);
234: // factory.setNamespaceAware(true);
235: try {
236: DocumentBuilder builder = factory.newDocumentBuilder();
237:
238: document = builder.newDocument();
239: } catch (Exception e) {
240: Debug.logError(e, module);
241: }
242:
243: if (document == null)
244: return null;
245:
246: if (rootElementName != null) {
247: Element rootElement = document
248: .createElement(rootElementName);
249: document.appendChild(rootElement);
250: }
251:
252: return document;
253: }
254:
255: /** Creates a child element with the given name and appends it to the element child node list. */
256: public static Element addChildElement(Element element,
257: String childElementName, Document document) {
258: Element newElement = document.createElement(childElementName);
259:
260: element.appendChild(newElement);
261: return newElement;
262: }
263:
264: /** Creates a child element with the given name and appends it to the element child node list.
265: * Also creates a Text node with the given value and appends it to the new elements child node list.
266: */
267: public static Element addChildElementValue(Element element,
268: String childElementName, String childElementValue,
269: Document document) {
270: Element newElement = addChildElement(element, childElementName,
271: document);
272:
273: newElement.appendChild(document
274: .createTextNode(childElementValue));
275: return newElement;
276: }
277:
278: /** Creates a child element with the given name and appends it to the element child node list.
279: * Also creates a CDATASection node with the given value and appends it to the new elements child node list.
280: */
281: public static Element addChildElementCDATAValue(Element element,
282: String childElementName, String childElementValue,
283: Document document) {
284: Element newElement = addChildElement(element, childElementName,
285: document);
286:
287: newElement.appendChild(document
288: .createCDATASection(childElementValue));
289: return newElement;
290: }
291:
292: /** Return a List of Element objects that have the given name and are
293: * immediate children of the given element; if name is null, all child
294: * elements will be included. */
295: public static List childElementList(Element element,
296: String childElementName) {
297: if (element == null)
298: return null;
299:
300: List elements = new LinkedList();
301: Node node = element.getFirstChild();
302:
303: if (node != null) {
304: do {
305: if (node.getNodeType() == Node.ELEMENT_NODE
306: && (childElementName == null || childElementName
307: .equals(node.getNodeName()))) {
308: Element childElement = (Element) node;
309:
310: elements.add(childElement);
311: }
312: } while ((node = node.getNextSibling()) != null);
313: }
314: return elements;
315: }
316:
317: /** Return the first child Element with the given name; if name is null
318: * returns the first element. */
319: public static Element firstChildElement(Element element,
320: String childElementName) {
321: if (element == null)
322: return null;
323: // get the first element with the given name
324: Node node = element.getFirstChild();
325:
326: if (node != null) {
327: do {
328: if (node.getNodeType() == Node.ELEMENT_NODE
329: && (childElementName == null || childElementName
330: .equals(node.getNodeName()))) {
331: Element childElement = (Element) node;
332:
333: return childElement;
334: }
335: } while ((node = node.getNextSibling()) != null);
336: }
337: return null;
338: }
339:
340: /** Return the first child Element with the given name; if name is null
341: * returns the first element. */
342: public static Element firstChildElement(Element element,
343: String childElementName, String attrName, String attrValue) {
344: if (element == null)
345: return null;
346: // get the first element with the given name
347: Node node = element.getFirstChild();
348:
349: if (node != null) {
350: do {
351: if (node.getNodeType() == Node.ELEMENT_NODE
352: && (childElementName == null || childElementName
353: .equals(node.getNodeName()))) {
354: Element childElement = (Element) node;
355:
356: String value = childElement.getAttribute(attrName);
357:
358: if (value != null && value.equals(attrValue)) {
359: return childElement;
360: }
361: }
362: } while ((node = node.getNextSibling()) != null);
363: }
364: return null;
365: }
366:
367: /** Return the text (node value) contained by the named child node. */
368: public static String childElementValue(Element element,
369: String childElementName) {
370: if (element == null)
371: return null;
372: // get the value of the first element with the given name
373: Element childElement = firstChildElement(element,
374: childElementName);
375:
376: return elementValue(childElement);
377: }
378:
379: /** Return the text (node value) contained by the named child node or a default value if null. */
380: public static String childElementValue(Element element,
381: String childElementName, String defaultValue) {
382: if (element == null)
383: return defaultValue;
384: // get the value of the first element with the given name
385: Element childElement = firstChildElement(element,
386: childElementName);
387: String elementValue = elementValue(childElement);
388:
389: if (elementValue == null || elementValue.length() == 0)
390: return defaultValue;
391: else
392: return elementValue;
393: }
394:
395: /** Return the text (node value) of the first node under this, works best if normalized. */
396: public static String elementValue(Element element) {
397: if (element == null)
398: return null;
399: // make sure we get all the text there...
400: element.normalize();
401: Node textNode = element.getFirstChild();
402:
403: if (textNode == null)
404: return null;
405:
406: StringBuffer valueBuffer = new StringBuffer();
407: do {
408: if (textNode.getNodeType() == Node.CDATA_SECTION_NODE
409: || textNode.getNodeType() == Node.TEXT_NODE) {
410: valueBuffer.append(textNode.getNodeValue());
411: }
412: } while ((textNode = textNode.getNextSibling()) != null);
413: return valueBuffer.toString();
414: }
415:
416: public static String checkEmpty(String string) {
417: if (string != null && string.length() > 0)
418: return string;
419: else
420: return "";
421: }
422:
423: public static String checkEmpty(String string1, String string2) {
424: if (string1 != null && string1.length() > 0)
425: return string1;
426: else if (string2 != null && string2.length() > 0)
427: return string2;
428: else
429: return "";
430: }
431:
432: public static String checkEmpty(String string1, String string2,
433: String string3) {
434: if (string1 != null && string1.length() > 0)
435: return string1;
436: else if (string2 != null && string2.length() > 0)
437: return string2;
438: else if (string3 != null && string3.length() > 0)
439: return string3;
440: else
441: return "";
442: }
443:
444: public static boolean checkBoolean(String str) {
445: return checkBoolean(str, false);
446: }
447:
448: public static boolean checkBoolean(String str, boolean defaultValue) {
449: if (defaultValue) {
450: //default to true, ie anything but false is true
451: return !"false".equals(str);
452: } else {
453: //default to false, ie anything but true is false
454: return "true".equals(str);
455: }
456: }
457:
458: /**
459: * Local entity resolver to handle J2EE DTDs. With this a http connection
460: * to sun is not needed during deployment.
461: * Function boolean hadDTD() is here to avoid validation errors in
462: * descriptors that do not have a DOCTYPE declaration.
463: */
464: public static class LocalResolver implements EntityResolver {
465:
466: private boolean hasDTD = false;
467: private EntityResolver defaultResolver;
468:
469: public LocalResolver(EntityResolver defaultResolver) {
470: this .defaultResolver = defaultResolver;
471: }
472:
473: /**
474: * Returns DTD inputSource. If DTD was found in the dtds Map and inputSource was created
475: * flag hasDTD is set to true.
476: * @param publicId - Public ID of DTD
477: * @param systemId - System ID of DTD
478: * @return InputSource of DTD
479: */
480: public InputSource resolveEntity(String publicId,
481: String systemId) throws SAXException, IOException {
482: hasDTD = false;
483: String dtd = UtilProperties.getSplitPropertyValue(UtilURL
484: .fromResource("localdtds.properties"), publicId);
485:
486: if (Debug.verboseOn())
487: Debug
488: .logVerbose(
489: "[UtilXml.LocalResolver.resolveEntity] resolving DTD with publicId ["
490: + publicId + "], systemId ["
491: + systemId
492: + "] and the dtd file is ["
493: + dtd + "]", module);
494: if (dtd != null && dtd.length() > 0) {
495: try {
496: URL dtdURL = UtilURL.fromResource(dtd);
497: InputStream dtdStream = dtdURL.openStream();
498: InputSource inputSource = new InputSource(dtdStream);
499:
500: inputSource.setPublicId(publicId);
501: hasDTD = true;
502: if (Debug.verboseOn())
503: Debug
504: .logVerbose(
505: "[UtilXml.LocalResolver.resolveEntity] got LOCAL DTD input source with publicId ["
506: + publicId
507: + "] and the dtd file is ["
508: + dtd + "]", module);
509: return inputSource;
510: } catch (Exception e) {
511: Debug.logWarning(e, module);
512: }
513: }
514: if (Debug.verboseOn())
515: Debug
516: .logVerbose(
517: "[UtilXml.LocalResolver.resolveEntity] local resolve failed for DTD with publicId ["
518: + publicId
519: + "] and the dtd file is ["
520: + dtd
521: + "], trying defaultResolver",
522: module);
523: return defaultResolver.resolveEntity(publicId, systemId);
524: }
525:
526: /**
527: * Returns the boolean value to inform id DTD was found in the XML file or not
528: * @return boolean - true if DTD was found in XML
529: */
530: public boolean hasDTD() {
531: return hasDTD;
532: }
533: }
534:
535: /** Local error handler for entity resolver to DocumentBuilder parser.
536: * Error is printed to output just if DTD was detected in the XML file.
537: */
538: public static class LocalErrorHandler implements ErrorHandler {
539:
540: private String docDescription;
541: private LocalResolver localResolver;
542:
543: public LocalErrorHandler(String docDescription,
544: LocalResolver localResolver) {
545: this .docDescription = docDescription;
546: this .localResolver = localResolver;
547: }
548:
549: public void error(SAXParseException exception) {
550: if (localResolver.hasDTD()) {
551: Debug.logError("XmlFileLoader: File " + docDescription
552: + " process error. Line: "
553: + String.valueOf(exception.getLineNumber())
554: + ". Error message: " + exception.getMessage(),
555: module);
556: }
557: }
558:
559: public void fatalError(SAXParseException exception) {
560: if (localResolver.hasDTD()) {
561: Debug.logError("XmlFileLoader: File " + docDescription
562: + " process fatal error. Line: "
563: + String.valueOf(exception.getLineNumber())
564: + ". Error message: " + exception.getMessage(),
565: module);
566: }
567: }
568:
569: public void warning(SAXParseException exception) {
570: if (localResolver.hasDTD()) {
571: Debug.logError("XmlFileLoader: File " + docDescription
572: + " process warning. Line: "
573: + String.valueOf(exception.getLineNumber())
574: + ". Error message: " + exception.getMessage(),
575: module);
576: }
577: }
578: }
579: }
|