summaryrefslogtreecommitdiff
path: root/l10ntools/source/filter/utils/XMLHelper.java
blob: 0f912cac8e25caa7ee541279264ca0047075dad8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: XMLHelper.java,v $
 * $Revision: 1.7 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

package com.sun.star.filter.config.tools.utils;

//_______________________________________________

import java.lang.*;
import java.util.*;
import java.io.*;

//_______________________________________________

/**
 *  It provides some constant values and some static helper routines
 *  which are neccessary to work with a xml file - especialy
 *  the filter configuration.
 *
 *
 */
public class XMLHelper
{
    //___________________________________________
    // public const

    /** its a possible value of the xml attribute "oor:type" and identify an integer type. */
    public static final java.lang.String XMLTYPE_INTEGER = "xs:int";

    /** its a possible value of the xml attribute "oor:type" and identify an boolean type. */
    public static final java.lang.String XMLTYPE_BOOLEAN = "xs:boolean";

    /** its a possible value of the xml attribute "oor:type" and identify an string type. */
    public static final java.lang.String XMLTYPE_STRING = "xs:string";

    /** its a possible value of the xml attribute "oor:type" and identify an string list type. */
    public static final java.lang.String XMLTYPE_STRINGLIST = "oor:string-list";

    /** its a xml attribute, which specify a property name. */
    public static final java.lang.String XMLATTRIB_OOR_NAME = "oor:name";

    /** its a xml attribute, which specify a property type. */
    public static final java.lang.String XMLATTRIB_OOR_TYPE = "oor:type";

    /** its a xml attribute, which specify a list separator. */
    public static final java.lang.String XMLATTRIB_OOR_SEPARATOR = "oor:separator";

    /** its a xml attribute, which specify a localized value. */
    public static final java.lang.String XMLATTRIB_OOR_LOCALIZED = "oor:localized";

    /** its a xml attribute, which specify a merge operation for cfg layering. */
    public static final java.lang.String XMLATTRIB_OOR_OP = "oor:op";

    /** can be used as value for XMLATTRIB_OOR_OP. */
    public static final java.lang.String XMLATTRIB_OP_REPLACE = "replace";

    /** its a xml attribute, which specify a locale value. */
    public static final java.lang.String XMLATTRIB_XML_LANG = "xml:lang";

    /** its the tag name of a <value ...> entry. */
    public static final java.lang.String XMLTAG_VALUE = "value";

    /** its the tag name of a <prop ...> entry. */
    public static final java.lang.String XMLTAG_PROP = "prop";

    /** its the tag name of a <node ...> entry. */
    public static final java.lang.String XMLTAG_NODE = "node";

    //___________________________________________
    // private const

    /** a static list of all possible separators, which can be used for configuration type string-list. */
    private static final java.lang.String[] DELIMS = {" ", ",", ";", ".", ":", "-", "_", "#", "'", "+", "*", "~", "=", "?"};

    /** index of the default separator inside list DELIMS.
     *  Its neccessary to know such default separator; because it can
     *  be supressed as xml attribute of the corresponding value tag. */
    private static final int DEFAULT_SEPARATOR = 0;

    //___________________________________________

