001: /*
002: * Copyright 2006 Pentaho Corporation. All rights reserved.
003: * This software was developed by Pentaho Corporation and is provided under the terms
004: * of the Mozilla Public License, Version 1.1, or any later version. You may not use
005: * this file except in compliance with the license. If you need a copy of the license,
006: * please go to http://www.mozilla.org/MPL/MPL-1.1.txt. The Original Code is the Pentaho
007: * BI Platform. The Initial Developer is Pentaho Corporation.
008: *
009: * Software distributed under the Mozilla Public License is distributed on an "AS IS"
010: * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. Please refer to
011: * the license for the specific language governing your rights and limitations.
012: *
013: * @created Jun 17, 2005
014: * @author James Dixon
015: * @author Marc Batchelor
016: */
017:
018: package org.pentaho.core.util;
019:
020: import java.io.ByteArrayInputStream;
021: import java.io.File;
022: import java.io.FileInputStream;
023: import java.io.FileNotFoundException;
024: import java.io.IOException;
025: import java.io.InputStream;
026: import java.io.UnsupportedEncodingException;
027: import java.math.BigDecimal;
028: import java.net.MalformedURLException;
029: import java.net.URL;
030: import java.text.ParseException;
031: import java.text.SimpleDateFormat;
032: import java.util.ArrayList;
033: import java.util.Date;
034: import java.util.HashMap;
035: import java.util.Iterator;
036: import java.util.List;
037: import java.util.Locale;
038: import java.util.Map;
039: import java.util.TimeZone;
040:
041: import javax.xml.transform.TransformerException;
042: import javax.xml.transform.URIResolver;
043:
044: import org.apache.commons.lang.StringEscapeUtils;
045: import org.apache.commons.logging.Log;
046: import org.apache.commons.logging.LogFactory;
047: import org.dom4j.Document;
048: import org.dom4j.DocumentException;
049: import org.dom4j.Element;
050: import org.dom4j.Node;
051: import org.pentaho.core.session.IPentahoSession;
052: import org.pentaho.core.system.PentahoSystem;
053: import org.pentaho.messages.Messages;
054: import org.pentaho.messages.util.LocaleHelper;
055: import org.pentaho.repository.PentahoEntityResolver;
056: import org.pentaho.util.PentahoChainedException;
057: import org.pentaho.util.logging.Logger;
058: import org.xml.sax.EntityResolver;
059:
060: /**
061: * A set of static methods for performing various operations on DOM Documents
062: * and XML text (in the form of streams, Strings, and files). The operations include
063: * creating DOM Documents (dom4j)
064: * transforming DOM Documents
065: * creating XML from Objects, Lists and Maps
066: * creating Lists or Maps from XML
067: * getting an XML node's text
068: *
069: * @author mbatchel/jdixon
070: *
071: */
072: public class XmlHelper extends CleanXmlHelper {
073:
074: private static final String DEFAULT_XSL_FOLDER = "system/custom/xsl/"; //$NON-NLS-1$
075:
076: private static final Log logger = LogFactory
077: .getLog(XmlHelper.class);
078:
079: private static final EntityResolver entityResolver = new PentahoEntityResolver();
080:
081: /**
082: * Should never be called.
083: *
084: */
085: private XmlHelper() {
086: }
087:
088: /**
089: * Create a <code>Document</code> from <code>str</code>.
090: *
091: * @param str String containing the XML that will be used to create the Document
092: * @return <code>Document</code> initialized with the xml in <code>strXml</code>.
093: */
094: public static Document getDocFromString(String strXml) {
095: Document doc = null;
096: try {
097: doc = CleanXmlHelper.getDocFromString(strXml,
098: entityResolver);
099: } catch (DocumentException e) {
100: Logger
101: .error(
102: XmlHelper.class.getName(),
103: Messages
104: .getErrorString(
105: "XmlHelper.ERROR_0014_FAILED_TO_PARSE_XML_DOCUMENT", //$NON-NLS-1$
106: strXml), e);
107: doc = null;
108: }
109: return doc;
110: }
111:
112: /**
113: * Create a <code>Document</code> from the contents of the input file
114: * <code>file</code>.
115: *
116: * @param file <code>File</code> usd to create the input stream that will be
117: * used to create the <code>Document</code>
118: * @return <code>Document</code> containing the contents of the file f.
119: */
120: public static Document getDocFromFile(File file) {
121: Document document = null;
122:
123: try {
124: document = CleanXmlHelper.getDocFromFile(file,
125: entityResolver);
126: } catch (IOException e) {
127: Logger
128: .error(
129: XmlHelper.class.getName(),
130: Messages
131: .getErrorString(
132: "XmlHelper.ERROR_0013_FAILED_TO_CREATE_FILEINPUTSTREAM", //$NON-NLS-1$
133: file.getPath()), e);
134: } catch (DocumentException e) {
135: Logger
136: .error(
137: XmlHelper.class.getName(),
138: Messages
139: .getErrorString(
140: "XmlHelper.ERROR_0014_FAILED_TO_PARSE_XML_DOCUMENT", //$NON-NLS-1$
141: file.getPath()), e);
142: }
143:
144: return document;
145: }
146:
147: /**
148: * Use the transform specified by xslName and xslPath, and transform the document specified
149: * by document, and return the resulting document.
150: *
151: * @param xslName String containing the path in the repository of the file containing the xsl transform
152: * @param document Document containing the document to be transformed
153: * @param params Map of properties to set on the transform
154: * @param session IPentahoSession containing a URIResolver instance to resolve URI's in the output document.
155: *
156: * @return StringBuffer containing the XML results of the transform. Null if there was an error.
157: * @throws TransformerException If attempt to transform the document fails.
158: */
159: public static final StringBuffer transformXml(String xslName,
160: String xslPath, Document document, Map params,
161: IPentahoSession session) throws TransformerException {
162:
163: InputStream inStrm = null;
164: try {
165: String xml = document.asXML();
166: String encoding = XmlHelper.getEncoding(xml);
167: inStrm = new ByteArrayInputStream(xml.getBytes(encoding));
168: } catch (UnsupportedEncodingException e) {
169: if (logger.isErrorEnabled()) {
170: logger.error(e);
171: }
172: }
173: StringBuffer result = transformXml(xslName, xslPath, inStrm,
174: params, session);
175: CleanXmlHelper.closeInputStream(inStrm);
176:
177: return result;
178: }
179:
180: /**
181: * Not currently used.
182: *
183: * Use the transform specified by xslName and transform the document specified
184: * by document, and return the resulting document.
185: *
186: * @param xslName String containing the path in the repository of the file containing the xsl transform
187: * @param document Document containing the document to be transformed
188: * @param params Map of properties to set on the transform
189: * @param session IPentahoSession containing a URIResolver instance to resolve URI's in the output document.
190: *
191: * @return StringBuffer containing the XML results of the transform. Null if there was an error.
192: * @throws TransformerException If attempt to transform the document fails.
193: */
194: public static final StringBuffer transformXml(String xslName,
195: Document document, Map params, IPentahoSession session)
196: throws TransformerException {
197: return transformXml(xslName, null, document, params, session);
198: }
199:
200: /**
201: * Not currently used.
202: *
203: * Use the transform specified by xslName and xslPath,and transform the document specified
204: * by uri, and return the resulting document.
205: *
206: * @param xslName String containing the name of a file in the repository containing the xsl transform
207: * @param xslPath String containing the path to the file identifyied by <code>xslName</code>
208: * @param uri String containing the URI of a resource containing the document to be transformed
209: * @param params Map of properties to set on the transform
210: * @param session IPentahoSession containing a URIResolver instance to resolve URI's in the output document.
211: *
212: * @return StringBuffer containing the XML results of the transform. Null if there was an error.
213: * @throws TransformerException If attempt to transform the document fails.
214: */
215: public static final StringBuffer transformXmlUrl(String xslName,
216: String xslPath, String uri, Map params,
217: IPentahoSession session) throws TransformerException {
218:
219: URL url = null;
220: try {
221: url = new URL(uri);
222: } catch (MalformedURLException e) {
223: Logger
224: .error(
225: XmlHelper.class.getName(),
226: Messages
227: .getErrorString(
228: "XmlHelper.ERROR_0007_TRANSFORM_XML_URL", e.getMessage(), xslName), e); //$NON-NLS-1$
229: return null;
230: }
231: InputStream inStrm = null;
232: try {
233: inStrm = url.openStream();
234: } catch (IOException e) {
235: Logger
236: .error(
237: XmlHelper.class.getName(),
238: Messages
239: .getErrorString(
240: "XmlHelper.ERROR_0007_TRANSFORM_XML_URL", e.getMessage(), xslName), e); //$NON-NLS-1$
241: return null;
242: }
243: return transformXml(xslName, xslPath, inStrm, params, session);
244: }
245:
246: /**
247: * Use the transform specified by xslName and transform the document specified
248: * by docInStrm, and return the resulting document.
249: *
250: * @param xslName String containing the name of a file in the repository containing the xsl transform
251: * @param xslPath String containing the path to the file identifyied by <code>xslName</code>
252: * @param uri String containing the URI of a resource containing the document to be transformed
253: * @param params Map of properties to set on the transform
254: * @param session IPentahoSession containing a URIResolver instance to resolve URI's in the output document.
255: *
256: * @return StringBuffer containing the XML results of the transform. Null if there was an error.
257: * @throws TransformerException If attempt to transform the document fails.
258: */
259: public static final StringBuffer transformXml(String xslName,
260: String xslPath, String strDocument, Map params,
261: IPentahoSession session) throws TransformerException {
262: InputStream inStrm = null;
263: try {
264: String encoding = XmlHelper.getEncoding(strDocument);
265: inStrm = new ByteArrayInputStream(strDocument
266: .getBytes(encoding));
267: } catch (UnsupportedEncodingException e) {
268: if (logger.isErrorEnabled()) {
269: logger.error(e);
270: }
271: }
272: StringBuffer result = transformXml(xslName, xslPath, inStrm,
273: params, session);
274: CleanXmlHelper.closeInputStream(inStrm);
275:
276: return result;
277: }
278:
279: /**
280: * Use the transform specified by xslPath and xslName and transform the document specified
281: * by docInStrm, and return the resulting document.
282: *
283: * @param xslSrc StreamSrc containing the xsl transform
284: * @param docSrc StreamSrc containing the document to be transformed
285: * @param params Map of properties to set on the transform
286: * @param session IPentahoSession containing a URIResolver instance to resolve URI's in the output document.
287: *
288: * @return StringBuffer containing the XML results of the transform. Null if there was an error.
289: * @throws TransformerException If attempt to transform the document fails.
290: */
291: public static final StringBuffer transformXml(String xslName,
292: String xslPath, InputStream docInStrm, Map params,
293: IPentahoSession session) throws TransformerException {
294: StringBuffer result = null;
295:
296: File localeXsl = getLocalizedXsl(xslPath, xslName);
297: if (null == localeXsl) {
298: Logger
299: .error(
300: XmlHelper.class.getName(),
301: Messages
302: .getErrorString("XmlHelper.ERROR_0003_NULL_XSL_SOURCE")); //$NON-NLS-1$
303: } else if (null == docInStrm) {
304: Logger
305: .error(
306: XmlHelper.class.getName(),
307: Messages
308: .getErrorString("XmlHelper.ERROR_0004_NULL_DOCUMENT")); //$NON-NLS-1$
309: } else {
310:
311: FileInputStream xslInStrm = null;
312: try {
313: xslInStrm = new FileInputStream(localeXsl);
314: } catch (FileNotFoundException e) {
315: Logger
316: .error(
317: XmlHelper.class.getName(),
318: Messages
319: .getErrorString(
320: "XmlHelper.ERROR_0013_FAILED_TO_CREATE_FILEINPUTSTREAM", e.getMessage(), xslName), e); //$NON-NLS-1$
321: }
322: // at this point, we have both of our InputStreams
323:
324: // Add encoding for any xsl that may set/use it
325: if (params == null) {
326: params = new HashMap();
327: }
328: params
329: .put(
330: "output-encoding", LocaleHelper.getSystemEncoding()); //$NON-NLS-1$
331:
332: URIResolver resolver = new SolutionURIResolver(session);
333: try {
334: result = CleanXmlHelper.transformXml(xslInStrm,
335: docInStrm, params, resolver);
336: } catch (TransformerException e) {
337: Logger
338: .error(
339: XmlHelper.class.getName(),
340: Messages
341: .getErrorString(
342: "XmlHelper.ERROR_0006_TRANSFORM_XML_ERROR", e.getMessage(), xslName), e); //$NON-NLS-1$
343: throw e;
344: } finally {
345: CleanXmlHelper.closeInputStream(xslInStrm);
346: }
347: }
348: return result;
349: }
350:
351: /**
352: * Find the character encoding specification in the xml String. If it exists, return
353: * the character encoding. Otherwise, return the system encoding.
354: *
355: * @param xml String containing the xml
356: * @return String containing the character encoding in the xml processing instruction
357: * if it exists, else the system encoding.
358: */
359: public static String getEncoding(String xml) {
360: String enc = CleanXmlHelper.getEncoding(xml);
361:
362: return null != enc ? enc : LocaleHelper.getSystemEncoding();
363: }
364:
365: /*
366: TODO sbarkdull, delete this, these methods exist in the SolutionRepository
367:
368: public static ResourceBundle getBundle(String baseName, File localeDir, Locale locale) {
369: try {
370:
371: URL localeDirUrl = localeDir.getParentFile().toURL();
372: URLClassLoader loader = new URLClassLoader(new URL[] { localeDirUrl });
373:
374: ResourceBundle bundle = ResourceBundle.getBundle(baseName, locale, loader);
375: return bundle;
376:
377: } catch (Exception e) {
378: Logger.error("XmlHelper", Messages.getErrorString("XmlHelper.ERROR_0012_COULD_NOT_READ_PROPERTIES", localeDir.getAbsolutePath() + File.separator + baseName), e); //$NON-NLS-1$ //$NON-NLS-2$
379: }
380: return null;
381: }
382:
383: // TODO sbarkdull, the caller of this method has no way of knowing if it succeeded or failed, needs
384: // to be fixed, should throw exception when something fails so caller knows of failure
385: // code is not currently used
386: public static void localizeDoc(Node document, File file, Locale locale, boolean xmlEncode) {
387:
388: String fileName = file.getName();
389: int dotIndex = fileName.indexOf('.');
390: String baseName = fileName.substring(0, dotIndex);
391: ResourceBundle bundle = null;
392: bundle = getBundle(baseName, file, locale);
393: if (bundle == null) {
394: return;
395: }
396: localizeDoc(document, bundle, locale, file.getAbsolutePath(), xmlEncode);
397: }
398:
399: // TODO sbarkdull, this code is duplicated in LocaleHelper
400: // public static String getXmlEncodedString(String rawValue) {
401: // return CleanXmlHelper.getXmlEncodedString( rawValue );
402: // }
403:
404: public static void localizeDoc(Node document, ResourceBundle bundle, Locale locale, String bundlePath, boolean xmlEncode) {
405:
406: if (bundle == null) {
407: return;
408: }
409: try {
410:
411: List nodes = document.selectNodes("descendant::*"); //$NON-NLS-1$
412: Iterator nodeIterator = nodes.iterator();
413: while (nodeIterator.hasNext()) {
414: Node node = (Node) nodeIterator.next();
415: String name = node.getText();
416: if (name.startsWith("%") && !node.getPath().endsWith("/text()")) { //$NON-NLS-1$ //$NON-NLS-2$
417: try {
418: if (bundle != null) {
419: String localeText = bundle.getString(name.substring(1));
420: if (localeText != null) {
421: if (xmlEncode) {
422: node.setText(CleanXmlHelper.getXmlEncodedString(localeText));
423: } else {
424: node.setText(localeText);
425: }
426: }
427: }
428: } catch (Exception e) {
429: Logger.warn("XmlHelper", Messages.getString("XmlHelper.WARN_MISSING_RESOURCE_PROPERTY", name.substring(1), bundlePath, locale.toString())); //$NON-NLS-1$ //$NON-NLS-2$
430: }
431: }
432: }
433:
434: } catch (Exception e) {
435: Logger.error("XmlHelper", Messages.getErrorString("XmlHelper.ERROR_0012_COULD_NOT_READ_PROPERTIES", bundlePath), e); //$NON-NLS-1$ //$NON-NLS-2$
436: }
437:
438: }
439:
440: */
441:
442: public static File getLocalizedFile(String fullPath, Locale locale) {
443: String language = locale.getLanguage();
444: String country = locale.getCountry();
445: String variant = locale.getVariant();
446:
447: File file = new File(fullPath);
448:
449: String fileName = file.getName();
450: int dotIndex = fileName.indexOf('.');
451: String baseName = dotIndex == -1 ? fileName : fileName
452: .substring(0, dotIndex); // These two lines fix an index out of bounds
453: String extension = dotIndex == -1 ? "" : fileName.substring(dotIndex); // Exception that occurs when a filename has no extension //$NON-NLS-1$
454:
455: File directory = file.getParentFile();
456: File localeFile = null;
457: if (!variant.equals("")) { //$NON-NLS-1$
458: localeFile = new File(
459: directory,
460: baseName
461: + "_" + language + "_" + country + "_" + variant + extension); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
462: }
463: if (localeFile == null || !localeFile.exists()) {
464: localeFile = new File(directory, baseName
465: + "_" + language + "_" + country + extension); //$NON-NLS-1$//$NON-NLS-2$
466: }
467: if (!localeFile.exists()) {
468: localeFile = new File(directory, baseName
469: + "_" + language + extension); //$NON-NLS-1$
470: }
471: if (!localeFile.exists()) {
472: localeFile = new File(directory, baseName + extension);
473: }
474: if (localeFile.exists()) {
475: return localeFile;
476: } else {
477: return null;
478: }
479: }
480:
481: /**
482: * Get the File object corresponding to the path, filename (xslName), and
483: * locale. The path is relative to the solution path.
484: *
485: * @param path
486: * @param xslName
487: * @return
488: */
489: public static final File getLocalizedXsl(String path, String xslName) {
490: String fullPath = null;
491: File file = null;
492: if (null != path) {
493: // try to find it on the specified path
494: fullPath = PentahoSystem.getApplicationContext()
495: .getSolutionPath(path + File.separator + xslName)
496: .replace('\\', '/');
497: file = getLocalizedFile(fullPath, LocaleHelper.getLocale());
498: }
499: if (null == file) {
500: // didn't find the file, let's try default path
501: fullPath = PentahoSystem.getApplicationContext()
502: .getSolutionPath(DEFAULT_XSL_FOLDER + xslName)
503: .replace('\\', '/');
504: file = getLocalizedFile(fullPath, LocaleHelper.getLocale());
505: }
506: if (null == file) {
507: // we should not get this far...
508: Logger
509: .error(
510: XmlHelper.class.getName(),
511: Messages
512: .getErrorString(
513: "XmlHelper.ERROR_0011_TRANSFORM_XSL_DOES_NOT_EXIST", fullPath)); //$NON-NLS-1$
514: }
515: return file;
516: }
517:
518: public static Document getDomFromResource(String path) {
519: String fullPath = PentahoSystem.getApplicationContext()
520: .getSolutionPath(path);
521: File f = new File(fullPath);
522: return getDocFromFile(f);
523: }
524:
525: public static String getContentFromResource(String fullPath) {
526: Document doc = getDomFromResource(fullPath);
527: return doc.asXML();
528: }
529:
530: public static String getContentFromSolutionResource(String path) {
531: return getContentFromResource(path);
532: }
533:
534: /*
535: * The following methods converts lists/maps to/from XML. author: mbatchelor
536: */
537:
538: public static String listToXML(List l)
539: throws UnsupportedOperationException {
540: return listToXML(l, ""); //$NON-NLS-1$
541: }
542:
543: public static String listToXML(List l, String indent)
544: throws UnsupportedOperationException {
545: StringBuffer sb = new StringBuffer();
546: sb.append(indent).append("<list>\r"); //$NON-NLS-1$
547: String newIndent = indent + " "; //$NON-NLS-1$
548: Object obj;
549: for (int i = 0; i < l.size(); i++) {
550: obj = l.get(i);
551: sb.append(newIndent).append("<list-element>\r"); //$NON-NLS-1$
552: objToXML(obj, sb, newIndent);
553: sb.append(newIndent).append("</list-element>\r"); //$NON-NLS-1$
554: }
555: sb.append(indent).append("</list>\r"); //$NON-NLS-1$
556: return sb.toString();
557: }
558:
559: public static String mapToXML(Map m)
560: throws UnsupportedOperationException {
561: return mapToXML(m, ""); //$NON-NLS-1$
562: }
563:
564: public static String mapToXML(Map mp, String indent)
565: throws UnsupportedOperationException {
566: StringBuffer sb = new StringBuffer();
567: sb.append(indent).append("<map>\r"); //$NON-NLS-1$
568: String newIndent = indent + " "; //$NON-NLS-1$
569: Iterator it = mp.entrySet().iterator();
570: Map.Entry ent;
571: Object obj;
572: while (it.hasNext()) {
573: ent = (Map.Entry) it.next();
574: if (!(ent.getKey() instanceof String)) {
575: throw new UnsupportedOperationException(Messages
576: .getErrorString("XMLUTL.ERROR_0011_MAP_KEYS")); //$NON-NLS-1$
577: }
578: sb.append(newIndent).append("<map-entry>\r"); //$NON-NLS-1$
579: sb.append(newIndent).append("<key>\r"); //$NON-NLS-1$
580: sb
581: .append(newIndent)
582: .append("<![CDATA[").append(ent.getKey().toString()).append("]]>\r"); //$NON-NLS-1$ //$NON-NLS-2$
583: sb.append(newIndent).append("</key>\r"); //$NON-NLS-1$
584: obj = ent.getValue();
585: objToXML(obj, sb, newIndent);
586: sb.append(newIndent).append("</map-entry>\r"); //$NON-NLS-1$
587: }
588: sb.append(indent).append("</map>\r"); //$NON-NLS-1$
589: return sb.toString();
590: }
591:
592: private static void objToXML(Object obj, StringBuffer sb,
593: String newIndent) {
594: if (obj instanceof String) {
595: sb.append(newIndent).append("<string-value>\r"); //$NON-NLS-1$
596: sb
597: .append(newIndent)
598: .append("<![CDATA[").append((String) obj).append("]]>\r"); //$NON-NLS-1$ //$NON-NLS-2$
599: sb.append(newIndent).append("</string-value>\r"); //$NON-NLS-1$
600: } else if (obj instanceof StringBuffer) {
601: sb.append(newIndent).append("<stringbuffer-value>\r"); //$NON-NLS-1$
602: sb
603: .append(newIndent)
604: .append("<![CDATA[").append(obj.toString()).append("]]>\r"); //$NON-NLS-1$ //$NON-NLS-2$
605: sb.append(newIndent).append("</stringbuffer-value>\r"); //$NON-NLS-1$
606: } else if (obj instanceof BigDecimal) {
607: sb
608: .append(newIndent)
609: .append("<bigdecimal-value>").append(obj.toString()).append("</bigdecimal-value>\r"); //$NON-NLS-1$ //$NON-NLS-2$
610: } else if (obj instanceof Date) {
611: SimpleDateFormat fmt = new SimpleDateFormat();
612: fmt.setTimeZone(TimeZone.getTimeZone("GMT")); //$NON-NLS-1$
613: sb.append(newIndent).append("<date-value>"); //$NON-NLS-1$
614: sb.append(fmt.format((Date) obj)).append("</date-value>\r"); //$NON-NLS-1$
615: } else if (obj instanceof Long) {
616: sb.append(newIndent).append("<long-value>"); //$NON-NLS-1$
617: sb.append(obj.toString()).append("</long-value>\r"); //$NON-NLS-1$
618: } else if (obj instanceof Map) {
619: sb.append(newIndent).append("<map-value>\r"); //$NON-NLS-1$
620: sb.append(mapToXML((Map) obj, newIndent));
621: sb.append(newIndent).append("</map-value>\r"); //$NON-NLS-1$
622: } else if (obj instanceof List) {
623: sb.append(newIndent).append("<list-value>\r"); //$NON-NLS-1$
624: sb.append(listToXML((List) obj, newIndent));
625: sb.append(newIndent).append("</list-value>\r"); //$NON-NLS-1$
626: } else {
627: throw new UnsupportedOperationException(
628: Messages
629: .getErrorString(
630: "XMLUTL.ERROR_0012_DATA_TYPE", obj.getClass().getName())); //$NON-NLS-1$
631: }
632:
633: }
634:
635: public static List xmlToList(String s)
636: throws PentahoChainedException {
637: try {
638: Document doc = XmlHelper.getDocFromString(s);
639: Element root = doc.getRootElement();
640: return processList(root);
641: } catch (ParseException pex) {
642: throw new PentahoChainedException(Messages
643: .getErrorString("XMLUTL.ERROR_0013_PARSING"), pex); //$NON-NLS-1$
644: }
645: }
646:
647: public static Map xmlToMap(String s) throws PentahoChainedException {
648: try {
649: Document doc = XmlHelper.getDocFromString(s);
650: Element root = doc.getRootElement();
651: return processMap(root);
652: } catch (ParseException pex) {
653: throw new PentahoChainedException(Messages
654: .getErrorString("XMLUTL.ERROR_0013_PARSING"), pex); //$NON-NLS-1$
655: }
656: }
657:
658: public static List processList(Element ele) throws ParseException {
659: List rtn = new ArrayList();
660: Iterator it = ele.elementIterator();
661: Element anElement;
662: while (it.hasNext()) {
663: anElement = (Element) it.next();
664: processListElement(anElement, rtn);
665: }
666: return rtn;
667: }
668:
669: public static Map processMap(Element ele) throws ParseException {
670: Map rtn = new HashMap();
671: Iterator it = ele.elementIterator();
672: Element anElement;
673: while (it.hasNext()) {
674: anElement = (Element) it.next();
675: processMapElement(anElement, rtn);
676: }
677: return rtn;
678: }
679:
680: public static Object elementToObject(Element anElement)
681: throws ParseException {
682: if (anElement.getName().equals("string-value")) { //$NON-NLS-1$
683: return anElement.getTextTrim();
684: } else if (anElement.getName().equals("stringbuffer-value")) { //$NON-NLS-1$
685: return new StringBuffer(anElement.getTextTrim());
686: } else if (anElement.getName().equals("bigdecimal-value")) { //$NON-NLS-1$
687: return new BigDecimal(anElement.getTextTrim());
688: } else if (anElement.getName().equals("long-value")) { //$NON-NLS-1$
689: return new Long(anElement.getTextTrim());
690: } else if (anElement.getName().equals("date-value")) { //$NON-NLS-1$
691: SimpleDateFormat fmt = new SimpleDateFormat();
692: fmt.setTimeZone(TimeZone.getTimeZone("GMT")); //$NON-NLS-1$
693: return fmt.parse(anElement.getTextTrim());
694: } else if (anElement.getName().equals("list-value")) { //$NON-NLS-1$
695: return processList(anElement.element("list")); //$NON-NLS-1$
696: } else if (anElement.getName().equals("map-value")) { //$NON-NLS-1$
697: return processMap(anElement.element("map")); //$NON-NLS-1$
698: } else {
699: throw new ParseException(
700: Messages
701: .getErrorString(
702: "XMLUTL.ERROR_0014_UNKNOWN_TYPE", anElement.getName()), 0); //$NON-NLS-1$
703: }
704: }
705:
706: public static void processListElement(Element ele, List rtn)
707: throws ParseException {
708: Iterator it = ele.elementIterator();
709: Element anElement;
710: while (it.hasNext()) {
711: anElement = (Element) it.next();
712: Object anObj = elementToObject(anElement);
713: rtn.add(anObj);
714: }
715: }
716:
717: public static void processMapElement(Element ele, Map rtn)
718: throws ParseException {
719: Iterator it = ele.elementIterator();
720: Element keyElement = null;
721: Element valueElement = null;
722: Element anElement = null;
723: while (it.hasNext()) {
724: anElement = (Element) it.next();
725: if (anElement.getName().equals("key")) { //$NON-NLS-1$
726: keyElement = anElement;
727: } else {
728: valueElement = anElement;
729: }
730: }
731: // Now, we have our key and our value. Let's figure out what kind of
732: // processing is required.
733: Object anObj = elementToObject(valueElement);
734: rtn.put(keyElement.getTextTrim(), anObj);
735: }
736:
737: // TODO sbarkdull begin, these methods could be moved to CleanXmlHelper
738:
739: public static String getNodeText(String xpath, Node rootNode) {
740: return (getNodeText(xpath, rootNode, null));
741: }
742:
743: public static long getNodeText(String xpath, Node rootNode,
744: long defaultValue) {
745: String valueStr = getNodeText(xpath, rootNode, Long
746: .toString(defaultValue));
747: try {
748: return Long.parseLong(valueStr);
749: } catch (Exception e) {
750: }
751: return defaultValue;
752: }
753:
754: public static double getNodeText(String xpath, Node rootNode,
755: double defaultValue) {
756: String valueStr = getNodeText(xpath, rootNode, null);
757: if (valueStr == null) {
758: return defaultValue;
759: }
760: try {
761: return Double.parseDouble(valueStr);
762: } catch (Exception e) {
763: }
764: return defaultValue;
765: }
766:
767: public static String getNodeText(String xpath, Node rootNode,
768: String defaultValue) {
769: if (rootNode == null) {
770: return (defaultValue);
771: }
772: Node node = rootNode.selectSingleNode(xpath);
773: if (node == null) {
774: return defaultValue;
775: }
776: return node.getText();
777: }
778:
779: public static void decode(String[] strings) {
780: if (strings != null) {
781: for (int i = 0; i < strings.length; ++i) {
782: strings[i] = decode(strings[i]);
783: }
784: }
785: }
786:
787: public static String decode(String string) {
788: // TODO replace this is a more robust encoder
789: if (string != null) {
790: string = string.replaceAll("<", "<") //$NON-NLS-1$ //$NON-NLS-2$
791: .replaceAll(">", ">") //$NON-NLS-1$ //$NON-NLS-2$
792: .replaceAll("'", "'") //$NON-NLS-1$ //$NON-NLS-2$
793: .replaceAll(""", "\"") //$NON-NLS-1$ //$NON-NLS-2$
794: .replaceAll("&", "&"); //$NON-NLS-1$ //$NON-NLS-2$ // DO THE & LAST!!!!
795: }
796: return string;
797: }
798:
799: public static void encode(String[] strings) {
800: if (strings != null) {
801: for (int i = 0; i < strings.length; ++i) {
802: strings[i] = encode(strings[i]);
803: }
804: }
805: }
806:
807: public static String encode(String string) {
808:
809: return StringEscapeUtils.escapeXml(string);
810: }
811: // TODO sbarkdull end, some of these preceeding methods could be moved to CleanXmlHelper
812:
813: }
|