Statistics
| Revision:

gvsig-sldtools / org.gvsig.sld / org.gvsig.sldsupport / org.gvsig.sldsupport.lib / org.gvsig.sldsupport.lib.impl / src / main / java / org / gvsig / sldsupport / impl / util / XmlBuilder.java @ 46

History | View | Annotate | Download (14.7 KB)

1
/*******************************************************************************
2
 *
3
 *   gvSIG. Desktop Geographic Information System.
4
 *  
5
 *   Copyright (C) 2007-2013 gvSIG Association.
6
 *  
7
 *   This program is free software; you can redistribute it and/or
8
 *   modify it under the terms of the GNU General Public License
9
 *   as published by the Free Software Foundation; either version 3
10
 *   of the License, or (at your option) any later version.
11
 *  
12
 *   This program is distributed in the hope that it will be useful,
13
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 *   GNU General Public License for more details.
16
 *  
17
 *   You should have received a copy of the GNU General Public License
18
 *   along with this program; if not, write to the Free Software
19
 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
20
 *   MA  02110-1301, USA.
21
 *  
22
 *   For any additional information, do not hesitate to contact us
23
 *   at info AT gvsig.com, or visit our website www.gvsig.com.
24
 *   
25
 *******************************************************************************/
26
package org.gvsig.sldsupport.impl.util;
27

    
28
import java.util.Map;
29
import java.util.Stack;
30

    
31
/**
32
 * Title: XmlBuilder
33
 * Description: Util class to build xml
34
 * 
35
 * @author laura
36
 */