    /** analyze the structures of the given XML node and
     *  return a property set of all found sub nodes.
     *
     *  Such properties are organized as [name, value] pairs.
     *  The type of a xml node will be detected automaticly.
     *  Following types are supported:
     *      xs:int          => java.lang.Integer
     *      xs:bool         => java.lang.Boolean
     *      xs:string       => java.lang.String
     *      oor:string-list => java.util.LinkedList[java.lang.String]
     *      oor:set         => java.util.Vector[java.lang.Object]
     *      oor:localized   => java.util.HashMap[java.lang.Object]
     *
     *  @param  aNode
     *          points directly to the xml node, where we should analyze
     *          the children nodes.
     *
     *  @return [java.util.HashMap]
     *          contains every node name as key and its string(!) as value.
     */
    public static java.util.HashMap convertNodeToPropSet(org.w3c.dom.Node aNode)
        throws java.lang.Exception
    {
        java.util.HashMap aPropSet = new java.util.HashMap();

        // get all child nodes, which seems to be properties
        java.util.Vector      lChildNodes = XMLHelper.extractChildNodesByTagName(aNode, XMLTAG_PROP);
        java.util.Enumeration en1         = lChildNodes.elements();
        while(en1.hasMoreElements())
        {
            org.w3c.dom.Node aChildNode = (org.w3c.dom.Node)en1.nextElement();

            // read its name
            java.lang.String sChildName = XMLHelper.extractNodeAttribByName(aChildNode, XMLATTRIB_OOR_NAME);
            if (sChildName == null)
                throw new java.io.IOException("unsupported format: could not extract child node name");

            // read its type info
            java.lang.String sChildType = XMLHelper.extractNodeAttribByName(aChildNode, XMLATTRIB_OOR_TYPE);
            if (sChildType == null)
            {
                /** Special patch:
                 *      If an xml tag has no type information set ... we can restore it
                 *      by analyzing the already readed tag name :-)
                 *      Not very nice - but it can help to read stripped xml files too. */
                sChildType = XMLHelper.getTypeForTag(sChildName);
                if (sChildType == null)
                    throw new java.io.IOException("unsupported format: could not extract child node type");
            }

            // read its value(s?)
            java.util.Vector      lChildValues = XMLHelper.extractChildNodesByTagName(aChildNode, XMLTAG_VALUE);
            java.util.Enumeration en2          = lChildValues.elements();
            int                   nValue       = 0;
            java.lang.Object      aValue       = null;
            while(en2.hasMoreElements())
            {
                org.w3c.dom.Node aValueNode   = (org.w3c.dom.Node)en2.nextElement();
                java.lang.String sChildLocale = XMLHelper.extractNodeAttribByName(aValueNode, XMLATTRIB_XML_LANG);
                boolean          bLocalized   = (sChildLocale != null);

                ++nValue;

                if (sChildType.equals(XMLTYPE_INTEGER))
                {
                    if (!bLocalized && nValue > 1)
                        throw new java.io.IOException("unsupported format: more then one value for non localized but atomic type detected");
                    java.lang.String sData = ((org.w3c.dom.CharacterData)aValueNode.getFirstChild()).getData();
                    aValue = new java.lang.Integer(sData);
                }
                else
                if (sChildType.equals(XMLTYPE_BOOLEAN))
                {
                    if (!bLocalized && nValue > 1)
                        throw new java.io.IOException("unsupported format: more then one value for non localized but atomic type detected");
                    java.lang.String sData = ((org.w3c.dom.CharacterData)aValueNode.getFirstChild()).getData();
                    aValue = new java.lang.Boolean(sData);
                }
                else
                if (sChildType.equals(XMLTYPE_STRING))
                {
                    if (!bLocalized && nValue > 1)
                        throw new java.io.IOException("unsupported format: more then one value for non localized but atomic type detected");

                    java.lang.String sData = ((org.w3c.dom.CharacterData)aValueNode.getFirstChild()).getData();

                    java.util.HashMap lLocalized = null;
                    if (bLocalized)
                    {
                        if (aValue == null)
                            aValue = new java.util.HashMap();
                        lLocalized = (java.util.HashMap)aValue;
                        lLocalized.put(sChildLocale, sData);
                    }
                    else
                        aValue = sData;
                }
                else
                if (sChildType.equals(XMLTYPE_STRINGLIST))
                {
                    if (!bLocalized && nValue > 1)
                        throw new java.io.IOException("unsupported format: more then one value for non localized but atomic type detected");

                    java.lang.String sSeparator = XMLHelper.extractNodeAttribByName(aChildNode, XMLATTRIB_OOR_SEPARATOR);
                    if (sSeparator == null)
                        sSeparator = " ";

                    java.lang.String          sData      = ((org.w3c.dom.CharacterData)aValueNode.getFirstChild()).getData();
                    sData = sData.replace('\t', ' ');
                    sData = sData.replace('\n', ' ');
                    java.util.StringTokenizer aTokenizer = new java.util.StringTokenizer(sData, sSeparator);
                    java.util.Vector          lList      = new java.util.Vector();
                    while(aTokenizer.hasMoreTokens())
                    {
                        java.lang.String sToken = (java.lang.String)aTokenizer.nextToken();
                        sToken.trim();
                        if (sToken.length() < 1)
                            continue;
                        lList.add(sToken);
                    }
                    aValue = lList;
                }

                aPropSet.put(sChildName, aValue);
            }
        }

        return aPropSet;
    }

