KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > mondrian > tui > XmlUtil


1 /*
2 // $Id: //open/mondrian/src/main/mondrian/tui/XmlUtil.java#8 $
3 // This software is subject to the terms of the Common Public License
4 // Agreement, available at the following URL:
5 // http://www.opensource.org/licenses/cpl.html.
6 // Copyright (C) 2005-2007 Julian Hyde and others
7 // All Rights Reserved.
8 // You must accept the terms of that agreement to use this software.
9 */

10
11 package mondrian.tui;
12
13 import org.apache.xerces.dom.DocumentImpl;
14 import org.apache.xerces.impl.Constants;
15 import org.apache.xerces.parsers.DOMParser;
16 import org.apache.xml.serialize.OutputFormat;
17 import org.apache.xml.serialize.XMLSerializer;
18 import org.apache.xpath.domapi.XPathEvaluatorImpl;
19 import org.w3c.dom.*;
20 import org.w3c.dom.xpath.*;
21 import org.xml.sax.*;
22
23 import javax.xml.parsers.*;
24 import javax.xml.transform.*;
25 import javax.xml.transform.dom.DOMResult JavaDoc;
26 import javax.xml.transform.dom.DOMSource JavaDoc;
27 import java.io.*;
28 import java.util.*;
29
30 /**
31  * Some XML parsing, validation and transform utility methods used
32  * to valiate XMLA responses.
33  *
34  * @author Richard M. Emberson
35  * @version $Id: //open/mondrian/src/main/mondrian/tui/XmlUtil.java#8 $
36  */

