xref: /aoo41x/main/qadevOOo/runner/util/XMLTools.java (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 package util;
29 
30 import java.io.PrintWriter ;
31 import java.util.Vector ;
32 import java.util.Hashtable ;
33 import java.util.Enumeration ;
34 import java.util.HashSet ;
35 
36 // access the implementations via names
37 import com.sun.star.uno.XInterface;
38 import com.sun.star.io.XOutputStream;
39 import com.sun.star.io.XInputStream;
40 import com.sun.star.io.XActiveDataSource;
41 import com.sun.star.ucb.XSimpleFileAccess;
42 import com.sun.star.lang.XMultiServiceFactory;
43 import com.sun.star.xml.sax.XDocumentHandler;
44 import com.sun.star.uno.Any;
45 import com.sun.star.uno.Type;
46 import com.sun.star.uno.UnoRuntime;
47 import com.sun.star.beans.PropertyValue;
48 import com.sun.star.xml.sax.XLocator;
49 import com.sun.star.xml.sax.XAttributeList;
50 import com.sun.star.xml.sax.XParser ;
51 import com.sun.star.xml.sax.InputSource ;
52 import com.sun.star.lang.XComponent;
53 import com.sun.star.document.XExporter;
54 import com.sun.star.document.XImporter;
55 import com.sun.star.document.XFilter;
56 
57 
58 public class XMLTools {
59 
60     /**
61      * The implementation of <code>com.sun.star.xml.sax.XAttributeList</code>
62      * where attributes and their values can be added.
63      */
64     public static class AttributeList implements XAttributeList {
65         private static class Attribute {
66             public String Name ;
67             public String Type ;
68             public String Value ;
69         }
70         private Hashtable attrByName = new Hashtable() ;
71         private Vector attributes = new Vector() ;
72         private PrintWriter log = null ;
73 
74         /**
75          * Creates a class instance.
76          */
77         public AttributeList() {}
78 
79         /**
80          * Constructs a list which will report to <code>log</code>
81          * specified about each <code>XDocumentHandler</code> method
82          * call.
83          */
84         public AttributeList(PrintWriter log) {
85             this.log = log ;
86         }
87 
88         public AttributeList(XAttributeList list) {
89             if (list == null) return ;
90             for (short i = 0; i < list.getLength(); i++) {
91                 add(list.getNameByIndex(i), list.getTypeByIndex(i),
92                     list.getValueByIndex(i)) ;
93             }
94         }
95 
96         /**
97          * Adds an attribute with type and value specified.
98          * @param name The attribute name.
99          * @param type Value type (usually 'CDATA' used).
100          * @param value Attribute value.
101          */
102         public void add(String name, String type, String value) {
103             Attribute attr = new Attribute() ;
104             attr.Name = name ;
105             attr.Type = type ;
106             attr.Value = value ;
107             attributes.add(attr) ;
108             attrByName.put(attr.Name, attr) ;
109         }
110 
111         /**
112          * Adds an attribute with value specified. As a type of
113          * value 'CDATA' string specified.
114          * @param name The attribute name.
115          * @param value Attribute value.
116          */
117         public void add(String name, String value) {
118             add(name, "CDATA", value) ;
119         }
120 
121         /**
122          * Clears all attributes added before.
123          */
124         public void clear() {
125             attrByName.clear() ;
126             attributes.clear() ;
127         }
128 
129         /***************************************
130         * XAttributeList methods
131         ****************************************/
132 
133         public short getLength() {
134             if (log != null)
135                 log.println("getLength() called -> " + attributes.size()) ;
136             return (short) attributes.size() ;
137         }
138 
139         public String getNameByIndex(short idx) {
140             String name = ((Attribute) attributes.get(idx)).Name ;
141             if (log != null)
142                 log.println("getNameByIndex(" + idx + ") called -> '" +
143                 name + "'") ;
144             return name ;
145         }
146 
147         public String getTypeByIndex(short idx) {
148             String type = ((Attribute) attributes.get(idx)).Type  ;
149             if (log != null)
150                 log.println("getTypeByIndex(" + idx + ") called -> '" +
151                     type + "'") ;
152             return type;
153         }
154 
155         public String getTypeByName(String name) {
156             String type = ((Attribute) attrByName.get(name)).Type ;
157             if (log != null)
158                 log.println("getTypeByName('" + name + "') called -> '" +
159                     type + "'") ;
160             return type;
161         }
162         public String getValueByIndex(short idx) {
163             String value = ((Attribute) attributes.get(idx)).Value ;
164             if (log != null)
165                 log.println("getValueByIndex(" + idx + ") called -> '" +
166                     value + "'") ;
167             return  value;
168         }
169 
170         public String getValueByName(String name) {
171             String value = ((Attribute) attrByName.get(name)).Value ;
172             if (log != null)
173                 log.println("getValueByName('" + name + "') called -> '" +
174                     value + "'") ;
175             return value;
176         }
177     }
178 
179     /**
180     * This class writes all XML data handled into a stream specified
181     * in the constructor.
182     */
183     public static class XMLWriter implements XDocumentHandler {
184         private PrintWriter _log = null ;
185         private String align = "" ;
186 
187         /**
188         * Creates a SAX handler which writes all XML data
189         * handled into a <code>log</code> stream specified.
190         */
191         public XMLWriter(PrintWriter log) {
192             _log = log ;
193         }
194 
195         /**
196         * Creates a SAX handler which does nothing.
197         */
198         public XMLWriter() {
199         }
200 
201         public void processingInstruction(String appl, String data) {
202             if (_log == null) return ;
203             _log.println(align + "<?" + appl + " " + data + "?>") ;
204         }
205         public void startDocument() {
206             if (_log == null) return ;
207             _log.println("START DOCUMENT:") ;
208         }
209         public void endDocument() {
210             if (_log == null) return ;
211             _log.println("END DOCUMENT:") ;
212         }
213         public void setDocumentLocator(XLocator loc) {
214             if (_log == null) return ;
215             _log.println("DOCUMENT LOCATOR: ('" + loc.getPublicId() +
216                 "','" + loc.getSystemId() + "')") ;
217         }
218         public void startElement(String name, XAttributeList attr) {
219             if (_log == null) return ;
220             _log.print(align + "<" + name + " ") ;
221             if (attr != null) {
222                 short attrLen = attr.getLength() ;
223                 for (short i = 0; i < attrLen; i++) {
224                     if (i != 0) _log.print(align + "       ") ;
225                     _log.print(attr.getNameByIndex(i) + "[" +
226                         attr.getTypeByIndex(i) + "]=\"" +
227                         attr.getValueByIndex(i) + "\"") ;
228                     if (i+1 != attrLen) {
229                         _log.println() ;
230                     }
231                 }
232             }
233             _log.println(">") ;
234 
235             align += "   " ;
236         }
237 
238         public void endElement(String name) {
239             if (_log == null) return ;
240             align = align.substring(3) ;
241             _log.println(align + "</" + name + ">") ;
242         }
243 
244         public void characters(String chars) {
245             if (_log == null) return ;
246             _log.println(align + chars) ;
247         }
248         public void ignorableWhitespace(String sp) {
249             if (_log == null) return ;
250             _log.println(sp) ;
251         }
252     }
253 
254     /**
255     * Checks if the XML structure is well formed (i.e. all tags opened must be
256     * closed and all tags opened inside a tag must be closed
257     * inside the same tag). It also checks parameters passed.
258     * If any collisions found appropriate error message is
259     * output into a stream specified. No XML data output, i.e.
260     * no output will be performed if no errors occur.<p>
261     * After document is completed there is a way to cehck
262     * if the XML data and structure was valid.
263     */
264     public static class XMLWellFormChecker extends XMLWriter {
265         protected boolean docStarted = false ;
266         protected boolean docEnded = false ;
267         protected Vector tagStack = new Vector() ;
268         protected boolean wellFormed = true ;
269         protected boolean noOtherErrors = true ;
270         protected PrintWriter log = null ;
271         protected boolean printXMLData = false ;
272 
273         public XMLWellFormChecker(PrintWriter log) {
274             super() ;
275             this.log = log ;
276         }
277 
278         public XMLWellFormChecker(PrintWriter log_, boolean printXMLData) {
279             super(printXMLData ? log_ : null) ;
280             this.printXMLData = printXMLData ;
281             this.log = log_ ;
282         }
283 
284         /**
285          * Reset all values. This is important e.g. for test of XFilter
286          * interface, where 'filter()' method istbstarted twice.
287          */
288         public void reset() {
289             docStarted = false ;
290             docEnded = false ;
291             tagStack = new Vector() ;
292             wellFormed = true ;
293             noOtherErrors = true ;
294             PrintWriter log = null ;
295             printXMLData = false ;
296         }
297 
298         public void startDocument() {
299             super.startDocument();
300 
301             if (docStarted) {
302                 printError("Document is started twice.") ;
303                 wellFormed = false ;
304             }
305 
306             docStarted = true ;
307         }
308         public void endDocument() {
309             super.endDocument();
310             if (!docStarted) {
311                 wellFormed = false ;
312                 printError("Document ended but not started.") ;
313             }
314             docEnded = true ;
315         }
316         public void startElement(String name, XAttributeList attr) {
317             super.startElement(name, attr);
318             if (attr == null) {
319                 printError("attribute list passed as parameter to startElement()"+
320                     " method has null value for tag <" + name + ">") ;
321                 noOtherErrors = false ;
322             }
323             tagStack.add(0, name) ;
324         }
325         public void endElement(String name) {
326             super.endElement(name);
327             if (wellFormed) {
328                 if (tagStack.size() == 0) {
329                     wellFormed = false ;
330                     printError("No tags to close (bad closing tag </" + name + ">)") ;
331                 } else {
332                     String startTag = (String) tagStack.elementAt(0) ;
333                     tagStack.remove(0) ;
334                     if (!startTag.equals(name)) {
335                         wellFormed = false ;
336                         printError("Bad closing tag: </" + name +
337                             ">; tag expected: </" + startTag + ">");
338                     }
339                 }
340             }
341         }
342 
343         /**
344         * Checks if there were no errors during document handling.
345         * I.e. startDocument() and endDocument() must be called,
346         * XML must be well formed, paramters must be valid.
347         */
348         public boolean isWellFormed() {
349             if (!docEnded) {
350                 printError("Document was not ended.") ;
351                 wellFormed = false ;
352             }
353 
354             return wellFormed && noOtherErrors ;
355         }
356 
357         /**
358         * Prints error message and all tags where error occured inside.
359         * Also prints "Tag trace" in case if the full XML data isn't
360         * printed.
361         */
362         public void printError(String msg) {
363             log.println("!!! Error: " + msg) ;
364             if (printXMLData) return ;
365             log.println("   Tag trace :") ;
366             for (int i = 0; i < tagStack.size(); i++) {
367                 String tag = (String) tagStack.elementAt(i) ;
368                 log.println("      <" + tag + ">") ;
369             }
370         }
371     }
372 
373     /**
374     * Beside structure of XML this class also can check existence
375     * of tags, inner tags, and character data. After document
376     * completion there is a way to check if required tags and
377     * character data was found. If there any error occurs an
378     * appropriate message is output.
379     */
380     public static class XMLTagsChecker extends XMLWellFormChecker {
381         protected Hashtable tags = new Hashtable() ;
382         protected Hashtable chars = new Hashtable() ;
383         protected boolean allOK = true ;
384 
385         public XMLTagsChecker(PrintWriter log) {
386             super(log) ;
387         }
388 
389         /**
390         * Adds a tag name which must be contained in the XML data.
391         */
392         public void addTag(String tag) {
393             tags.put(tag, "") ;
394         }
395         /**
396         * Adds a tag name which must be contained in the XML data and
397         * must be inside the tag with name <code>outerTag</code>.
398         */
399         public void addTagEnclosed(String tag, String outerTag) {
400             tags.put(tag, outerTag) ;
401         }
402         /**
403         * Adds a character data which must be contained in the XML data.
404         */
405         public void addCharacters(String ch) {
406             chars.put(ch, "") ;
407         }
408         /**
409         * Adds a character data which must be contained in the XML data and
410         * must be inside the tag with name <code>outerTag</code>.
411         */
412         public void addCharactersEnclosed(String ch, String outerTag) {
413             chars.put(ch, outerTag) ;
414         }
415 
416         public void startElement(String name, XAttributeList attrs) {
417             super.startElement(name, attrs) ;
418             if (tags.containsKey(name)) {
419                 String outerTag = (String) tags.get(name);
420                 if (!outerTag.equals("")) {
421                     boolean isInTag = false ;
422                     for (int i = 0; i < tagStack.size(); i++) {
423                         if (outerTag.equals((String) tagStack.elementAt(i))) {
424                             isInTag = true ;
425                             break ;
426                         }
427                     }
428                     if (!isInTag) {
429                         printError("Required tag <" + name + "> found, but is not enclosed in tag <" +
430                             outerTag + ">") ;
431                         allOK = false ;
432                     }
433                 }
434                 tags.remove(name) ;
435             }
436         }
437 
438         public void characters(String ch) {
439             super.characters(ch) ;
440 
441             if (chars.containsKey(ch)) {
442                 String outerTag = (String) chars.get(ch);
443                 if (!outerTag.equals("")) {
444                     boolean isInTag = false ;
445                     for (int i = 0; i < tagStack.size(); i++) {
446                         if (outerTag.equals((String) tagStack.elementAt(i))) {
447                             isInTag = true ;
448                             break ;
449                         }
450                     }
451                     if (!isInTag) {
452                         printError("Required characters '" + ch + "' found, but are not enclosed in tag <" +
453                             outerTag + ">") ;
454                         allOK = false ;
455                     }
456                 }
457                 chars.remove(ch) ;
458             }
459         }
460 
461         /**
462         * Checks if the XML data was valid and well formed and if
463         * all necessary tags and character data was found.
464         */
465         public boolean checkTags() {
466             allOK &= isWellFormed() ;
467 
468             Enumeration badTags = tags.keys() ;
469             Enumeration badChars = chars.keys() ;
470 
471             if (badTags.hasMoreElements()) {
472                 allOK = false ;
473                 log.println("Required tags were not found in export :") ;
474                 while(badTags.hasMoreElements()) {
475                     log.println("   <" + ((String) badTags.nextElement()) + ">") ;
476                 }
477             }
478             if (badChars.hasMoreElements()) {
479                 allOK = false ;
480                 log.println("Required characters were not found in export :") ;
481                 while(badChars.hasMoreElements()) {
482                     log.println("   <" + ((String) badChars.nextElement()) + ">") ;
483                 }
484             }
485             reset();
486             return allOK ;
487         }
488     }
489 
490     /**
491      * Represents an XML tag which must be found in XML data written.
492      * This tag can contain only its name or tag name and attribute
493      * name, or attribute value additionally.
494      */
495     public static class Tag {
496         private String name = null;
497         private String[][] attrList = new String[0][3] ;
498 
499         /**
500          * Creates tag which has only a name. Attributes don't make sense.
501          * @param tagName The name of the tag.
502          */
503         public Tag(String tagName) {
504             name = tagName ;
505         }
506 
507         /**
508          * Creates a tag with the name specified, which must have an
509          * attribute with name specified. The value of this attribute
510          * doesn't make sense.
511          * @param tagName The name of the tag.
512          * @param attrName The name of attribute which must be contained
513          * in the tag.
514          */
515         public Tag(String tagName, String attrName) {
516             name = tagName ;
517             attrList = new String[1][3] ;
518             attrList[0][0] = attrName ;
519         }
520 
521         /**
522          * Creates a tag with the name specified, which must have an
523          * attribute with the value specified. The type of value
524          * assumed to be 'CDATA'.
525          * @param tagName The name of the tag.
526          * @param attrName The name of attribute which must be contained
527          * in the tag.
528          * @param attrValue Attribute value.
529          */
530         public Tag(String tagName, String attrName, String attrValue) {
531             name = tagName ;
532             attrList = new String[1][3] ;
533             attrList[0][0] = attrName ;
534             attrList[0][1] = "CDATA" ;
535             attrList[0][2] = attrValue ;
536         }
537 
538         /**
539          * Creates a tag with the name specified, which must have
540          * attributes specified. The value of thesee attributes
541          * doesn't make sense.
542          * @param tagName The name of the tag.
543          * @param attrNames Array with names of attributes which must
544          * be contained in the tag.
545          */
546         public Tag(String tagName, String[] attrNames) {
547             name = tagName ;
548             attrList = new String[attrNames.length][3] ;
549             for (int i = 0; i < attrNames.length; i++) {
550                 attrList[i][0] = attrNames[i] ;
551             }
552         }
553 
554         /**
555          * Creates a tag with the name specified, which must have an
556          * attributes with their values specified. The type of all values
557          * assumed to be 'CDATA'.
558          * @param tagName The name of the tag.
559          * @param attrValues An array with attribute names and their values.
560          * <code>attrValues[N][0]</code> element contains the name of Nth
561          * attribute, and <code>attrValues[N][1]</code> element contains
562          * value of Nth attribute, if value is <code>null</code> then the
563          * attribute value can be any.
564          */
565         public Tag(String tagName, String[][] attrValues) {
566             name = tagName ;
567             attrList = new String[attrValues.length][3] ;
568             for (int i = 0; i < attrValues.length; i++) {
569                 attrList[i][0] = attrValues[i][0] ;
570                 attrList[i][1] = "CDATA" ;
571                 attrList[i][2] = attrValues[i][1] ;
572             }
573         }
574 
575         /**
576          * Gets tag String description.
577          */
578         public String toString() {
579             String ret = "<" + name ;
580             for (int i = 0; i < attrList.length; i++) {
581                 ret += " " + attrList[i][0] + "=";
582                 if (attrList[i][2] == null) {
583                     ret += "(not specified)";
584                 } else {
585                     ret += "\"" + attrList[i][2] + "\"";
586                 }
587             }
588             ret += ">";
589 
590             return ret ;
591         }
592 
593         protected boolean checkAttr(int attrListIdx, XAttributeList list) {
594             short j  = 0 ;
595             int listLen = list.getLength();
596             while(j < listLen) {
597                 if (attrList[attrListIdx][0].equals(list.getNameByIndex(j))) {
598                     if (attrList[attrListIdx][2] == null) return true ;
599                     return attrList[attrListIdx][2].equals(list.getValueByIndex(j)) ;
600                 }
601                 j++ ;
602             }
603             return false ;
604         }
605 
606         /**
607          * Checks if this tag matches tag passed in parameters.
608          * I.e. if tag specifies only it's name it mathes if names
609          * are equal (attributes don't make sense). If there are
610          * some attributes names specified in this tag method checks
611          * if all names present in attribute list <code>list</code>
612          * (attributes' values don't make sense). If attributes specified
613          * with values method checks if these attributes exist and
614          * have appropriate values.
615          */
616         public boolean isMatchTo(String tagName, XAttributeList list) {
617             if (!name.equals(tagName)) return false;
618             boolean result = true ;
619             for (int i = 0; i < attrList.length; i++) {
620                 result &= checkAttr(i, list) ;
621             }
622             return result ;
623         }
624     }
625 
626     /**
627      * Class realises extended XML data checking. It has possibilities
628      * to check if a tag exists, if it has some attributes with
629      * values, and if this tag is contained in another tag (which
630      * also can specify any attributes). It can check if some
631      * character data exists inside any tag specified.
632      */
633     public static class XMLChecker extends XMLWellFormChecker {
634         protected HashSet tagSet = new HashSet() ;
635         protected Vector tags = new Vector() ;
636         protected Vector chars = new Vector() ;
637         protected Vector tagStack = new Vector() ;
638         protected Vector attrStack = new Vector() ;
639 
640         public XMLChecker(PrintWriter log, boolean writeXML) {
641             super(log, writeXML) ;
642         }
643 
644         public void addTag(Tag tag) {
645             tags.add(new Tag[] {tag, null}) ;
646             tagSet.add(tag.name) ;
647         }
648 
649         public void addTagEnclosed(Tag tag, Tag outerTag) {
650             tags.add(new Tag[] {tag, outerTag}) ;
651             tagSet.add(tag.name) ;
652         }
653 
654         public void addCharacters(String ch) {
655             chars.add(new Object[] {ch.trim(), null}) ;
656         }
657 
658         public void addCharactersEnclosed(String ch, Tag outerTag) {
659             chars.add(new Object[] {ch.trim(), outerTag}) ;
660         }
661 
662         public void startElement(String name, XAttributeList attr) {
663             try {
664             super.startElement(name, attr);
665 
666             if (tagSet.contains(name)) {
667                 for (int i = 0; i < tags.size(); i++) {
668                     Tag[] tag = (Tag[]) tags.elementAt(i);
669                     if (tag[0].isMatchTo(name, attr)) {
670                         if (tag[1] == null) {
671                             tags.remove(i--);
672                         } else {
673                             boolean isInStack = false ;
674                             for (int j = 0; j < tagStack.size(); j++) {
675                                 if (tag[1].isMatchTo((String) tagStack.elementAt(j),
676                                     (XAttributeList) attrStack.elementAt(j))) {
677 
678                                     isInStack = true ;
679                                     break ;
680                                 }
681                             }
682                             if (isInStack) {
683                                 tags.remove(i--) ;
684                             }
685                         }
686                     }
687                 }
688             }
689 
690             tagStack.add(0, name) ;
691             attrStack.add(0, new AttributeList(attr));
692             } catch (Exception e) {
693                 e.printStackTrace(log);
694             }
695         }
696 
697         public void characters(String ch) {
698             super.characters(ch) ;
699             for (int i = 0; i < chars.size(); i++) {
700                 Object[] chr = (Object[]) chars.elementAt(i);
701                 if (((String) chr[0]).equals(ch)) {
702                     if (chr[1] == null) {
703                         chars.remove(i--);
704                     } else {
705                         boolean isInStack = false ;
706                         for (int j = 0; j < tagStack.size(); j++) {
707                             if (((Tag) chr[1]).isMatchTo((String) tagStack.elementAt(j),
708                                 (XAttributeList) attrStack.elementAt(j))) {
709 
710                                 isInStack = true ;
711                                 break ;
712                             }
713                         }
714                         if (isInStack) {
715                             chars.remove(i--) ;
716                         }
717                     }
718                 }
719             }
720         }
721 
722         public void endElement(String name) {
723             try {
724             super.endElement(name);
725 
726             if (tagStack.size() > 0) {
727                 tagStack.remove(0) ;
728                 attrStack.remove(0) ;
729             }
730             } catch(Exception e) {
731                 e.printStackTrace(log) ;
732             }
733         }
734 
735         public boolean check() {
736             if (tags.size()> 0) {
737                 log.println("!!! Error: Some tags were not found :") ;
738                 for (int i = 0; i < tags.size(); i++) {
739                     Tag[] tag = (Tag[]) tags.elementAt(i) ;
740                     log.println("   Tag " + tag[0] + " was not found");
741                     if (tag[1] != null)
742                         log.println("      inside tag " + tag[1]) ;
743                 }
744             }
745             if (chars.size() > 0) {
746                 log.println("!!! Error: Some character data blocks were not found :") ;
747                 for (int i = 0; i < chars.size(); i++) {
748                     Object[] ch = (Object[]) chars.elementAt(i) ;
749                     log.println("   Character data \"" + ch[0] + "\" was not found ") ;
750                     if (ch[1] != null)
751                         log.println("      inside tag " + ch[1]) ;
752                 }
753             }
754 
755             if (!isWellFormed())
756                 log.println("!!! Some errors were found in XML structure") ;
757 
758             boolean result = tags.size() == 0 && chars.size() == 0 && isWellFormed();
759             reset();
760             return result;
761         }
762     }
763 
764     /**
765     * Creates <code>XDocumentHandler</code> implementation in form
766     * of <code>com.sun.star.xml.sax.Writer</code> service, which
767     * writes XML data into a <code>com.sun.star.io.Pipe</code>
768     * created.
769     * @return Single element array which contains the handler
770     * contained in <code>Any</code> structure.
771     */
772     public static Object[] getDocumentHandler(XMultiServiceFactory xMSF) {
773         Object[] ret = new Object[1];
774         try {
775             XInterface Writer = (XInterface) xMSF.createInstance(
776                                     "com.sun.star.xml.sax.Writer");
777             XInterface oPipe = (XInterface) xMSF.createInstance
778                 ( "com.sun.star.io.Pipe" );
779             XOutputStream xPipeOutput = (XOutputStream) UnoRuntime.
780                 queryInterface(XOutputStream.class, oPipe) ;
781 
782             XActiveDataSource xADS = (XActiveDataSource)
783                 UnoRuntime.queryInterface(XActiveDataSource.class,Writer);
784             xADS.setOutputStream(xPipeOutput);
785             XDocumentHandler handler = (XDocumentHandler)
786                 UnoRuntime.queryInterface(XDocumentHandler.class,Writer);
787 
788             Any arg = new Any(new Type(XDocumentHandler.class),handler);
789 
790             ret[0] = arg;
791         } catch (com.sun.star.uno.Exception e) {
792             e.printStackTrace();
793         }
794         return ret;
795     }
796 
797     public static PropertyValue[] createMediaDescriptor(String[] propNames, Object[] values) {
798         PropertyValue[] props = new PropertyValue[propNames.length] ;
799 
800         for (int i = 0; i < props.length; i++) {
801             props[i] = new PropertyValue() ;
802             props[i].Name = propNames[i] ;
803             if (values != null && i < values.length) {
804                 props[i].Value = values[i] ;
805             }
806         }
807 
808         return props ;
809     }
810 
811     /**
812      * Gets the hanlder, which writes all the XML data passed to the
813      * file specified.
814      * @param xMSF Soffice <code>ServiceManager</code> factory.
815      * @param fileURL The file URL (in form file:///<path>) to which
816      * XML data is written.
817      * @return SAX handler to which XML data has to be written.
818      */
819     public static XDocumentHandler getFileXMLWriter(XMultiServiceFactory xMSF, String fileURL)
820         throws com.sun.star.uno.Exception
821     {
822         XInterface oFacc = (XInterface)xMSF.createInstance(
823             "com.sun.star.comp.ucb.SimpleFileAccess");
824         XSimpleFileAccess xFacc = (XSimpleFileAccess)UnoRuntime.queryInterface
825             (XSimpleFileAccess.class, oFacc) ;
826 
827         XInterface oWriter = (XInterface)xMSF.createInstance(
828             "com.sun.star.xml.sax.Writer");
829         XActiveDataSource xWriterDS = (XActiveDataSource)
830             UnoRuntime.queryInterface(XActiveDataSource.class, oWriter);
831         XDocumentHandler xDocHandWriter = (XDocumentHandler) UnoRuntime.queryInterface
832             (XDocumentHandler.class, oWriter) ;
833 
834         if (xFacc.exists(fileURL))
835             xFacc.kill(fileURL);
836         XOutputStream fOut = xFacc.openFileWrite(fileURL) ;
837         xWriterDS.setOutputStream(fOut);
838 
839         return xDocHandWriter ;
840     }
841 
842     /**
843      * Parses XML file and passes its data to the SAX handler specified.
844      * @param xMSF Soffice <code>ServiceManager</code> factory.
845      * @param fileURL XML file name (in form file:///<path>) to be parsed.
846      * @param handler SAX handler to which XML data from file will
847      * be transferred.
848      */
849     public static void parseXMLFile(XMultiServiceFactory xMSF,
850         String fileURL, XDocumentHandler handler) throws com.sun.star.uno.Exception
851     {
852         XInterface oFacc = (XInterface)xMSF.createInstance(
853             "com.sun.star.comp.ucb.SimpleFileAccess");
854         XSimpleFileAccess xFacc = (XSimpleFileAccess)UnoRuntime.queryInterface
855             (XSimpleFileAccess.class, oFacc) ;
856         XInputStream oIn = xFacc.openFileRead(fileURL) ;
857 
858         XInterface oParser = (XInterface)xMSF.createInstance(
859             "com.sun.star.xml.sax.Parser");
860         XParser xParser = (XParser) UnoRuntime.queryInterface(XParser.class, oParser);
861 
862         xParser.setDocumentHandler(handler) ;
863         InputSource inSrc = new InputSource() ;
864         inSrc.aInputStream = oIn ;
865         xParser.parseStream(inSrc) ;
866 
867         oIn.closeInput();
868     }
869 
870     /**
871      * Exports document (the whole or a part) into the file specified
872      * in XML format.
873      * @param xMSF Soffice <code>ServiceManager</code> factory.
874      * @param xDoc Document to be exported.
875      * @param docType Type of document (for example 'Calc', 'Writer', 'Draw')
876      * The type must start with <b>capital</b> letter.
877      * @param exportType The type of export specifies if the whole
878      * document will be exported or one of its parts (Meta info, Styles, etc.).
879      * The following types supported (it also depends of document type) :
880      *  "" (empty string) - for the whole document ;
881      *  "Content" - only content exported ;
882      *  "Meta" - meta document info exported ;
883      *  "Settings" - view settings of document exported ;
884      *  "Styles" - document styles exported ;
885      * @param fileURL XML file name (in form file:///<path>) to be exported to.
886      */
887     public static void exportDocument(XMultiServiceFactory xMSF, XComponent xDoc,
888         String docType, String exportType, String fileURL)
889         throws com.sun.star.uno.Exception {
890 
891         XDocumentHandler xDocHandWriter = XMLTools.getFileXMLWriter(xMSF, fileURL) ;
892 
893         Any arg = new Any(new Type(XDocumentHandler.class), xDocHandWriter);
894         XInterface oExp = (XInterface)xMSF.createInstanceWithArguments(
895             "com.sun.star.comp." + docType + ".XML" + exportType + "Exporter",
896             new Object[] {arg});
897 
898         XExporter xExp = (XExporter) UnoRuntime.queryInterface
899             (XExporter.class, oExp) ;
900         xExp.setSourceDocument(xDoc) ;
901 
902         XFilter filter = (XFilter) UnoRuntime.queryInterface(XFilter.class, oExp) ;
903         filter.filter(XMLTools.createMediaDescriptor(
904             new String[] {"FilterName"},
905             new Object[] {"Custom filter"})) ;
906     }
907 
908     /**
909      * Imports document (the whole or a part) from the file specified
910      * in XML format.
911      * @param xMSF Soffice <code>ServiceManager</code> factory.
912      * @param xDoc Target document to be imported.
913      * @param docType Type of document (for example 'Calc', 'Writer', 'Draw')
914      * The type must start with <b>capital</b> letter.
915      * @param exportType The type of export specifies if the whole
916      * document will be exported or one of its parts (Meta info, Styles, etc.).
917      * The following types supported (it hardly depends of XML data in file) :
918      *  "" (empty string) - for the whole document ;
919      *  "Content" - only content exported ;
920      *  "Meta" - meta document info exported ;
921      *  "Settings" - view settings of document exported ;
922      *  "Styles" - document styles exported ;
923      * @param fileURL XML file name (in form file:///<path>) to be imported from.
924      */
925     public static void importDocument(XMultiServiceFactory xMSF, XComponent xDoc,
926         String docType, String importType, String fileURL)
927         throws com.sun.star.uno.Exception {
928 
929         XInterface oImp = (XInterface)xMSF.createInstance(
930             "com.sun.star.comp." + docType + ".XML" + importType + "Importer");
931         XImporter xImp = (XImporter) UnoRuntime.queryInterface
932             (XImporter.class, oImp) ;
933         XDocumentHandler xDocHandImp = (XDocumentHandler) UnoRuntime.queryInterface
934             (XDocumentHandler.class, oImp) ;
935 
936         xImp.setTargetDocument(xDoc) ;
937         parseXMLFile(xMSF, fileURL, xDocHandImp) ;
938     }
939 }