    //___________________________________________

    private static java.lang.String getTypeForTag(java.lang.String sTag)
    {
        java.lang.String sType = null;

        if (
            (sTag.equals(Cache.PROPNAME_DATA            )) ||
            (sTag.equals(Cache.PROPNAME_NAME            )) ||
            (sTag.equals(Cache.PROPNAME_UINAME          )) ||
            (sTag.equals(Cache.PROPNAME_MEDIATYPE       )) ||
            (sTag.equals(Cache.PROPNAME_CLIPBOARDFORMAT )) ||
            (sTag.equals(Cache.PROPNAME_PREFERREDFILTER )) ||
            (sTag.equals(Cache.PROPNAME_DETECTSERVICE   )) ||
            (sTag.equals(Cache.PROPNAME_FRAMELOADER     )) ||
            (sTag.equals(Cache.PROPNAME_CONTENTHANDLER  )) ||
            (sTag.equals(Cache.PROPNAME_DOCUMENTSERVICE )) ||
            (sTag.equals(Cache.PROPNAME_FILTERSERVICE   )) ||
            (sTag.equals(Cache.PROPNAME_TEMPLATENAME    )) ||
            (sTag.equals(Cache.PROPNAME_TYPE            )) ||
            (sTag.equals(Cache.PROPNAME_UICOMPONENT     ))
           )
            sType = XMLTYPE_STRING;
        else
        if (
            (sTag.equals(Cache.PROPNAME_PREFERRED   )) ||
            (sTag.equals("Installed"                ))
           )
            sType = XMLTYPE_BOOLEAN;
        else
        if (
            (sTag.equals(Cache.PROPNAME_UIORDER          )) ||
            (sTag.equals(Cache.PROPNAME_DOCUMENTICONID   )) ||
            (sTag.equals(Cache.PROPNAME_FILEFORMATVERSION))
           )
            sType = XMLTYPE_INTEGER;
        else
        if (
            (sTag.equals(Cache.PROPNAME_URLPATTERN  )) ||
            (sTag.equals(Cache.PROPNAME_EXTENSIONS  )) ||
            (sTag.equals(Cache.PROPNAME_USERDATA    )) ||
            (sTag.equals(Cache.PROPNAME_FLAGS       )) ||
            (sTag.equals(Cache.PROPNAME_TYPES       ))
           )
            sType = XMLTYPE_STRINGLIST;

        if (sType == null)
            System.err.println("getTypeForTag("+sTag+") = "+sType);

        return sType;
    }

    //___________________________________________

    /** return a xml representation of the given property set.
     *
     *  @param  aPropSet
     *          a set of <name,value> pairs, which should be translated to xml
     *
     *  @return [java.lang.String]
     *          the xml string representation.
     *
     *  @throws [java.lang.Exception]
     *          if anything during convertion fill fail.
     */
    public static java.lang.String convertPropSetToXML(java.util.HashMap aPropSet   ,
                                                       int               nPrettyTabs)
        throws java.lang.Exception
    {
        java.lang.StringBuffer sXML = new java.lang.StringBuffer(256);

        java.util.Iterator it1 = aPropSet.keySet().iterator();
        while(it1.hasNext())
        {
            java.lang.String sProp = (java.lang.String)it1.next();
            java.lang.Object aVal  = aPropSet.get(sProp);

            sProp = encodeHTMLSigns(sProp);

            // is it a simple type?
            if (
                (aVal instanceof java.lang.Integer) ||
                (aVal instanceof java.lang.Boolean) ||
                (aVal instanceof java.lang.String )
               )
            {
                sXML.append(XMLHelper.convertSimpleObjectToXML(sProp, aVal, nPrettyTabs));
                continue;
            }

            // no!
            // is it a list value?
            if (aVal instanceof java.util.Vector)
            {
                java.util.Vector lVal = (java.util.Vector)aVal;
                sXML.append(XMLHelper.convertListToXML(sProp, lVal, nPrettyTabs));
                continue;
            }

            // its a localized value?
            if (aVal instanceof java.util.HashMap)
            {
                java.util.HashMap lVal = (java.util.HashMap)aVal;
                sXML.append(XMLHelper.convertLocalizedValueToXML(sProp, lVal, nPrettyTabs));
                continue;
            }

            // unknown type!
            java.lang.StringBuffer sMsg = new java.lang.StringBuffer(256);
            sMsg.append("unsupported object type detected.");
            sMsg.append("\ttype ?  : \""+sProp+"\" = "+aVal);
            sMsg.append("\tprop set: \""+aPropSet          );
            throw new java.lang.Exception(sMsg.toString());
        }

        return sXML.toString();
    }

