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