37 public class XmlUtil {
38
39     public static final String JavaDoc LINE_SEP =
40             System.getProperty("line.separator", "\n");
41
42
43     public static final String JavaDoc SOAP_PREFIX = "SOAP-ENV";
44     public static final String JavaDoc XSD_PREFIX = "xsd";
45
46     public static final String JavaDoc XMLNS = "xmlns";
47
48     public static final String JavaDoc NAMESPACES_FEATURE_ID =
49               "http://xml.org/sax/features/namespaces";
50     public static final String JavaDoc VALIDATION_FEATURE_ID =
51               "http://xml.org/sax/features/validation";
52
53     public static final String JavaDoc SCHEMA_VALIDATION_FEATURE_ID =
54               "http://apache.org/xml/features/validation/schema";
55     public static final String JavaDoc FULL_SCHEMA_VALIDATION_FEATURE_ID =
56               "http://apache.org/xml/features/validation/schema-full-checking";
57
58     public static final String JavaDoc DEFER_NODE_EXPANSION =
59               "http://apache.org/xml/features/dom/defer-node-expansion";
60
61     public static final String JavaDoc SCHEMA_LOCATION =
62                 Constants.XERCES_PROPERTY_PREFIX + Constants.SCHEMA_LOCATION;
63
64     /**
65      * This is the xslt that can extract the "data" part of a SOAP
66      * XMLA response.
67      */

68     public static final String JavaDoc getSoapXmlaXds2xd(String JavaDoc xmlaPrefix) {
69         return
70         "<?xml version='1.0'?>" + LINE_SEP +
71         "<xsl:stylesheet " + LINE_SEP +
72             "xmlns:xsl='http://www.w3.org/1999/XSL/Transform' " + LINE_SEP +
73             "xmlns:xalan='http://xml.apache.org/xslt' " + LINE_SEP +
74             "xmlns:xsd='http://www.w3.org/2001/XMLSchema' " + LINE_SEP +
75             "xmlns:ROW='urn:schemas-microsoft-com:xml-analysis:rowset' " + LINE_SEP +
76             "xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/' " + LINE_SEP +
77             "xmlns:xmla='urn:schemas-microsoft-com:xml-analysis' " + LINE_SEP +
78             "version='1.0' " + LINE_SEP +
79                 "> " + LINE_SEP +
80         "<xsl:output method='xml' " + LINE_SEP +
81             "encoding='UTF-8' " + LINE_SEP +
82             "indent='yes' " + LINE_SEP +
83             "xalan:indent-amount='2'/> " + LINE_SEP +
84             " " + LINE_SEP +
85             "<!-- consume '/' and apply --> " + LINE_SEP +
86             "<xsl:template match='/'> " + LINE_SEP +
87                 "<xsl:apply-templates/> " + LINE_SEP +
88             "</xsl:template> " + LINE_SEP +
89             "<!-- consume 'Envelope' and apply --> " + LINE_SEP +
90             "<xsl:template match='SOAP-ENV:Envelope'> " + LINE_SEP +
91                 "<xsl:apply-templates/> " + LINE_SEP +
92             "</xsl:template> " + LINE_SEP +
93             "<!-- consume 'Header' --> " + LINE_SEP +
94             "<xsl:template match='SOAP-ENV:Header'> " + LINE_SEP +
95             "</xsl:template> " + LINE_SEP +
96             "<!-- consume 'Body' and apply --> " + LINE_SEP +
97             "<xsl:template match='SOAP-ENV:Body'> " + LINE_SEP +
98                 "<xsl:apply-templates/> " + LINE_SEP +
99             "</xsl:template> " + LINE_SEP +
100             "<!-- consume 'DiscoverResponse' and apply --> " + LINE_SEP +
101             "<xsl:template match='" + xmlaPrefix + ":DiscoverResponse'> " + LINE_SEP +
102                 "<xsl:apply-templates/> " + LINE_SEP +
103             "</xsl:template> " + LINE_SEP +
104             "<!-- consume 'return' and apply --> " + LINE_SEP +
105             "<xsl:template match='" + xmlaPrefix + ":return'> " + LINE_SEP +
106                 "<xsl:apply-templates/> " + LINE_SEP +
107             "</xsl:template> " + LINE_SEP +
108             "<!-- consume 'xsd:schema' --> " + LINE_SEP +
109             "<xsl:template match='xsd:schema'> " + LINE_SEP +
110             "</xsl:template> " + LINE_SEP +
111             "<!-- copy everything else --> " + LINE_SEP +
112             "<xsl:template match='*|@*'> " + LINE_SEP +
113                 "<xsl:copy> " + LINE_SEP +
114                     "<xsl:apply-templates select='@*|node()'/> " + LINE_SEP +
115                 "</xsl:copy> " + LINE_SEP +
116             "</xsl:template> " + LINE_SEP +
117         "</xsl:stylesheet>";
118     }
119
120     /**
121      * This is the xslt that can extract the "schema" part of a SOAP
122      * XMLA response.
123      */

124     public static final String JavaDoc getSoapXmlaXds2xs(String JavaDoc xmlaPrefix) {
125         return
126         "<?xml version='1.0'?> " + LINE_SEP +
127         "<xsl:stylesheet " + LINE_SEP +
128             "xmlns:xsl='http://www.w3.org/1999/XSL/Transform' " + LINE_SEP +
129             "xmlns:xalan='http://xml.apache.org/xslt' " + LINE_SEP +
130             "xmlns:xsd='http://www.w3.org/2001/XMLSchema' " + LINE_SEP +
131             "xmlns:ROW='urn:schemas-microsoft-com:xml-analysis:rowset' " + LINE_SEP +
132             "xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/' " + LINE_SEP +
133             "xmlns:xmla='urn:schemas-microsoft-com:xml-analysis' " + LINE_SEP +
134             "version='1.0' " + LINE_SEP +
135                 "> " + LINE_SEP +
136         "<xsl:output method='xml' " + LINE_SEP +
137             "encoding='UTF-8' " + LINE_SEP +
138             "indent='yes' " + LINE_SEP +
139             "xalan:indent-amount='2'/> " + LINE_SEP +
140             "<!-- consume '/' and apply --> " + LINE_SEP +
141             "<xsl:template match='/'> " + LINE_SEP +
142                 "<xsl:apply-templates/> " + LINE_SEP +
143             "</xsl:template> " + LINE_SEP +
144             "<!-- consume 'Envelope' and apply --> " + LINE_SEP +
145             "<xsl:template match='SOAP-ENV:Envelope'> " + LINE_SEP +
146                 "<xsl:apply-templates/> " + LINE_SEP +
147             "</xsl:template> " + LINE_SEP +
148             "<!-- consume 'Header' --> " + LINE_SEP +
149             "<xsl:template match='SOAP-ENV:Header'> " + LINE_SEP +
150             "</xsl:template> " + LINE_SEP +
151             "<!-- consume 'Body' and apply --> " + LINE_SEP +
152             "<xsl:template match='SOAP-ENV:Body'> " + LINE_SEP +
153                 "<xsl:apply-templates/> " + LINE_SEP +
154             "</xsl:template> " + LINE_SEP +
155             "<!-- consume 'DiscoverResponse' and apply --> " + LINE_SEP +
156             "<xsl:template match='" + xmlaPrefix + ":DiscoverResponse'> " + LINE_SEP +
157                 "<xsl:apply-templates/> " + LINE_SEP +
158             "</xsl:template> " + LINE_SEP +
159             "<!-- consume 'return' and apply --> " + LINE_SEP +
160             "<xsl:template match='" + xmlaPrefix + ":return'> " + LINE_SEP +
161                 "<xsl:apply-templates/> " + LINE_SEP +
162             "</xsl:template> " + LINE_SEP +
163             "<!-- consume 'root' and apply --> " + LINE_SEP +
164             "<xsl:template match='ROW:root'> " + LINE_SEP +
165                 "<xsl:apply-templates/> " + LINE_SEP +
166             "</xsl:template> " + LINE_SEP +
167             "<!-- consume 'row' --> " + LINE_SEP +
168             "<xsl:template match='ROW:row'> " + LINE_SEP +
169             "</xsl:template> " + LINE_SEP +
170             "<!-- copy everything else --> " + LINE_SEP +
171             "<xsl:template match='*|@*'> " + LINE_SEP +
172                 "<xsl:copy> " + LINE_SEP +
173                     "<xsl:apply-templates select='@*|node()'/> " + LINE_SEP +
174                 "</xsl:copy> " + LINE_SEP +
175             "</xsl:template> " + LINE_SEP +
176         "</xsl:stylesheet>";
177     }
178
179     /**
180      * This is the xslt that can extract the "data" part of a XMLA response.
181      */

182     public static final String JavaDoc getXmlaXds2xd(String JavaDoc ns) {
183         String JavaDoc xmlaPrefix = (ns == null) ? "" : (ns + ":");
184         return
185         "<?xml version='1.0'?>" + LINE_SEP +
186         "<xsl:stylesheet " + LINE_SEP +
187             "xmlns:xsl='http://www.w3.org/1999/XSL/Transform' " + LINE_SEP +
188             "xmlns:xalan='http://xml.apache.org/xslt' " + LINE_SEP +
189             "xmlns:xsd='http://www.w3.org/2001/XMLSchema' " + LINE_SEP +
190             "xmlns:ROW='urn:schemas-microsoft-com:xml-analysis:rowset' " + LINE_SEP +
191             "xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/' " + LINE_SEP +
192             "xmlns:xmla='urn:schemas-microsoft-com:xml-analysis' " + LINE_SEP +
193             "version='1.0' " + LINE_SEP +
194                 "> " + LINE_SEP +
195         "<xsl:output method='xml' " + LINE_SEP +
196             "encoding='UTF-8' " + LINE_SEP +
197             "indent='yes' " + LINE_SEP +
198             "xalan:indent-amount='2'/> " + LINE_SEP +
199             " " + LINE_SEP +
200             "<!-- consume '/' and apply --> " + LINE_SEP +
201             "<xsl:template match='/'> " + LINE_SEP +
202                 "<xsl:apply-templates/> " + LINE_SEP +
203             "</xsl:template> " + LINE_SEP +
204             "<!-- consume 'DiscoverResponse' and apply --> " + LINE_SEP +
205             "<xsl:template match='" + xmlaPrefix + "DiscoverResponse'> " + LINE_SEP +
206                 "<xsl:apply-templates/> " + LINE_SEP +
207             "</xsl:template> " + LINE_SEP +
208             "<!-- consume 'return' and apply --> " + LINE_SEP +
209             "<xsl:template match='" + xmlaPrefix + "return'> " + LINE_SEP +
210                 "<xsl:apply-templates/> " + LINE_SEP +
211             "</xsl:template> " + LINE_SEP +
212             "<!-- consume 'xsd:schema' --> " + LINE_SEP +
213             "<xsl:template match='xsd:schema'> " + LINE_SEP +
214             "</xsl:template> " + LINE_SEP +
215             "<!-- copy everything else --> " + LINE_SEP +
216             "<xsl:template match='*|@*'> " + LINE_SEP +
217                 "<xsl:copy> " + LINE_SEP +
218                     "<xsl:apply-templates select='@*|node()'/> " + LINE_SEP +
219                 "</xsl:copy> " + LINE_SEP +
220             "</xsl:template> " + LINE_SEP +
221         "</xsl:stylesheet>";
222     }
223
224     /**
225      * This is the xslt that can extract the "schema" part of a XMLA response.
226      */

227     public static final String JavaDoc getXmlaXds2xs(String JavaDoc ns) {
228         String JavaDoc xmlaPrefix = (ns == null) ? "" : (ns + ":");
229         return
230         "<?xml version='1.0'?> " + LINE_SEP +
231         "<xsl:stylesheet " + LINE_SEP +
232             "xmlns:xsl='http://www.w3.org/1999/XSL/Transform' " + LINE_SEP +
233             "xmlns:xalan='http://xml.apache.org/xslt' " + LINE_SEP +
234             "xmlns:xsd='http://www.w3.org/2001/XMLSchema' " + LINE_SEP +
235             "xmlns:ROW='urn:schemas-microsoft-com:xml-analysis:rowset' " + LINE_SEP +
236             "xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/' " + LINE_SEP +
237             "xmlns:xmla='urn:schemas-microsoft-com:xml-analysis' " + LINE_SEP +
238             "version='1.0' " + LINE_SEP +
239                 "> " + LINE_SEP +
240         "<xsl:output method='xml' " + LINE_SEP +
241             "encoding='UTF-8' " + LINE_SEP +
242             "indent='yes' " + LINE_SEP +
243             "xalan:indent-amount='2'/> " + LINE_SEP +
244             "<!-- consume '/' and apply --> " + LINE_SEP +
245             "<xsl:template match='/'> " + LINE_SEP +
246                 "<xsl:apply-templates/> " + LINE_SEP +
247             "</xsl:template> " + LINE_SEP +
248             "<!-- consume 'DiscoverResponse' and apply --> " + LINE_SEP +
249             "<xsl:template match='" + xmlaPrefix + "DiscoverResponse'> " + LINE_SEP +
250                 "<xsl:apply-templates/> " + LINE_SEP +
251             "</xsl:template> " + LINE_SEP +
252             "<!-- consume 'return' and apply --> " + LINE_SEP +
253             "<xsl:template match='" + xmlaPrefix + "return'> " + LINE_SEP +
254                 "<xsl:apply-templates/> " + LINE_SEP +
255             "</xsl:template> " + LINE_SEP +
256             "<!-- consume 'root' and apply --> " + LINE_SEP +
257             "<xsl:template match='ROW:root'> " + LINE_SEP +
258                 "<xsl:apply-templates/> " + LINE_SEP +
259             "</xsl:template> " + LINE_SEP +
260             "<!-- consume 'row' --> " + LINE_SEP +
261             "<xsl:template match='ROW:row'> " + LINE_SEP +
262             "</xsl:template> " + LINE_SEP +
263             "<!-- copy everything else --> " + LINE_SEP +
264             "<xsl:template match='*|@*'> " + LINE_SEP +
265                 "<xsl:copy> " + LINE_SEP +
266                     "<xsl:apply-templates select='@*|node()'/> " + LINE_SEP +
267                 "</xsl:copy> " + LINE_SEP +
268             "</xsl:template> " + LINE_SEP +
269         "</xsl:stylesheet>";
270     }
271
272     /**
273      * Error handler plus helper methods.
274      */

275     public static class SAXErrorHandler implements ErrorHandler {
276         public static final String JavaDoc WARNING_STRING = "WARNING";
277         public static final String JavaDoc ERROR_STRING = "ERROR";
278         public static final String JavaDoc FATAL_ERROR_STRING = "FATAL";
279
280         // DOMError values
281
public static final short SEVERITY_WARNING = 1;
282         public static final short SEVERITY_ERROR = 2;
283         public static final short SEVERITY_FATAL_ERROR = 3;
284
285         public void printErrorInfos(PrintStream out) {
286             if (errors != null) {
287                 for (ErrorInfo error : errors) {
288                     out.println(formatErrorInfo(error));
289                 }
290             }
291         }
292
293         public static String JavaDoc formatErrorInfos(SAXErrorHandler saxEH) {
294             if (! saxEH.hasErrors()) {
295                 return "";
296             }
297             StringBuilder JavaDoc buf = new StringBuilder JavaDoc(512);
298             for (ErrorInfo error : saxEH.getErrors()) {
299                 buf.append(formatErrorInfo(error));
300                 buf.append(LINE_SEP);
301             }
302             return buf.toString();
303         }
304
305         public static String JavaDoc formatErrorInfo(ErrorInfo ei) {
306             StringBuilder JavaDoc buf = new StringBuilder JavaDoc(128);
307             buf.append("[");
308             switch (ei.severity) {
309             case SEVERITY_WARNING:
310                 buf.append(WARNING_STRING);
311                 break;
312             case SEVERITY_ERROR:
313                 buf.append(ERROR_STRING);
314                 break;
315             case SEVERITY_FATAL_ERROR:
316                 buf.append(FATAL_ERROR_STRING);
317                 break;
318             }
319             buf.append(']');
320             String JavaDoc systemId = ei.exception.getSystemId();
321             if (systemId != null) {
322                 int index = systemId.lastIndexOf('/');
323                 if (index != -1) {
324                     systemId = systemId.substring(index + 1);
325                 }
326                 buf.append(systemId);
327             }
328             buf.append(':');
329             buf.append(ei.exception.getLineNumber());
330             buf.append(':');
331             buf.append(ei.exception.getColumnNumber());
332             buf.append(": ");
333             buf.append(ei.exception.getMessage());
334             return buf.toString();
335         }
336         public static class ErrorInfo {
337             public SAXParseException exception;
338             public short severity;
339             ErrorInfo(short severity, SAXParseException exception) {
340                 this.severity = severity;
341                 this.exception = exception;
342             }
343         }
344         private List<ErrorInfo> errors;
345         public SAXErrorHandler() {
346         }
347         public List<ErrorInfo> getErrors() {
348             return this.errors;
349         }
350         public boolean hasErrors() {
351             return (this.errors != null);
352         }
353         public void warning(SAXParseException exception) throws SAXException {
354             addError(new ErrorInfo(SEVERITY_WARNING, exception));
355         }
356         public void error(SAXParseException exception) throws SAXException {
357             addError(new ErrorInfo(SEVERITY_ERROR, exception));
358         }
359         public void fatalError(SAXParseException exception)
360                                                         throws SAXException {
361             addError(new ErrorInfo(SEVERITY_FATAL_ERROR, exception));
362         }
363         protected void addError(ErrorInfo ei) {
364             if (this.errors == null) {
365                 this.errors = new ArrayList<ErrorInfo>();
366             }
367             this.errors.add(ei);
368         }
369
370         public String JavaDoc getFirstError() {
371             return (hasErrors())
372                 ? formatErrorInfo(errors.get(0))
373                 : "";
374         }
375     }
376
377     public static Document newDocument(Node firstElement, boolean deepcopy) {
378         Document newDoc = new DocumentImpl();
379         newDoc.appendChild(newDoc.importNode(firstElement, deepcopy));
380         return newDoc;
381     }
382
383
384     //////////////////////////////////////////////////////////////////////////
385
// parse
386
//////////////////////////////////////////////////////////////////////////
387

388     /**
389      * Get your non-cached DOM parser which can be configured to do schema
390      * based validation of the instance Document.
391      *
392      */

393     public static DOMParser getParser(
394             String JavaDoc schemaLocationPropertyValue,
395             EntityResolver entityResolver,
396             boolean validate)
397             throws SAXNotRecognizedException, SAXNotSupportedException {
398
399         boolean doingValidation =
400             (validate || (schemaLocationPropertyValue != null));
401
402         DOMParser parser = new DOMParser();
403
404         parser.setEntityResolver(entityResolver);
405         parser.setErrorHandler(new SAXErrorHandler());
406         parser.setFeature(DEFER_NODE_EXPANSION, false);
407         parser.setFeature(NAMESPACES_FEATURE_ID, true);
408         parser.setFeature(SCHEMA_VALIDATION_FEATURE_ID, doingValidation);
409         parser.setFeature(VALIDATION_FEATURE_ID, doingValidation);
410
411         if (schemaLocationPropertyValue != null) {
412             parser.setProperty(SCHEMA_LOCATION,
413                 schemaLocationPropertyValue.replace('\\', '/'));
414         }
415
416         return parser;
417     }
418
419     /**
420      * See if the DOMParser after parsing a Document has any errors and,
421      * if so, throw a RuntimeException exception containing the errors.
422      *
423      */

424     private static void checkForParseError(final DOMParser parser, Throwable JavaDoc t) {
425         final ErrorHandler errorHandler = parser.getErrorHandler();
426
427         if (errorHandler instanceof SAXErrorHandler) {
428             final SAXErrorHandler saxEH = (SAXErrorHandler) errorHandler;
429             final List<SAXErrorHandler.ErrorInfo> errors = saxEH.getErrors();
430
431             if (errors != null && errors.size() > 0) {
432                 String JavaDoc errorStr = SAXErrorHandler.formatErrorInfos(saxEH);
433                 throw new RuntimeException JavaDoc(errorStr, t);
434             }
435         } else {
436             System.out.println("errorHandler=" +errorHandler);
437         }
438     }
439
440     private static void checkForParseError(final DOMParser parser) {
441         checkForParseError(parser, null);
442     }
443
444
445     /**
446      * Parse a String into a Document (no validation).
447      *
448      */

449     public static Document parseString(String JavaDoc s)
450             throws SAXException, IOException {
451         // Hack to workaround bug #622 until 1.4.2_08
452
final int length = s.length();
453
454         if (length > 16777216 && length % 4 == 1) {
455             final StringBuilder JavaDoc buf = new StringBuilder JavaDoc(length + 1);
456
457             buf.append(s);
458             buf.append('\n');
459             s = buf.toString();
460         }
461
462         return XmlUtil.parse(s.getBytes());
463     }
464
465     /**
466      * Parse a byte array into a Document (no validation).
467      *
468      */

469     public static Document parse(byte[] bytes)
470             throws SAXException, IOException {
471         return XmlUtil.parse(new ByteArrayInputStream(bytes));
472     }
473
474     public static Document parse(File file)
475             throws SAXException, IOException {
476
477         return parse(new FileInputStream(file));
478     }
479
480     /**
481      * Parse a stream into a Document (no validation).
482      *
483      */

484     public static Document parse(InputStream in)
485             throws SAXException, IOException {
486
487         InputSource source = new InputSource(in);
488
489         DOMParser parser = XmlUtil.getParser(null, null, false);
490         try {
491             parser.parse(source);
492             checkForParseError(parser);
493         } catch (SAXParseException ex) {
494             checkForParseError(parser, ex);
495         }
496
497         Document document = parser.getDocument();
498         return document;
499     }
500
501
502     //////////////////////////////////////////////////////////////////////////
503
// xpath
504
//////////////////////////////////////////////////////////////////////////
505
/**
506      * Create a context document for use in performing XPath operations.
507      * An array of prefix/namespace-urls are provided as input. These
508      * namespace-urls should be all of those that will appear in the
509      * document against which an xpath is to be applied.
510      * Importantly, it is, in fact, each element of the Document that
511      * has a default namespace these namespaces MUST have
512      * prefix/namespace-urls pairs in the context document and the prefix
513      * provided MUST also be used in the xpath.
514      * Elements with explicit namespaces don't have to have pairs in the
515      * context Document as long as the xpath uses the same prefixes
516      * that appear in the target Document.
517      *
518      */

519     public static Document createContextDocument(String JavaDoc[][] nsArray)
520             throws SAXException, IOException {
521         StringBuilder JavaDoc buf = new StringBuilder JavaDoc(256);
522         buf.append("<?xml version='1.0' encoding='utf-8'?>");
523         buf.append("<DOES_NOT_MATTER");
524         for (int i = 0; i < nsArray.length; i++) {
525             String JavaDoc prefix = nsArray[i][0];
526             String JavaDoc nsURI = nsArray[i][1];
527
528             buf.append(" xmlns:");
529             buf.append(prefix);
530             buf.append("=\"");
531             buf.append(nsURI);
532             buf.append("\"");
533         }
534         buf.append(" />");
535
536         String JavaDoc docStr = buf.toString();
537         return parseString(docStr);
538     }
539
540     public static String JavaDoc makeSoapPath() {
541         return XmlUtil.makeSoapPath(SOAP_PREFIX);
542     }
543
544     // '/soapX:Envelope/soapX:Body/*'
545
public static String JavaDoc makeSoapPath(String JavaDoc prefix) {
546         StringBuilder JavaDoc buf = new StringBuilder JavaDoc(20);
547         buf.append('/');
548         if (prefix != null) {
549             buf.append(prefix);
550             buf.append(':');
551         }
552         buf.append("Envelope");
553         buf.append('/');
554         if (prefix != null) {
555             buf.append(prefix);
556             buf.append(':');
557         }
558         buf.append("Body");
559         buf.append('/');
560         buf.append('*');
561
562         return buf.toString();
563     }
564
565     public static String JavaDoc makeRootPathInSoapBody() {
566         return makeRootPathInSoapBody("xmla", XSD_PREFIX);
567     }
568
569     // '/xmla:DiscoverResponse/xmla:return/ROW/root/*'
570
public static String JavaDoc makeRootPathInSoapBody(
571         String JavaDoc xmlaPrefix,
572         String JavaDoc xsdPrefix)
573     {
574         StringBuilder JavaDoc buf = new StringBuilder JavaDoc(20);
575         buf.append("/").append(xmlaPrefix).append(":DiscoverResponse");
576         buf.append("/").append(xmlaPrefix).append(":return");
577         buf.append("/ROW:root");
578         buf.append('/');
579         buf.append('*');
580 /*
581         if (xsdPrefix != null) {
582             buf.append(xsdPrefix);
583             buf.append(':');
584         }
585         buf.append("schema");
586 */

587
588         return buf.toString();
589     }
590
591     public static String JavaDoc selectAsString(Node node, String JavaDoc xpath)
592                                             throws XPathException {
593         return XmlUtil.selectAsString(node, xpath, node);
594     }
595     public static String JavaDoc selectAsString(Node node, String JavaDoc xpath,
596                         Node namespaceNode) throws XPathException {
597
598         XPathResult xpathResult = XmlUtil.select(node, xpath, namespaceNode);
599         return XmlUtil.convertToString(xpathResult, false);
600     }
601
602     public static Node[] selectAsNodes(Node node, String JavaDoc xpath)
603                                             throws XPathException {
604         return XmlUtil.selectAsNodes(node, xpath, node);
605     }
606     public static Node[] selectAsNodes(Node node, String JavaDoc xpath,
607                         Node namespaceNode) throws XPathException {
608
609         XPathResult xpathResult = XmlUtil.select(node, xpath, namespaceNode);
610         return XmlUtil.convertToNodes(xpathResult);
611     }
612
613     public static XPathResult select(Node contextNode, String JavaDoc xpath,
614                         Node namespaceNode) throws XPathException {
615         XPathEvaluator evaluator = new XPathEvaluatorImpl();
616         XPathNSResolver resolver = evaluator.createNSResolver(namespaceNode);
617
618         return (XPathResult) evaluator.evaluate(xpath, contextNode, resolver,
619                 XPathResult.ANY_TYPE, null);
620     }
621
622     /**
623      * Convert an XPathResult object to String.
624      *
625      */

626     public static String JavaDoc convertToString(XPathResult xpathResult,
627                                          boolean prettyPrint) {
628         switch (xpathResult.getResultType()) {
629         case XPathResult.NUMBER_TYPE:
630             double d = xpathResult.getNumberValue();
631             return Double.toString(d);
632
633         case XPathResult.STRING_TYPE:
634             String JavaDoc s = xpathResult.getStringValue();
635             return s;
636
637         case XPathResult.BOOLEAN_TYPE:
638             boolean b = xpathResult.getBooleanValue();
639             return String.valueOf(b);
640
641         case XPathResult.FIRST_ORDERED_NODE_TYPE:
642         case XPathResult.ANY_UNORDERED_NODE_TYPE: {
643             Node node = xpathResult.getSingleNodeValue();
644             return XmlUtil.toString(node, prettyPrint);
645         }
646         case XPathResult.ORDERED_NODE_ITERATOR_TYPE:
647         case XPathResult.UNORDERED_NODE_ITERATOR_TYPE: {
648             StringBuilder JavaDoc buf = new StringBuilder JavaDoc(512);
649             Node node = xpathResult.iterateNext();
650             while (node != null) {
651                 buf.append(XmlUtil.toString(node, prettyPrint));
652                 node = xpathResult.iterateNext();
653             }
654             return buf.toString();
655         }
656         case XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE:
657         case XPathResult.ORDERED_NODE_SNAPSHOT_TYPE: {
658             StringBuilder JavaDoc buf = new StringBuilder JavaDoc(512);
659             int len = xpathResult.getSnapshotLength();
660             for (int i = 0; i < len; i++) {
661                 Node node = xpathResult.snapshotItem(i);
662                 buf.append(XmlUtil.toString(node, prettyPrint));
663             }
664             return buf.toString();
665         }
666         default:
667             String JavaDoc msg = "Unknown xpathResult.type = "
668                         + xpathResult.getResultType();
669             throw new XPathException(XPathException.TYPE_ERR ,msg);
670         }
671     }
672
673     private static final Node[] NULL_NODE_ARRAY = new Node[0];
674
675     /**
676      * Convert an XPathResult to an array of Nodes.
677      *
678      */

679     public static Node[] convertToNodes(XPathResult xpathResult) {
680         switch (xpathResult.getResultType()) {
681         case XPathResult.NUMBER_TYPE:
682             return NULL_NODE_ARRAY;
683
684         case XPathResult.STRING_TYPE:
685             return NULL_NODE_ARRAY;
686
687         case XPathResult.BOOLEAN_TYPE:
688             return NULL_NODE_ARRAY;
689
690         case XPathResult.FIRST_ORDERED_NODE_TYPE:
691         case XPathResult.ANY_UNORDERED_NODE_TYPE: {
692             Node node = xpathResult.getSingleNodeValue();
693             return new Node[] { node };
694         }
695         case XPathResult.ORDERED_NODE_ITERATOR_TYPE:
696         case XPathResult.UNORDERED_NODE_ITERATOR_TYPE: {
697             List<Node> list = new ArrayList<Node>();
698             Node node = xpathResult.iterateNext();
699             while (node != null) {
700                 list.add(node);
701                 node = xpathResult.iterateNext();
702             }
703             return (Node[]) list.toArray(NULL_NODE_ARRAY);
704         }
705         case XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE:
706         case XPathResult.ORDERED_NODE_SNAPSHOT_TYPE: {
707             int len = xpathResult.getSnapshotLength();
708             Node[] nodes = new Node[len];
709             for (int i = 0; i < len; i++) {
710                 Node node = xpathResult.snapshotItem(i);
711                 nodes[i] = node;
712             }
713             return nodes;
714         }
715         default:
716             String JavaDoc msg = "Unknown xpathResult.type = "
717                         + xpathResult.getResultType();
718             throw new XPathException(XPathException.TYPE_ERR ,msg);
719         }
720     }
721
722     /**
723      * Convert a Node to a String.
724      *
725      */

726     public static String JavaDoc toString(Node node, boolean prettyPrint) {
727         if (node == null) {
728             return null;
729         }
730         try {
731             Document doc = node.getOwnerDocument();
732             OutputFormat format = null;
733             if (doc != null) {
734                 format = new OutputFormat(doc, null, prettyPrint);
735             } else {
736                 format = new OutputFormat("xml", null, prettyPrint);
737             }
738             if (prettyPrint) {
739                 format.setLineSeparator(LINE_SEP);
740             } else {
741                 format.setLineSeparator("");
742             }
743             StringWriter writer = new StringWriter(1000);
744             XMLSerializer serial = new XMLSerializer(writer, format);
745             serial.asDOMSerializer();
746             if (node instanceof Document) {
747                 serial.serialize((Document) node);
748             } else if (node instanceof Element) {
749                 format.setOmitXMLDeclaration(true);
750                 serial.serialize((Element) node);
751             } else if (node instanceof DocumentFragment) {
752                 format.setOmitXMLDeclaration(true);
753                 serial.serialize((DocumentFragment) node);
754             } else if (node instanceof Text) {
755                 Text text = (Text) node;
756                 return text.getData();
757             } else if (node instanceof Attr) {
758                 Attr attr = (Attr) node;
759                 String JavaDoc name = attr.getName();
760                 String JavaDoc value = attr.getValue();
761                 writer.write(name);
762                 writer.write("=\"");
763                 writer.write(value);
764                 writer.write("\"");
765                 if (prettyPrint) {
766                     writer.write(LINE_SEP);
767                 }
768             } else {
769                 writer.write("node class = " +node.getClass().getName());
770                 if (prettyPrint) {
771                     writer.write(LINE_SEP);
772                 } else {
773                     writer.write(' ');
774                 }
775                 writer.write("XmlUtil.toString: fix me: ");
776                 writer.write(node.toString());
777                 if (prettyPrint) {
778                     writer.write(LINE_SEP);
779                 }
780             }
781             return writer.toString();
782         } catch (Exception JavaDoc ex) {
783             // ignore
784
return null;
785         }
786     }
787
788     //////////////////////////////////////////////////////////////////////////
789
// validate
790
//////////////////////////////////////////////////////////////////////////
791

792     /**
793      * This can be extened to have a map from publicId/systemId
794      * to InputSource.
795      */

796     public static class Resolver implements EntityResolver {
797         private InputSource source;
798
799         protected Resolver() {
800             this((InputSource) null);
801         }
802         public Resolver(Document doc) {
803             this(XmlUtil.toString(doc, false));
804         }
805         public Resolver(String JavaDoc str) {
806             this(new InputSource(new StringReader(str)));
807         }
808         public Resolver(InputSource source) {
809             this.source = source;
810         }
811         public InputSource resolveEntity(String JavaDoc publicId,
812                                          String JavaDoc systemId)
813                 throws SAXException, IOException {
814 /*
815 System.err.println("XmlUtil.Resolver.resolveEntity:");
816 System.err.println(" publicId="+publicId);
817 System.err.println(" systemId="+systemId);
818 */

819             return source;
820         }
821     }
822
823     /**
824      * Get the Xerces version being used.
825      *
826      * @return
827      */

828     public static String JavaDoc getXercesVersion() {
829         try {
830             return org.apache.xerces.impl.Version.getVersion();
831         } catch (java.lang.NoClassDefFoundError JavaDoc ex) {
832             return "Xerces-J 2.2.0";
833         }
834     }
835
836     /**
837      * Get the number part of the Xerces Version string.
838      *
839      * @return
840      */

841     public static String JavaDoc getXercesVersionNumberString() {
842         String JavaDoc version = getXercesVersion();
843         int index = version.indexOf(' ');
844         return (index == -1)
845             ? "0.0.0" : version.substring(index+1);
846     }
847
848     protected static int[] versionNumbers = null;
849
850     /**
851      * Get the Xerces numbers as a three part array of ints where
852      * the first element is the major release number, the second is the
853      * minor release number, and the third is the patch number.
854      *
855      * @return
856      */

857     public static int[] getXercesVersionNumbers() {
858         if (versionNumbers == null) {
859             int[] verNums = new int[3];
860             String JavaDoc verNumStr = getXercesVersionNumberString();
861             int index = verNumStr.indexOf('.');
862             verNums[0] = Integer.parseInt(verNumStr.substring(0, index));
863
864             verNumStr = verNumStr.substring(index+1);
865             index = verNumStr.indexOf('.');
866             verNums[1] = Integer.parseInt(verNumStr.substring(0, index));
867
868             verNumStr = verNumStr.substring(index+1);
869             verNums[2] = Integer.parseInt(verNumStr);
870
871             versionNumbers = verNums;
872         }
873
874         return versionNumbers;
875
876     }
877
878     /**
879      * I could not get Xerces 2.2 to validate. So, I hard coded allowing
880      * Xerces 2.6 and above to validate and by setting the following
881      * System property one can test validating with earlier versions
882      * of Xerces.
883      */

884     private static final String JavaDoc ALWAYS_ATTEMPT_VALIDATION =
885                 "mondrian.xml.always.attempt.validation";
886     private static final boolean alwaysAttemptValidation;
887     static {
888         alwaysAttemptValidation =
889             Boolean.getBoolean(ALWAYS_ATTEMPT_VALIDATION);
890     }
891     /**
892      * I could not get validation to work with Xerces 2.2 so I put in
893      * this check. If you want to test on an earlier version of Xerces
894      * simply define the above property:
895      * "mondrian.xml.always.attempt.validation",
896      * to true.
897      *
898      * @return
899      */

900     public static boolean supportsValidation() {
901         if (alwaysAttemptValidation) {
902             return true;
903         } else {
904             int[] verNums = getXercesVersionNumbers();
905             return ((verNums[0] >= 3) ||
906                 ((verNums[0] == 2) && (verNums[1] >= 6)));
907         }
908     }
909     public static void validate(Document doc,
910                     String JavaDoc schemaLocationPropertyValue,
911                     EntityResolver resolver)
912             throws IOException ,
913                     SAXException,
914                     SAXNotRecognizedException {
915
916         OutputFormat format = new OutputFormat(doc, null, true);
917         StringWriter writer = new StringWriter(1000);
918         XMLSerializer serial = new XMLSerializer(writer, format);
919         serial.asDOMSerializer();
920         serial.serialize(doc);
921         String JavaDoc docString = writer.toString();
922
923         validate(docString, schemaLocationPropertyValue, resolver);
924     }
925
926 /*
927     public static void validate(String docStr,
928                     String schemaLocationPropertyValue,
929                     EntityResolver resolver)
930             throws IOException ,
931                     SAXException,
932                     SAXNotRecognizedException {
933
934         if (resolver == null) {
935             resolver = new Resolver();
936         }
937         DOMParser parser =
938             getParser(schemaLocationPropertyValue, resolver, true);
939
940         parser.parse(new InputSource(new StringReader(docStr)));
941         checkForParseError(parser);
942
943     }
944 */

945
946     public static void validate(String JavaDoc docStr,
947                     String JavaDoc schemaLocationPropertyValue,
948                     EntityResolver resolver)
949             throws IOException ,
950                     SAXException,
951                     SAXNotRecognizedException {
952         if (resolver == null) {
953             resolver = new Resolver();
954         }
955         DOMParser parser =
956             getParser(schemaLocationPropertyValue, resolver, true);
957
958         try {
959             parser.parse(new InputSource(new StringReader(docStr)));
960             checkForParseError(parser);
961         } catch (SAXParseException ex) {
962             checkForParseError(parser, ex);
963         }
964
965     }
966
967 /*
968     public static void validate(Document inDoc, Document xsdDoc)
969             throws IOException ,
970                     SAXException,
971                     SAXNotRecognizedException {
972         String xmlns = XmlUtil.getNamespaceAttributeValue(inDoc);
973 System.out.println("XmlUtil.validate: xmlns=" +xmlns);
974
975         OutputFormat format = new OutputFormat(inDoc, null, true);
976         StringWriter writer = new StringWriter(1000);
977         XMLSerializer serial = new XMLSerializer(writer, format);
978         serial.asDOMSerializer();
979         serial.serialize(inDoc);
980         String docString = writer.toString();
981 System.out.println("XmlUtil.validate: docString=" +docString);
982
983         String schemaStr = XmlUtil.toString(xsdDoc, false);
984 System.out.println("XmlUtil.validate: schemaStr=" +schemaStr);
985         Resolver resolver =
986             new Resolver(new InputSource(new StringReader(schemaStr)));
987
988         String schemaLocationPropertyValue = xmlns + " bar";
989 System.out.println("XmlUtil.validate: schemaLocationPropertyValue=" +schemaLocationPropertyValue);
990
991         schemaLocationPropertyValue = null;
992         DOMParser parser =
993             getParser(schemaLocationPropertyValue, resolver, true);
994         parser.parse(new InputSource(new StringReader(docString)));
995         checkForParseError(parser);
996     }
997 */

998
999     /**
1000     * This is used to get a Document's namespace attribute value.
1001     *
1002     */

1003    public static String JavaDoc getNamespaceAttributeValue(Document doc) {
1004        Element el = doc.getDocumentElement();
1005        String JavaDoc prefix = el.getPrefix();
1006        Attr attr = (prefix == null)
1007                    ? el.getAttributeNode(XMLNS)
1008                    : el.getAttributeNode(XMLNS + ':' + prefix);
1009        return (attr == null) ? null : attr.getValue();
1010    }
1011
1012    //////////////////////////////////////////////////////////////////////////
1013
// transform
1014
//////////////////////////////////////////////////////////////////////////
1015

1016    private static TransformerFactory tfactory = null;
1017    public static TransformerFactory getTransformerFactory()
1018            throws TransformerFactoryConfigurationError {
1019        if (tfactory == null) {
1020            tfactory = TransformerFactory.newInstance();
1021        }
1022        return tfactory;
1023    }
1024
1025    /**
1026     * Transform a Document and return the transformed Node.
1027     *
1028     */

1029    public static Node transform(Document inDoc,
1030        String JavaDoc xslFileName,
1031        String JavaDoc[][] namevalueParameters)
1032            throws ParserConfigurationException,
1033                SAXException,
1034                IOException,
1035                TransformerConfigurationException,
1036                TransformerException {
1037
1038        DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance();
1039        dfactory.setNamespaceAware(true);
1040
1041        DocumentBuilder docBuilder = dfactory.newDocumentBuilder();
1042        Node xslDOM = docBuilder.parse(new InputSource(xslFileName));
1043
1044        TransformerFactory tfactory = getTransformerFactory();
1045        Templates stylesheet = tfactory.newTemplates(
1046                            new DOMSource JavaDoc(xslDOM, xslFileName));
1047        Transformer transformer = stylesheet.newTransformer();
1048        if (namevalueParameters != null) {
1049            for (int i = 0; i < namevalueParameters.length; i++) {
1050                String JavaDoc name = namevalueParameters[i][0];
1051                String JavaDoc value = namevalueParameters[i][1];
1052
1053                transformer.setParameter(name, value);
1054            }
1055        }
1056        DOMResult JavaDoc domResult = new DOMResult JavaDoc();
1057        transformer.transform(new DOMSource JavaDoc(inDoc, null), domResult);
1058
1059        return domResult.getNode();
1060    }
1061    public static Node transform(Document inDoc,
1062        String JavaDoc xslFileName)
1063            throws ParserConfigurationException,
1064                SAXException,
1065                IOException,
1066                TransformerConfigurationException,
1067                TransformerException {
1068        return transform(inDoc, xslFileName, null);
1069    }
1070
1071    /**
1072     * Transform a Document and return the transformed Node.
1073     *
1074     */

1075    public static Node transform(Document inDoc,
1076        Reader xslReader,
1077        String JavaDoc[][] namevalueParameters)
1078            throws ParserConfigurationException,
1079                SAXException,
1080                IOException,
1081                TransformerConfigurationException,
1082                TransformerException {
1083
1084        DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance();
1085        dfactory.setNamespaceAware(true);
1086
1087        DocumentBuilder docBuilder = dfactory.newDocumentBuilder();
1088        Node xslDOM = docBuilder.parse(new InputSource(xslReader));
1089
1090        TransformerFactory tfactory = getTransformerFactory();
1091        Templates stylesheet = tfactory.newTemplates(new DOMSource JavaDoc(xslDOM));
1092        Transformer transformer = stylesheet.newTransformer();
1093        if (namevalueParameters != null) {
1094            for (int i = 0; i < namevalueParameters.length; i++) {
1095                String JavaDoc name = namevalueParameters[i][0];
1096                String JavaDoc value = namevalueParameters[i][1];
1097
1098                transformer.setParameter(name, value);
1099            }
1100        }
1101
1102        DOMResult JavaDoc domResult = new DOMResult JavaDoc();
1103        transformer.transform(new DOMSource JavaDoc(inDoc, null), domResult);
1104
1105        return domResult.getNode();
1106    }
1107    public static Node transform(Document inDoc,
1108        Reader xslReader)
1109            throws ParserConfigurationException,
1110                SAXException,
1111                IOException,
1112                TransformerConfigurationException,
1113                TransformerException {
1114        return transform(inDoc, xslReader, null);
1115    }
1116
1117
1118    private XmlUtil() {}
1119}
1120
1121// End XmlUtil.java
1122
Popular Tags