    public static java.lang.String encodeHTMLSigns(java.lang.String sValue)
    {
        java.lang.StringBuffer sSource      = new java.lang.StringBuffer(sValue);
        java.lang.StringBuffer sDestination = new java.lang.StringBuffer(1000  );

        for (int i=0; i<sSource.length(); ++i)
        {
            char c = sSource.charAt(i);
            if (c == '&')
                sDestination.append("&amp;");
            else
                sDestination.append(c);
        }

        java.lang.String sReturn = sDestination.toString();
        if (!sReturn.equals(sValue))
            System.out.println("encode \""+sValue+"\" => \""+sReturn+"\"");

        return sReturn;
    }

    //___________________________________________

    /** return a xml representation of an atomic property.
     *
     *  Atomic property types are e.g. Integer, Boolean, String.
     *
     *  @param  sName
     *          the name of the property.

     *  @param  aValue
     *          the value of the property.
     *
     *  @param  nPrettyTabs
     *          count of tab signs for pretty format the xml code :-)
     *
     *  @return [java.lang.String]
     *          the xml string representation.
     *
     *  @throws [java.lang.Exception]
     *          if anything during convertion fill fail.
     */
    private static java.lang.String convertSimpleObjectToXML(java.lang.String sName      ,
                                                             java.lang.Object aValue     ,
                                                             int              nPrettyTabs)
        throws java.lang.Exception
    {
        java.lang.StringBuffer sXML = new java.lang.StringBuffer(256);
        for (int t=0; t<nPrettyTabs; ++t)
            sXML.append("\t");

        if (aValue instanceof java.lang.Integer)
        {
            sXML.append("<prop "+XMLATTRIB_OOR_NAME+"=\""+sName+"\">");
            sXML.append("<value>"+aValue.toString()+"</value>");
            sXML.append("</prop>\n");
        }
        else
        if (aValue instanceof java.lang.Boolean)
        {
            sXML.append("<prop "+XMLATTRIB_OOR_NAME+"=\""+sName+"\">");
            sXML.append("<value>"+aValue.toString()+"</value>");
            sXML.append("</prop>\n");
        }
        else
        if (aValue instanceof java.lang.String)
        {
            sXML.append("<prop "+XMLATTRIB_OOR_NAME+"=\""+sName+"\"");
            java.lang.String sValue = (java.lang.String)aValue;

            sValue = encodeHTMLSigns(sValue);

            if (sValue.length() < 1)
                sXML.append("/>\n");
            else
            {
                sXML.append("><value>"+sValue+"</value>");
                sXML.append("</prop>\n");
            }
        }
        else
        {
            System.err.println("name  = "+sName);
            System.err.println("value = "+aValue);
            // ! can be used outside to detect - that it was not a simple type :-)
            throw new java.lang.Exception("not an atomic type.");
        }

        return sXML.toString();
    }

    //___________________________________________