37
public class XmlBuilder {
38

    
39
    // Default size of the XML document to be generated. Used to set the initial
40
    // capacity of m_xml.
41
    private static final int DEF_XMLDOC_SIZE = 256;
42

    
43
    // Pad unit.
44
    private static final String PAD = "  ";
45

    
46
    // Number of pre-defined pad strings, one for each pad
47
    // level (0..NUM_PADSTRINGS-1). Should at least be set to 10 for
48
    // performance.
49
    private static final int NUM_PADSTRINGS = 20;
50

    
51
    // Byte representation of '\n'.
52
    private static final byte[] NEWLINE_BYTES = "\n".getBytes();
53

    
54
    // Array of pad strings, each preceded by a '\n' character.
55
    private static String s_padStrings[];
56

    
57
    // XML-encoded newline character.
58
    private static String s_newlineXmlEnc;
59

    
60
    // XML document being built.
61
    private StringBuffer m_xml = new StringBuffer(DEF_XMLDOC_SIZE);
62

    
63
    // Scratch buffer exclusively used to encode strings.
64
    private StringBuffer m_encodeBuf = new StringBuffer(40);
65

    
66
    // Current pad string.
67
    private String m_pad = "";
68

    
69
    // If set, indentation will be added to the XML document.
70
    private boolean m_autoPad;
71

    
72
    // Stack of strings. The string at the top is the tag name of the current
73
    // XML block. The string immediately below the top is the tag name of the
74
    // XML block that immediately encloses the current XML block.
75
    protected Stack m_openElements = new Stack();
76

    
77
    // Current pad level (0, 1, 2, ...).
78
    private int m_padLevel = 0;
79

    
80
    private String encoding = "UTF-8";
81

    
82
    /*
83
     * Create the pad strings.
84
     */
85
    static {
86
        s_padStrings = new String[NUM_PADSTRINGS];
87
        String pad = "";
88

    
89
        for (int i = 0; i < NUM_PADSTRINGS; i++) {
90
            s_padStrings[i] = "\n" + pad;
91
            pad += PAD;
92
        }
93

    
94
        StringBuffer tmp = new StringBuffer();
95

    
96
        for (int i = 0; i < NEWLINE_BYTES.length; i++) {
97
            tmp.append("&#");
98
            tmp.append(NEWLINE_BYTES[i]);
99
            tmp.append(";");
100
        }
101

    
102
        s_newlineXmlEnc = tmp.toString();
103
    }
104

    
105
    /**
106
     * Constructor. The XML document to be generated will automatically be
107
     * indented.
108
     */
109
    public XmlBuilder() {
110
        this(true);
111
    }
112

    
113
    /**
114
     * Constructor.
115
     * 
116
     * @param autoPad
117
     *            if set, the XML document to be generated will
118
     *            automatically be indented.
119
     */
120
    public XmlBuilder(boolean autoPad) {
121
        m_autoPad = autoPad;
122
        m_padLevel = 0;
123
        m_pad = s_padStrings[m_padLevel];
124
    }
125

    
126
    /**
127
     * Reset this XmlBuilder.
128
     */
129
    public void reset() {
130
        m_padLevel = 0;
131
        m_pad = s_padStrings[m_padLevel];
132
        m_xml.setLength(0);
133
    }
134

    
135
    /**
136
     * Adds raw data to the xml.
137
     */
138
    public void writeRaw(String raw) {
139
        m_xml.append(raw);
140
    }
141

    
142
    /**
143
     * Adds a comment to the xml.
144
     */
145
    public void writeComment(String comment) {
146
        if (m_autoPad) {
147
            m_xml.append(m_pad);
148
        }
149

    
150
        m_xml.append("<!-- ");
151
        encode(comment, m_xml);
152
        m_xml.append(" -->\n");
153
    }
154

    
155
    /**
156
     * Writes the XML document header.
157
     */
158
    public void writeHeader() {
159
        // XML document header.
160
        final String HEADER =
161
            "<?xml version=\"1.0\" encoding=\"" + encoding + "\"?>\n";
162

    
163
        m_xml.append(HEADER);
164
    }
165

    
166
    /**
167
     * Sets the encoding used in the XML. By default UTF-8 is used.
168
     * 
169
     * @param encoding
170
     */
171
    public void setEncoding(String encoding) {
172
        this.encoding = encoding;
173
    }
174

    
175
    /**
176
     * Adds a opening and closing tag with charcter data.
177
     */
178
    public void writeTag(String name, String data) {
179
        name = encode(name);
180

    
181
        if (m_autoPad) {
182
            m_xml.append(m_pad);
183
        }
184

    
185
        m_xml.append("<");
186
        m_xml.append(name);
187
        m_xml.append(">");
188
        encode(data, m_xml);
189
        m_xml.append("</");
190
        m_xml.append(name);
191
        m_xml.append(">");
192
    }
193

    
194
    /**
195
     * Adds a opening and closing tag with attributes.
196
     */
197
    public void writeTag(String name, Map attributes) {
198
        if (m_autoPad) {
199
            m_xml.append(m_pad);
200
        }
201

    
202
        m_xml.append("<");
203
        encode(name, m_xml);
204
        m_xml.append(" ");
205

    
206
        Object elems[] = attributes.keySet().toArray();
207

    
208
        for (int i = 0; i < elems.length; i++) {
209
            String nm = (String) elems[i];
210
            String val = (String) attributes.get(nm);
211

    
212
            encode(nm, m_xml);
213
            m_xml.append("=\"");
214
            encode(val, m_xml);
215
            m_xml.append("\" ");
216
        }
217

    
218
        m_xml.append("/>");
219
    }
220

    
221
    /**
222
     * Adds a opening and closing tag with an attribute and character data.
223
     */
224
    public void writeTag(String name, String attr1Name, String attr1Value,
225
        String attr2Name, String attr2Value) {
226
        if (m_autoPad) {
227
            m_xml.append(m_pad);
228
        }
229

    
230
        m_xml.append("<");
231
        encode(name, m_xml);
232
        m_xml.append(" ");
233

    
234
        encode(attr1Name, m_xml);
235
        m_xml.append("=\"");
236
        encode(attr1Value, m_xml);
237
        m_xml.append("\" ");
238

    
239
        encode(attr2Name, m_xml);
240
        m_xml.append("=\"");
241
        encode(attr2Value, m_xml);
242
        m_xml.append("\" ");
243

    
244
        m_xml.append("/>");
245
    }
246

    
247
    /**
248
     * Adds a opening and closing tag with an attribute and character data.
249
     */
250
    public void writeTag(String name, String data, String attrName,
251
        String attrValue) {
252
        name = encode(name);
253

    
254
        if (m_autoPad) {
255
            m_xml.append(m_pad);
256
        }
257

    
258
        m_xml.append("<");
259
        m_xml.append(name);
260
        m_xml.append(" ");
261

    
262
        encode(attrName, m_xml);
263
        m_xml.append("=\"");
264
        encode(attrValue, m_xml);
265
        m_xml.append("\" ");
266

    
267
        m_xml.append(">");
268
        encode(data, m_xml);
269
        m_xml.append("</");
270
        m_xml.append(name);
271
        m_xml.append(">");
272
    }
273

    
274
    /**
275
     * Adds a opening and closing tag with two attributes and character data.
276
     */
277
    public void writeTag(String name, String data, String attr1Name,
278
        String attr1Value, String attr2Name, String attr2Value) {
279
        name = encode(name);
280

    
281
        if (m_autoPad) {
282
            m_xml.append(m_pad);
283
        }
284

    
285
        m_xml.append("<");
286
        m_xml.append(name);
287
        m_xml.append(" ");
288

    
289
        encode(attr1Name, m_xml);
290
        m_xml.append("=\"");
291
        encode(attr1Value, m_xml);
292
        m_xml.append("\" ");
293

    
294
        encode(attr2Name, m_xml);
295
        m_xml.append("=\"");
296
        encode(attr2Value, m_xml);
297
        m_xml.append("\" ");
298

    
299
        m_xml.append(">");
300
        encode(data, m_xml);
301
        m_xml.append("</");
302
        m_xml.append(name);
303
        m_xml.append(">");
304
    }
305

    
306
    /**
307
     * Adds a opening and closing tag with attributes and character data.
308
     */
309
    public void writeTag(String name, String data, Map attributes) {
310
        name = encode(name);
311

    
312
        if (m_autoPad) {
313
            m_xml.append(m_pad);
314
        }
315

    
316
        m_xml.append("<");
317
        m_xml.append(name);
318
        m_xml.append(" ");
319

    
320
        Object elems[] = attributes.keySet().toArray();
321

    
322
        for (int i = 0; i < elems.length; i++) {
323
            String nm = (String) elems[i];
324
            String val = (String) attributes.get(nm);
325

    
326
            encode(nm, m_xml);
327
            m_xml.append("=\"");
328
            encode(val, m_xml);
329
            m_xml.append("\" ");
330
        }
331

    
332
        m_xml.append(">");
333
        encode(data, m_xml);
334
        m_xml.append("</");
335
        m_xml.append(name);
336
        m_xml.append(">");
337
    }
338

    
339
    /**
340
     * Writes an opening tag
341
     */
342
    public void openTag(String name) {
343
        name = encode(name);
344

    
345
        m_openElements.push(name); // must be encoded!
346

    
347
        if (m_autoPad) {
348
            m_xml.append(m_pad);
349
        }
350

    
351
        m_xml.append("<");
352
        m_xml.append(name);
353
        m_xml.append(">");
354

    
355
        if (m_autoPad) {
356
            m_padLevel++;
357

    
358
            if (m_padLevel < NUM_PADSTRINGS) {
359
                m_pad = s_padStrings[m_padLevel];
360
            } else // really deep nesting level
361
            {
362
                m_pad += PAD;
363
            }
364
        }
365
    }
366

    
367
    /**
368
     * Writes an opening tag with one attribute.
369
     */
370
    public void openTag(String name, String attrName, String attrValue) {
371
        name = encode(name);
372

    
373
        m_openElements.push(name); // must be encoded!
374

    
375
        if (m_autoPad) {
376
            m_xml.append(m_pad);
377
        }
378

    
379
        m_xml.append("<");
380
        m_xml.append(name);
381
        m_xml.append(" ");
382

    
383
        encode(attrName, m_xml);
384
        m_xml.append("=\"");
385
        encode(attrValue, m_xml);
386
        m_xml.append("\" ");
387

    
388
        m_xml.append(">");
389

    
390
        if (m_autoPad) {
391
            m_padLevel++;
392

    
393
            if (m_padLevel < NUM_PADSTRINGS) {
394
                m_pad = s_padStrings[m_padLevel];
395
            } else // really deep nesting level
396
            {
397
                m_pad += PAD;
398
            }
399
        }
400
    }
401

    
402
    /**
403
     * Writes an opening tag with two attributes.
404
     */
405
    public void openTag(String name, String attr1Name, String attr1Value,
406
        String attr2Name, String attr2Value) {
407
        name = encode(name);
408

    
409
        m_openElements.push(name); // must be encoded!
410

    
411
        if (m_autoPad) {
412
            m_xml.append(m_pad);
413
        }
414

    
415
        m_xml.append("<");
416
        m_xml.append(name);
417
        m_xml.append(" ");
418

    
419
        encode(attr1Name, m_xml);
420
        m_xml.append("=\"");
421
        encode(attr1Value, m_xml);
422
        m_xml.append("\" ");
423

    
424
        encode(attr2Name, m_xml);
425
        m_xml.append("=\"");
426
        encode(attr2Value, m_xml);
427
        m_xml.append("\" ");
428

    
429
        m_xml.append(">");
430

    
431
        if (m_autoPad) {
432
            m_padLevel++;
433

    
434
            if (m_padLevel < NUM_PADSTRINGS) {
435
                m_pad = s_padStrings[m_padLevel];
436
            } else // really deep nesting level
437
            {
438
                m_pad += PAD;
439
            }
440
        }
441
    }
442

    
443
    /**
444
     * Writes an opening tag with attributes.
445
     */
446
    public void openTag(String name, Map attributes) {
447
        name = encode(name);
448

    
449
        m_openElements.push(name); // must be encoded!
450

    
451
        if (m_autoPad) {
452
            m_xml.append(m_pad);
453
        }
454

    
455
        m_xml.append("<");
456
        m_xml.append(name);
457
        m_xml.append(" ");
458

    
459
        Object elems[] = attributes.keySet().toArray();
460

    
461
        for (int i = 0; i < elems.length; i++) {
462
            String nm = (String) elems[i];
463
            String val = (String) attributes.get(nm);
464

    
465
            encode(nm, m_xml);
466
            m_xml.append("=\"");
467
            encode(val, m_xml);
468
            m_xml.append("\" ");
469
        }
470

    
471
        m_xml.append(">");
472

    
473
        if (m_autoPad) {
474
            m_padLevel++;
475

    
476
            if (m_padLevel < NUM_PADSTRINGS) {
477
                m_pad = s_padStrings[m_padLevel];
478
            } else // really deep nesting level
479
            {
480
                m_pad += PAD;
481
            }
482
        }
483
    }
484

    
485
    /**
486
     * Closes an open tag.
487
     */
488
    public void closeTag() {
489
        if (m_autoPad) {
490
            if (m_padLevel > 0) {
491
                m_padLevel--;
492
            }
493

    
494
            if (m_padLevel < NUM_PADSTRINGS) {
495
                m_pad = s_padStrings[m_padLevel];
496
            } else // really deep nesting level
497
            {
498
                int len = m_pad.length() - PAD.length();
499
                if (len > 0) {
500
                    m_pad = m_pad.substring(0, len);
501
                }
502
            }
503

    
504
            m_xml.append(m_pad);
505
        }
506

    
507
        String name = (String) m_openElements.pop(); // already encoded
508

    
509
        m_xml.append("</");
510
        m_xml.append(name);
511
        m_xml.append(">");
512
    }
513

    
514
    /**
515
     * Get the xml.
516
     */
517
    public String getXML() {
518
        return m_xml.toString();
519
    }
520

    
521
/**
522
   * Encodes the funny characters (e.g., '&', '<', '\"') in an XML
523
   * string.
524
   *
525
   * @param  src  XML string to encode.
526
   * @return the encoded string.
527
   */
528
    private String encode(String src) {
529
        m_encodeBuf.setLength(0); // clear old contents
530
        encode(src, m_encodeBuf);
531
        return m_encodeBuf.toString();
532
    }
533

    
534
/**
535
   * Encodes the funny characters (e.g., '&', '<', '\"') in an XML
536
   * string.
537
   *
538
   * @param  src  XML string to encode.
539
   * @param  dst  string buffer to write the encoded XML string to.
540
   */
541
    private static final void encode(String src, StringBuffer dst) {
542
        int n = src.length();
543

    
544
        for (int i = 0; i < n; i++) {
545
            char c = src.charAt(i);
546

    
547
            switch (c) {
548
            case '&':
549
                dst.append("&amp;");
550
                break;
551
            case '<':
552
                dst.append("&lt;");
553
                break;
554
            case '>':
555
                dst.append("&gt;");
556
                break;
557
            case '\'':
558
                dst.append("&apos;");
559
                break;
560
            case '\"':
561
                dst.append("&quot;");
562
                break;
563
            case '\n':
564
                dst.append(s_newlineXmlEnc);
565
                break;
566
            default:
567
                dst.append(c);
568
            }
569
        }
570
    }
571
}