KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > opencms > xml > CmsXmlUtils


1 /*
2  * File : $Source: /usr/local/cvs/opencms/src/org/opencms/xml/CmsXmlUtils.java,v $
3  * Date : $Date: 2006/03/27 14:52:20 $
4  * Version: $Revision: 1.21 $
5  *
6  * This library is part of OpenCms -
7  * the Open Source Content Mananagement System
8  *
9  * Copyright (c) 2005 Alkacon Software GmbH (http://www.alkacon.com)
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2.1 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  * Lesser General Public License for more details.
20  *
21  * For further information about Alkacon Software GmbH, please see the
22  * company website: http://www.alkacon.com
23  *
24  * For further information about OpenCms, please see the
25  * project website: http://www.opencms.org
26  *
27  * You should have received a copy of the GNU Lesser General Public
28  * License along with this library; if not, write to the Free Software
29  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30  */

31
32 package org.opencms.xml;
33
34 import org.opencms.file.CmsResource;
35 import org.opencms.main.CmsLog;
36 import org.opencms.util.CmsStringUtil;
37
38 import java.io.ByteArrayInputStream JavaDoc;
39 import java.io.ByteArrayOutputStream JavaDoc;
40 import java.io.IOException JavaDoc;
41 import java.io.OutputStream JavaDoc;
42 import java.io.StringReader JavaDoc;
43 import java.io.StringWriter JavaDoc;
44 import java.io.UnsupportedEncodingException JavaDoc;
45 import java.util.List JavaDoc;
46
47 import org.apache.commons.logging.Log;
48
49 import org.dom4j.Document;
50 import org.dom4j.DocumentException;
51 import org.dom4j.Node;
52 import org.dom4j.io.OutputFormat;
53 import org.dom4j.io.SAXReader;
54 import org.dom4j.io.XMLWriter;
55 import org.xml.sax.EntityResolver JavaDoc;
56 import org.xml.sax.InputSource JavaDoc;
57 import org.xml.sax.SAXException JavaDoc;
58 import org.xml.sax.SAXNotRecognizedException JavaDoc;
59 import org.xml.sax.SAXNotSupportedException JavaDoc;
60 import org.xml.sax.XMLReader JavaDoc;
61 import org.xml.sax.helpers.XMLReaderFactory JavaDoc;
62
63 /**
64  * Provides some basic XML handling utilities.<p>
65  *
66  * @author Alexander Kandzior
67  *
68  * @version $Revision: 1.21 $
69  *
70  * @since 6.0.0
71  */