    /** return a xml representation of a string-list property.
     *
     *  @param  sName
     *          the name of the property.

     *  @param  aValue
     *          the value of the property.
     *
     *  @param  nPrettyTabs
     *          count of tab signs for pretty format the xml code :-)
     *
     *  @return [java.lang.String]
     *          the xml string representation.
     *
     *  @throws [java.lang.Exception]
     *          if anything during convertion fill fail.
     */
    private static java.lang.String convertListToXML(java.lang.String sName      ,
                                                     java.util.Vector aValue     ,
                                                     int              nPrettyTabs)
        throws java.lang.Exception
    {
        java.lang.StringBuffer sXML = new java.lang.StringBuffer(256);

        for (int t=0; t<nPrettyTabs; ++t)
            sXML.append("\t");

        int c = aValue.size();
        if (c < 1)
        {
            sXML.append("<prop "+XMLATTRIB_OOR_NAME+"=\""+sName+"\"/>\n");
            return sXML.toString();
        }

        // step over all list items and add it to a string buffer
        // Every item will be separated by a default separator "\n" first.
        // Because "\n" is not a valid separator at all and can`t occure inside
        // our list items. During we step over all items, we check if our current separator
        // (we use a list of possible ones!) clash with an item.
        // If it clash - we step to the next possible separator.
        // If our list of possible separator values runs out of range we throw
        // an exception :-) Its better then generating of wrong values
        // If we found a valid seperator - we use it to replace our "\n" place holder
        // at the end of the following loop ...

        int                    d        = 0;
        java.lang.StringBuffer sValBuff = new java.lang.StringBuffer(256);
        for (int i=0; i<c; ++i)
        {
            // get the next list item
            java.lang.Object aItem = aValue.get(i);
            if (!(aItem instanceof java.lang.String))
                throw new java.lang.Exception("Current implementation supports string-list only!");

            java.lang.String sValue = (java.lang.String)aItem;

            sValue = encodeHTMLSigns(sValue);

            // append item with default separator, which isn a valid separator at all
            // But supress adding of the separator if last element is reached.
            sValBuff.append(sValue);
            if (i<(c-1))
                sValBuff.append("\n");

            // check for delim clash
            // Attention: An empty (means default) element forbid using
            // of a whitespace character as separator!
            while(true)
            {
                if (d >= DELIMS.length)
                    throw new java.lang.Exception("No valid separator found for a string list item.");
                if (sValue.length() < 1 && DELIMS[d].equals(" "))
                {
                    ++d;
                    continue;
                }
                if (sValue.indexOf(DELIMS[d]) != -1)
                {
                    ++d;
                    continue;
                }
                break;
            }
        }

        // replace default separator with right one
        System.out.println("TODO: must be adapted to java 1.3 :-(");
        System.exit(-1);
//TODO_JAVA        java.lang.String sListVal = sValBuff.toString().replaceAll("\n", DELIMS[d]);
        java.lang.String sListVal = null;

        sXML.append("<prop "+XMLATTRIB_OOR_NAME+"=\""+sName+"\">");
        if (d == DEFAULT_SEPARATOR)
            sXML.append("<value>");
        else
            sXML.append("<value "+XMLATTRIB_OOR_SEPARATOR+"=\""+DELIMS[d]+"\">");
        sXML.append(sListVal);
        sXML.append("</value>");
        sXML.append("</prop>\n");

        return sXML.toString();
    }

    //___________________________________________

    /** return a xml representation of a localized property.
     *
     *  @param  sName
     *          the name of the property.

     *  @param  aValue
     *          the value of the property.
     *
     *  @param  nPrettyTabs
     *          count of tab signs for pretty format the xml code :-)
     *
     *  @return [java.lang.String]
     *          the xml string representation.
     *
     *  @throws [java.lang.Exception]
     *          if anything during convertion fill fail.
     */
    private static java.lang.String convertLocalizedValueToXML(java.lang.String  sName      ,
                                                               java.util.HashMap aValue     ,
                                                               int               nPrettyTabs)
        throws java.lang.Exception
    {
        java.lang.StringBuffer sXML = new java.lang.StringBuffer(256);

        int c = aValue.size();
        if (c < 1)
            throw new java.lang.Exception("Cant detect type of localized values. Because the given list is empty.");

        for (int t=0; t<nPrettyTabs; ++t)
            sXML.append("\t");
        // !Our localized values must be formated at a deeper coloum
        // then its property name!
        ++nPrettyTabs;

        sXML.append("<prop "+XMLATTRIB_OOR_NAME+"=\""+sName+"\">\n");
        java.util.Iterator it = aValue.keySet().iterator();
//        boolean bTypeKnown = false;
        while(it.hasNext())
        {
            java.lang.String sLocale = (java.lang.String)it.next();
            java.lang.Object aLocalizedValue = aValue.get(sLocale);
/*
            if (!bTypeKnown)
            {
                bTypeKnown = true;
                if (aLocalizedValue instanceof java.lang.Integer)
                    sXML.append(" "+XMLATTRIB_OOR_TYPE+"=\""+XMLTYPE_INTEGER+"\">\n");
                else
                if (aLocalizedValue instanceof java.lang.Boolean)
                    sXML.append(" "+XMLATTRIB_OOR_TYPE+"=\""+XMLTYPE_BOOLEAN+"\">\n");
                else
                if (aLocalizedValue instanceof java.lang.String)
                    sXML.append(" "+XMLATTRIB_OOR_TYPE+"=\""+XMLTYPE_STRING+"\">\n");
                else
                    throw new java.lang.Exception("Unsupported type for localized value detected.");
            }
*/
            java.lang.String sLocValue = aLocalizedValue.toString();
            java.lang.String sValue    = encodeHTMLSigns(sLocValue);

            for (int t=0; t<nPrettyTabs; ++t)
                sXML.append("\t");
            sXML.append("<value "+XMLATTRIB_XML_LANG+"=\""+sLocale+"\">"+sValue+"</value>\n");
        }
        --nPrettyTabs;
        for (int t=0; t<nPrettyTabs; ++t)
            sXML.append("\t");
        sXML.append("</prop>\n");

        return sXML.toString();
    }

    //___________________________________________

    /** returns the value of an attribute of the given node.
     *
     *  If the given node represent an lement node, may it supports some attributes.
     *  Then this method search for an attribute with the specified name and return it's value.
     *  If nothing could be found ... or the given node isn't a suitable node ... it returns null.
     *
     *  @param  aNode
     *          the node, which should be analyzed.
     *
     *  @param  sAttrib
     *          name of the attribute, which should be searched.
     *
     *  @return The value of the specified attribute if it could be found at the given node.
     *          Can be null if node doesn't support attributes or the searched one does not exist there.
     */
    public static java.lang.String extractNodeAttribByName(org.w3c.dom.Node aNode  ,
                                                           java.lang.String sAttrib)
        throws java.lang.Exception
    {
        // We can get valid attributes for element nodes only!
        if (aNode.getNodeType() != org.w3c.dom.Node.ELEMENT_NODE)
        {
//            System.err.println("not an element node");
            return null;
        }

        // may it supports attributes in general ... but doesn't have anyone realy.
        org.w3c.dom.NamedNodeMap lAttribs = aNode.getAttributes();
        if (lAttribs==null)
        {
//            System.err.println("no attributes at all");
            return null;
        }

        // step over the attribute list and search for the requested one
        for (int i=0; i<lAttribs.getLength(); ++i)
        {
            org.w3c.dom.Attr aAttrib = (org.w3c.dom.Attr)lAttribs.item(i);
            if (aAttrib.getName().equals(sAttrib))
            {
                java.lang.String sValue = aAttrib.getValue();
                return sValue;
            }
        }

        // the searched attribute was not found!
//        System.err.println("required attribute \""+sAttrib+"\" does not exist for node ["+aNode.toString()+"]");
        return null;
    }

    //___________________________________________

    /** returns a list of childs, which are ELEMENT_NODES and have the right tag name.
     *
     *  It analyze the list of all possible child nodes. Only ELEMENT_NODES are candidates.
     *  All other ones will be ignored. Further these element nodes are compared by it's tag
     *  names. If it match with the specified value it's added to the return list.
     *  So the return list includes references to the DOM tree nodes only, which are child
     *  element nodes with the right tag name.
     *
     *  @param  aNode
     *          provides access to the child nodes, which should be analyzed
     *
     *  @param  sTag
     *          the searched tag name.
     *
     * @return  A list of child nodes, which are element nodes and have the right tag name.
     */
    public static java.util.Vector extractChildNodesByTagName(org.w3c.dom.Node aNode,
                                                               java.lang.String sTag )
    {
        // extract first all ELEMENT_NODES of he given parent
        // Such nodes only provide tag names.
        java.util.Vector lChilds          = XMLHelper.extractChildNodesByType(aNode,org.w3c.dom.Node.ELEMENT_NODE);
        java.util.Vector lExtractedChilds = new java.util.Vector(lChilds.size());

        // step over the list and search for the right tags using the specified name
        java.util.Enumeration en = lChilds.elements();
        while (en.hasMoreElements())
        {
            org.w3c.dom.Node aChild = (org.w3c.dom.Node)en.nextElement();
            if (aChild.getNodeName().equals(sTag))
                lExtractedChilds.add(aChild);
        }

        // pack(!) and return the list
        lExtractedChilds.trimToSize();
        return lExtractedChilds;
    }