72 public final class CmsXmlUtils {
73
74     /** The log object for this class. */
75     private static final Log LOG = CmsLog.getLog(CmsXmlUtils.class);
76
77     /**
78      * Prevents instances of this class from being generated.<p>
79      */

80     private CmsXmlUtils() {
81
82         // noop
83
}
84
85     /**
86      * Concats two Xpath expressions, ensuring that exactly one slash "/" is between them.<p>
87      *
88      * Use this method if it's uncertain if the given arguments are starting or ending with
89      * a slash "/".<p>
90      *
91      * Examples:<br>
92      * <code>"title", "subtitle"</code> becomes <code>title/subtitle</code><br>
93      * <code>"title[1]/", "subtitle"</code> becomes <code>title[1]/subtitle</code><br>
94      * <code>"title[1]/", "/subtitle[1]"</code> becomes <code>title[1]/subtitle[1]</code><p>
95      *
96      * @param prefix the prefix Xpath
97      * @param suffix the suffix Xpath
98      *
99      * @return the concated Xpath build from prefix and suffix
100      */

101     public static String JavaDoc concatXpath(String JavaDoc prefix, String JavaDoc suffix) {
102
103         if (suffix == null) {
104             // ensure suffix is not null
105
suffix = "";
106         } else {
107             if ((suffix.length() > 0) && (suffix.charAt(0) == '/')) {
108                 // remove leading '/' form suffix
109
suffix = suffix.substring(1);
110             }
111         }
112         if (prefix != null) {
113             StringBuffer JavaDoc result = new StringBuffer JavaDoc(32);
114             result.append(prefix);
115             if (!CmsResource.isFolder(prefix)) {
116                 result.append('/');
117             }
118             result.append(suffix);
119             return result.toString();
120         }
121         return suffix;
122     }
123
124     /**
125      * Translates a simple lookup path to the simplified Xpath format used for
126      * the internal bookmarks.<p>
127      *
128      * Examples:<br>
129      * <code>title</code> becomes <code>title[1]</code><br>
130      * <code>title[1]</code> is left untouched<br>
131      * <code>title/subtitle</code> becomes <code>title[1]/subtitle[1]</code><br>
132      * <code>title/subtitle[1]</code> becomes <code>title[1]/subtitle[1]</code><p>
133      *
134      * Note: If the name already has the format <code>title[1]</code> then provided index parameter
135      * is ignored.<p>
136      *
137      * @param path the path to get the simplified Xpath for
138      * @param index the index to append (if required)
139      *
140      * @return the simplified Xpath for the given name
141      */

142     public static String JavaDoc createXpath(String JavaDoc path, int index) {
143
144         if (path.indexOf('/') > -1) {
145             // this is a complex path over more then 1 node
146
StringBuffer JavaDoc result = new StringBuffer JavaDoc(path.length() + 32);
147
148             // split the path into subelements
149
List JavaDoc elements = CmsStringUtil.splitAsList(path, '/');
150             int end = elements.size() - 1;
151             for (int i = 0; i <= end; i++) {
152                 // append [i] to path element if required
153
result.append(createXpathElementCheck((String JavaDoc)elements.get(i), (i == end) ? index : 1));
154                 if (i < end) {
155                     // append path delimiter if not final path element
156
result.append('/');
157                 }
158             }
159             return result.toString();
160         }
161
162         // this path has only 1 node, append [index] if required
163
return createXpathElementCheck(path, index);
164     }
165
166     /**
167      * Appends the provided index parameter in square brackets to the given name,
168      * like <code>path[index]</code>.<p>
169      *
170      * This method is used if it's clear that some path does not have
171      * a square bracket already appended.<p>
172      *
173      * @param path the path append the index to
174      * @param index the index to append
175      *
176      * @return the simplified Xpath for the given name
177      */

178     public static String JavaDoc createXpathElement(String JavaDoc path, int index) {
179
180         StringBuffer JavaDoc result = new StringBuffer JavaDoc(path.length() + 5);
181         result.append(path);
182         result.append('[');
183         result.append(index);
184         result.append(']');
185         return result.toString();
186     }
187
188     /**
189      * Ensures that a provided simplified Xpath has the format <code>title[1]</code>.<p>
190      *
191      * This method is used if it's uncertain if some path does have
192      * a square bracket already appended or not.<p>
193      *
194      * Note: If the name already has the format <code>title[1]</code>, then provided index parameter
195      * is ignored.<p>
196      *
197      * @param path the path to get the simplified Xpath for
198      * @param index the index to append (if required)
199      *
200      * @return the simplified Xpath for the given name
201      */

202     public static String JavaDoc createXpathElementCheck(String JavaDoc path, int index) {
203
204         if (path.charAt(path.length() - 1) == ']') {
205             // path is already in the form "title[1]"
206
// ignore provided index and return the path "as is"
207
return path;
208         }
209
210         // append index in square brackets
211
return createXpathElement(path, index);
212     }
213
214     /**
215      * Returns the first Xpath element from the provided path,
216      * without the index value.<p>
217      *
218      * Examples:<br>
219      * <code>title</code> is left untouched<br>
220      * <code>title[1]</code> becomes <code>title</code><br>
221      * <code>title/subtitle</code> becomes <code>title</code><br>
222      * <code>title[1]/subtitle[1]</code> becomes <code>title</code><p>
223      *
224      * @param path the path to get the first Xpath element from
225      *
226      * @return the first Xpath element from the provided path
227      */

228     public static String JavaDoc getFirstXpathElement(String JavaDoc path) {
229
230         int pos = path.indexOf('/');
231         if (pos >= 0) {
232             path = path.substring(0, pos);
233         }
234
235         return CmsXmlUtils.removeXpathIndex(path);
236     }
237
238     /**
239      * Returns the last Xpath element from the provided path,
240      * without the index value.<p>
241      *
242      * Examples:<br>
243      * <code>title</code> is left untouched<br>
244      * <code>title[1]</code> becomes <code>title</code><br>
245      * <code>title/subtitle</code> becomes <code>subtitle</code><br>
246      * <code>title[1]/subtitle[1]</code> becomes <code>subtitle</code><p>
247      *
248      * @param path the path to get the last Xpath element from
249      *
250      * @return the last Xpath element from the provided path
251      */

252     public static String JavaDoc getLastXpathElement(String JavaDoc path) {
253
254         int pos = path.lastIndexOf('/');
255         if (pos >= 0) {
256             path = path.substring(pos + 1);
257         }
258
259         return CmsXmlUtils.removeXpathIndex(path);
260     }
261
262     /**
263      * Returns the last Xpath index from the given path.<p>
264      *
265      * Examples:<br>
266      * <code>title</code> returns them empty String<p>
267      * <code>title[1]</code> returns <code>[1]</code><p>
268      * <code>title/subtitle</code> returns them empty String<p>
269      * <code>title[1]/subtitle[1]</code> returns <code>[1]</code><p>
270      *
271      * @param path the path to remove the Xpath index from
272      *
273      * @return the path with the last Xpath index removed
274      */

275     public static String JavaDoc getXpathIndex(String JavaDoc path) {
276
277         int pos1 = path.lastIndexOf('/');
278         int pos2 = path.lastIndexOf('[');
279         if ((pos2 < 0) || (pos1 > pos2)) {
280             return "";
281         }
282
283         return path.substring(pos2);
284     }
285
286     /**
287      * Returns <code>true</code> if the given path is a Xpath with
288      * at last 2 elements.<p>
289      *
290      * Examples:<br>
291      * <code>title</code> returns <code>false</code><br>
292      * <code>title[1]</code> returns <code>false</code><br>
293      * <code>title/subtitle</code> returns <code>true</code><br>
294      * <code>title[1]/subtitle[1]</code> returns <code>true</code><p>
295      *
296      * @param path the path to check
297      * @return true if the given path is a Xpath with at last 2 elements
298      */

299     public static boolean isDeepXpath(String JavaDoc path) {
300
301         return path.indexOf('/') > 0;
302     }
303
304     /**
305      * Marshals (writes) an XML document into an output stream using XML pretty-print formatting.<p>
306      *
307      * @param document the XML document to marshal
308      * @param out the output stream to write to
309      * @param encoding the encoding to use
310      * @return the output stream with the xml content
311      * @throws CmsXmlException if something goes wrong
312      */

313     public static OutputStream JavaDoc marshal(Document document, OutputStream JavaDoc out, String JavaDoc encoding) throws CmsXmlException {
314
315         try {
316             OutputFormat format = OutputFormat.createPrettyPrint();
317             format.setEncoding(encoding);
318
319             XMLWriter writer = new XMLWriter(out, format);
320             writer.setEscapeText(false);
321
322             writer.write(document);
323             writer.close();
324
325         } catch (Exception JavaDoc e) {
326             throw new CmsXmlException(Messages.get().container(Messages.ERR_MARSHALLING_XML_DOC_0), e);
327         }
328
329         return out;
330     }
331
332     /**
333      * Marshals (writes) an XML document to a String using XML pretty-print formatting.<p>
334      *
335      * @param document the XML document to marshal
336      * @param encoding the encoding to use
337      * @return the marshalled XML document
338      * @throws CmsXmlException if something goes wrong
339      */

340     public static String JavaDoc marshal(Document document, String JavaDoc encoding) throws CmsXmlException {
341
342         ByteArrayOutputStream JavaDoc out = new ByteArrayOutputStream JavaDoc();
343         marshal(document, out, encoding);
344         try {
345             return out.toString(encoding);
346         } catch (UnsupportedEncodingException JavaDoc e) {
347             throw new CmsXmlException(Messages.get().container(Messages.ERR_MARSHALLING_XML_DOC_TO_STRING_0), e);
348         }
349     }
350
351     /**
352      * Marshals (writes) an XML node into an output stream using XML pretty-print formatting.<p>
353      *
354      * @param node the XML node to marshal
355      * @param encoding the encoding to use
356      *
357      * @return the string with the xml content
358      *
359      * @throws CmsXmlException if something goes wrong
360      */

361     public static String JavaDoc marshal(Node node, String JavaDoc encoding) throws CmsXmlException {
362
363         ByteArrayOutputStream JavaDoc out = new ByteArrayOutputStream JavaDoc();
364         try {
365             OutputFormat format = OutputFormat.createPrettyPrint();
366             format.setEncoding(encoding);
367             format.setSuppressDeclaration(true);
368
369             XMLWriter writer = new XMLWriter(out, format);
370             writer.setEscapeText(false);
371
372             writer.write(node);
373             writer.close();
374         } catch (Exception JavaDoc e) {
375             throw new CmsXmlException(Messages.get().container(Messages.ERR_MARSHALLING_XML_DOC_0), e);
376         }
377         return new String JavaDoc(out.toByteArray());
378     }
379
380     /**
381      * Removes the first Xpath element from the path.<p>
382      *
383      * If the provided path does not contain a "/" character,
384      * it is returned unchanged.<p>
385      *
386      * <p>Examples:<br>
387      * <code>title</code> is left untouched<br>
388      * <code>title[1]</code> is left untouched<br>
389      * <code>title/subtitle</code> becomes <code>subtitle</code><br>
390      * <code>title[1]/subtitle[1]</code> becomes <code>subtitle[1]</code><p>
391      *
392      * @param path the Xpath to remove the first element from
393      *
394      * @return the path with the first element removed
395      */

396     public static String JavaDoc removeFirstXpathElement(String JavaDoc path) {
397
398         int pos = path.indexOf('/');
399         if (pos < 0) {
400             return path;
401         }
402
403         return path.substring(pos + 1);
404     }
405
406     /**
407      * Removes the last Xpath element from the path.<p>
408      *
409      * If the provided path does not contain a "/" character,
410      * it is returned unchanged.<p>
411      *
412      * <p>Examples:<br>
413      * <code>title</code> is left untouched<br>
414      * <code>title[1]</code> is left untouched<br>
415      * <code>title/subtitle</code> becomes <code>title</code><br>
416      * <code>title[1]/subtitle[1]</code> becomes <code>title[1]</code><p>
417      *
418      * @param path the Xpath to remove the last element from
419      *
420      * @return the path with the last element removed
421      */

422     public static String JavaDoc removeLastXpathElement(String JavaDoc path) {
423
424         int pos = path.lastIndexOf('/');
425         if (pos < 0) {
426             return path;
427         }
428
429         return path.substring(0, pos);
430     }
431
432     /**
433      * Removes the last complex Xpath element from the path.<p>
434      *
435      * The same as {@link #removeLastXpathElement(String)} both it works with more complex xpaths.
436      *
437      * <p>Example:<br>
438      * <code>system/backup[@date='23/10/2003']/resource[path='/a/b/c']</code> becomes <code>system/backup[@date='23/10/2003']</code><p>
439      *
440      * @param path the Xpath to remove the last element from
441      *
442      * @return the path with the last element removed
443      */

444     public static String JavaDoc removeLastComplexXpathElement(String JavaDoc path) {
445
446         int pos = path.lastIndexOf('/');
447         if (pos < 0) {
448             return path;
449         }
450         // count ' chars
451
int p = pos;
452         int count = -1;
453         while (p > 0) {
454             count++;
455             p = path.indexOf("\'", p + 1);
456         }
457         String JavaDoc parentPath = path.substring(0, pos);
458         if (count % 2 == 0) {
459             // if substring is complete
460
return parentPath;
461         }
462         // if not complete
463
p = parentPath.lastIndexOf("'");
464         if (p >= 0) {
465             // complete it if possible
466
return removeLastComplexXpathElement(parentPath.substring(0, p));
467         }
468         return parentPath;
469     }
470
471     /**
472      * Removes all Xpath index information from the given input path.<p>
473      *
474      * Examples:<br>
475      * <code>title</code> is left untouched<br>
476      * <code>title[1]</code> becomes <code>title</code><br>
477      * <code>title/subtitle</code> is left untouched<br>
478      * <code>title/subtitle[1]</code> becomes <code>title/subtitle</code><p>
479      *
480      * @param path the path to remove the Xpath index information from
481      *
482      * @return the simplified Xpath for the given name
483      */

484     public static String JavaDoc removeXpath(String JavaDoc path) {
485
486         if (path.indexOf('/') > -1) {
487             // this is a complex path over more then 1 node
488
StringBuffer JavaDoc result = new StringBuffer JavaDoc(path.length() + 32);
489
490             // split the path into subelements
491
List JavaDoc elements = CmsStringUtil.splitAsList(path, '/');
492             int end = elements.size() - 1;
493             for (int i = 0; i <= end; i++) {
494                 // append [i] to path element if required
495
result.append(removeXpathIndex((String JavaDoc)elements.get(i)));
496                 if (i < end) {
497                     // append path delimiter if not final path element
498
result.append('/');
499                 }
500             }
501             return result.toString();
502         }
503
504         // this path has only 1 node, remove last index if required
505
return removeXpathIndex(path);
506     }
507
508     /**
509      * Removes the last Xpath index from the given path.<p>
510      *
511      * Examples:<br>
512      * <code>title</code> is left untouched<br>
513      * <code>title[1]</code> becomes <code>title</code><br>
514      * <code>title/subtitle</code> is left untouched<br>
515      * <code>title[1]/subtitle[1]</code> becomes <code>title[1]/subtitle</code><p>
516      *
517      * @param path the path to remove the Xpath index from
518      *
519      * @return the path with the last Xpath index removed
520      */

521     public static String JavaDoc removeXpathIndex(String JavaDoc path) {
522
523         int pos1 = path.lastIndexOf('/');
524         int pos2 = path.lastIndexOf('[');
525         if ((pos2 < 0) || (pos1 > pos2)) {
526             return path;
527         }
528
529         return path.substring(0, pos2);
530     }
531
532     /**
533      * Simplifies an Xpath by removing a leading and a trailing slash from the given path.<p>
534      *
535      * Examples:<br>
536      * <code>title/</code> becomes <code>title</code><br>
537      * <code>/title[1]/</code> becomes <code>title[1]</code><br>
538      * <code>/title/subtitle/</code> becomes <code>title/subtitle</code><br>
539      * <code>/title/subtitle[1]/</code> becomes <code>title/subtitle[1]</code><p>
540      *
541      * @param path the path to process
542      * @return the input with a leading and a trailing slash removed
543      */

544     public static String JavaDoc simplifyXpath(String JavaDoc path) {
545
546         StringBuffer JavaDoc result = new StringBuffer JavaDoc(path);
547         if (result.charAt(0) == '/') {
548             result.deleteCharAt(0);
549         }
550         int pos = result.length() - 1;
551         if (result.charAt(pos) == '/') {
552             result.deleteCharAt(pos);
553         }
554         return result.toString();
555     }
556
557     /**
558      * Helper to unmarshal (read) xml contents from a byte array into a document.<p>
559      *
560      * Using this method ensures that the OpenCms XML entitiy resolver is used.<p>
561      *
562      * @param xmlData the XML data in a byte array
563      * @param resolver the XML entitiy resolver to use
564      * @return the base object initialized with the unmarshalled XML document
565      * @throws CmsXmlException if something goes wrong
566      * @see CmsXmlUtils#unmarshalHelper(InputSource, EntityResolver)
567      */

568     public static Document unmarshalHelper(byte[] xmlData, EntityResolver JavaDoc resolver) throws CmsXmlException {
569
570         return CmsXmlUtils.unmarshalHelper(new InputSource JavaDoc(new ByteArrayInputStream JavaDoc(xmlData)), resolver);
571     }
572
573     /**
574      * Helper to unmarshal (read) xml contents from an input source into a document.<p>
575      *
576      * Using this method ensures that the OpenCms XML entitiy resolver is used.<p>
577      *
578      * Important: The encoding provided will NOT be used uring unmarshalling,
579      * the XML parser will do this on the base of the information in the source String.
580      * The encoding is used for initializing the created instance of the document,
581      * which means it will be used when marshalling the document again later.<p>
582      *
583      * @param source the XML input source to use
584      * @param resolver the XML entitiy resolver to use
585      * @return the unmarshalled XML document
586      * @throws CmsXmlException if something goes wrong
587      */

588     public static Document unmarshalHelper(InputSource JavaDoc source, EntityResolver JavaDoc resolver) throws CmsXmlException {
589
590         try {
591             SAXReader reader = new SAXReader();
592             if (resolver != null) {
593                 reader.setEntityResolver(resolver);
594             }
595             reader.setMergeAdjacentText(true);
596             reader.setStripWhitespaceText(true);
597             return reader.read(source);
598         } catch (DocumentException e) {
599             throw new CmsXmlException(Messages.get().container(Messages.ERR_UNMARSHALLING_XML_DOC_0), e);
600         }
601     }
602
603     /**
604      * Helper to unmarshal (read) xml contents from a String into a document.<p>
605      *
606      * Using this method ensures that the OpenCms XML entitiy resolver is used.<p>
607      *
608      * @param xmlData the xml data in a String
609      * @param resolver the XML entitiy resolver to use
610      * @return the base object initialized with the unmarshalled XML document
611      * @throws CmsXmlException if something goes wrong
612      * @see CmsXmlUtils#unmarshalHelper(InputSource, EntityResolver)
613      */

614     public static Document unmarshalHelper(String JavaDoc xmlData, EntityResolver JavaDoc resolver) throws CmsXmlException {
615
616         return CmsXmlUtils.unmarshalHelper(new InputSource JavaDoc(new StringReader JavaDoc(xmlData)), resolver);
617     }
618
619     /**
620      * Validates the structure of a XML document contained in a byte array
621      * with the DTD or XML schema used by the document.<p>
622      *
623      * @param xmlData a byte array containing a XML document that should be validated
624      * @param resolver the XML entitiy resolver to use
625      *
626      * @throws CmsXmlException if the validation fails
627      */

628     public static void validateXmlStructure(byte[] xmlData, EntityResolver JavaDoc resolver) throws CmsXmlException {
629
630         XMLReader JavaDoc reader;
631         try {
632             reader = XMLReaderFactory.createXMLReader("org.apache.xerces.parsers.SAXParser");
633         } catch (SAXException JavaDoc e) {
634             // xerces parser not available - no schema validation possible
635
if (LOG.isWarnEnabled()) {
636                 LOG.warn(Messages.get().getBundle().key(Messages.LOG_VALIDATION_INIT_XERXES_SAX_READER_FAILED_0), e);
637             }
638             // no validation of the content is possible
639
return;
640         }
641         // turn on validation
642
try {
643             reader.setFeature("http://xml.org/sax/features/validation", true);
644             // turn on schema validation
645
reader.setFeature("http://apache.org/xml/features/validation/schema", true);
646             // configure namespace support
647
reader.setFeature("http://xml.org/sax/features/namespaces", true);
648             reader.setFeature("http://xml.org/sax/features/namespace-prefixes", false);
649         } catch (SAXNotRecognizedException JavaDoc e) {
650             // should not happen as Xerces 2 support this feature
651
if (LOG.isWarnEnabled()) {
652                 LOG.warn(Messages.get().getBundle().key(Messages.LOG_SAX_READER_FEATURE_NOT_RECOGNIZED_0), e);
653             }
654             // no validation of the content is possible
655
return;
656         } catch (SAXNotSupportedException JavaDoc e) {
657             // should not happen as Xerces 2 support this feature
658
if (LOG.isWarnEnabled()) {
659                 LOG.warn(Messages.get().getBundle().key(Messages.LOG_SAX_READER_FEATURE_NOT_SUPPORTED_0), e);
660             }
661             // no validation of the content is possible
662
return;
663         }
664
665         // add an error handler which turns any errors into XML
666
CmsXmlValidationErrorHandler errorHandler = new CmsXmlValidationErrorHandler();
667         reader.setErrorHandler(errorHandler);
668
669         if (resolver != null) {
670             // set the resolver for the "opencms://" URIs
671
reader.setEntityResolver(resolver);
672         }
673
674         try {
675             reader.parse(new InputSource JavaDoc(new ByteArrayInputStream JavaDoc(xmlData)));
676         } catch (IOException JavaDoc e) {
677             // should not happen since we read form a byte array
678
if (LOG.isErrorEnabled()) {
679                 LOG.error(Messages.get().getBundle().key(Messages.LOG_READ_XML_FROM_BYTE_ARR_FAILED_0), e);
680             }
681             return;
682         } catch (SAXException JavaDoc e) {
683             // should not happen since all errors are handled in the XML error handler
684
if (LOG.isErrorEnabled()) {
685                 LOG.error(Messages.get().getBundle().key(Messages.LOG_PARSE_SAX_EXC_0), e);
686             }
687             return;
688         }
689
690         if (errorHandler.getErrors().elements().size() > 0) {
691             // there was at last one validation error, so throw an exception
692
StringWriter JavaDoc out = new StringWriter JavaDoc(256);
693             OutputFormat format = OutputFormat.createPrettyPrint();
694             XMLWriter writer = new XMLWriter(out, format);
695             try {
696                 writer.write(errorHandler.getErrors());
697                 writer.write(errorHandler.getWarnings());
698                 writer.close();
699             } catch (IOException JavaDoc e) {
700                 // should not happen since we write to a StringWriter
701
if (LOG.isErrorEnabled()) {
702                     LOG.error(Messages.get().getBundle().key(Messages.LOG_STRINGWRITER_IO_EXC_0), e);
703                 }
704             }
705             // generate String from XML for display of document in error message
706
throw new CmsXmlException(Messages.get().container(Messages.ERR_XML_VALIDATION_1, out.toString()));
707         }
708     }
709
710     /**
711      * Validates the structure of a XML document with the DTD or XML schema used
712      * by the document.<p>
713      *
714      * @param document a XML document that should be validated
715      * @param encoding the encoding to use when marshalling the XML document (required)
716      * @param resolver the XML entitiy resolver to use
717      *
718      * @throws CmsXmlException if the validation fails
719      */

720     public static void validateXmlStructure(Document document, String JavaDoc encoding, EntityResolver JavaDoc resolver)
721     throws CmsXmlException {
722
723         // generate bytes from document
724
byte[] xmlData = ((ByteArrayOutputStream JavaDoc)marshal(document, new ByteArrayOutputStream JavaDoc(512), encoding)).toByteArray();
725         validateXmlStructure(xmlData, resolver);
726     }
727 }
Popular Tags