    //___________________________________________

    /** returns a list of childs, which supports the right node type.
     *
     *  It analyze the list of all possible child nodes. If a node represent the right node type
     *  it is added to the return list. Otherwhise it will be ignored.
     *
     *  @param  aNode
     *          provides access to the list of possible children nodes.
     *
     *  @param  nType
     *          represent the searched node type.
     *          Possible values are constant fields of a org.w3c.dom.Node - e.g. org.w3c.dom.Node.ELEMENT_NODE.
     *
     * @return A list of child nodes, which provides the right node type.
     */
    public static java.util.Vector extractChildNodesByType(org.w3c.dom.Node aNode,
                                                           short            nType)
    {
        // get list of all possibe childs and reserve enough space for our return list
        // Attention: A null pointer is not allowed for return! (means lExtractedChilds)
        org.w3c.dom.NodeList lChilds          = aNode.getChildNodes();
        int                  c                = lChilds.getLength();
        java.util.Vector     lExtractedChilds = new java.util.Vector(c);

        // step of these childs and select only needed ones
        for (int i=0; i<c; ++i)
        {
            org.w3c.dom.Node aChild = lChilds.item(i);
            if (aChild.getNodeType() == nType)
                lExtractedChilds.add(aChild);
        }

        // pack(!) and return the list
        lExtractedChilds.trimToSize();
        return lExtractedChilds;
    }

    //___________________________________________

    /** generates an xml header, using parameters.
     *
     *  @param  sVersion
     *          number of the xml version.
     *
     *  @param  sEncoding
     *          used file encoding.
     *
     *  @param  sPath
     *          name of the configuration root.
     *
     *  @param  sPackage
     *          name of the configuration package.
     *
     *  @param  bLanguagepack
     *          force creation of a special header,
     *          which is needed for language packs only.
     *
     *  @return [java.lang.String]
     *          the generated xml header.

*/
    public static java.lang.String generateHeader(java.lang.String sVersion     ,
                                                  java.lang.String sEncoding    ,
                                                  java.lang.String sPath        ,
                                                  java.lang.String sPackage     ,
                                                  boolean          bLanguagePack)
    {
        java.lang.StringBuffer sHeader = new java.lang.StringBuffer(256);

        if (bLanguagePack)
        {
            sHeader.append("<?xml version=\"");
            sHeader.append(sVersion);
            sHeader.append("\" encoding=\"");
            sHeader.append(sEncoding);
            sHeader.append("\"?>\n");
            sHeader.append("<oor:component-data oor:package=\"");
            sHeader.append(sPath);
            sHeader.append("\" oor:name=\"");
            sHeader.append(sPackage);
            sHeader.append("\" xmlns:install=\"http://openoffice.org/2004/installation\"");
            sHeader.append(" xmlns:oor=\"http://openoffice.org/2001/registry\"");
            sHeader.append(" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\"");
            sHeader.append(" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n");
        }
        else
        {
            sHeader.append("<?xml version=\"");
            sHeader.append(sVersion);
            sHeader.append("\" encoding=\"");
            sHeader.append(sEncoding);
            sHeader.append("\"?>\n<!DOCTYPE oor:component-data SYSTEM \"../../../../component-update.dtd\">\n");
            sHeader.append("<oor:component-data xmlns:oor=\"http://openoffice.org/2001/registry\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" oor:package=\"");
            sHeader.append(sPath);
            sHeader.append("\" oor:name=\"");
            sHeader.append(sPackage);
            sHeader.append("\">\n");
        }

        return sHeader.toString();
    }

    public static java.lang.String generateFooter()
    {
        return "</oor:component-data>\n";
    }
}