Statistics
| Revision:

svn-gvsig-desktop / trunk / libraries / libFMap / src / com / iver / cit / gvsig / fmap / rendering / XmlBuilder.java @ 4111

History | View | Annotate | Download (11.5 KB)

1
package com.iver.cit.gvsig.fmap.rendering;
2

    
3
import java.util.Stack;
4
import java.util.HashMap;
5

    
6
/**
7
 * Title:         XmlBuilder
8
 * Description:   Util class to build xml
9
 */
10
public class XmlBuilder
11
{
12
  // Default size of the XML document to be generated. Used to set the initial
13
  // capacity of m_xml.
14
  private static final int DEF_XMLDOC_SIZE = 256;
15

    
16
  // Pad unit.
17
  private static final String PAD = "  ";
18

    
19
  // XML document header.
20
  private static final String HEADER = "<?xml version=\"1.0\"?>\n";
21

    
22
  // Number of pre-defined pad strings, one for each pad
23
  // level (0..NUM_PADSTRINGS-1). Should at least be set to 10 for performance.
24
  private static final int NUM_PADSTRINGS = 20;
25

    
26
  // Byte representation of '\n'.
27
  private static final byte[] NEWLINE_BYTES = "\n".getBytes();
28

    
29

    
30
  // Array of pad strings, each preceded by a '\n' character.
31
  private static String s_padStrings[];
32

    
33
  // XML-encoded newline character.
34
  private static String s_newlineXmlEnc;
35

    
36

    
37
  // XML document being built.
38
  private StringBuffer m_xml = new StringBuffer(DEF_XMLDOC_SIZE);
39

    
40
  // Scratch buffer exclusively used to encode strings.
41
  private StringBuffer m_encodeBuf = new StringBuffer(40);
42

    
43
  // Current pad string.
44
  private String m_pad = "";
45

    
46
  // If set, indentation will be added to the XML document.
47
  private boolean m_autoPad;
48

    
49
  // Stack of strings. The string at the top is the tag name of the current
50
  // XML block. The string immediately below the top is the tag name of the
51
  // XML block that immediately encloses the current XML block.
52
  protected Stack m_openElements = new Stack();
53

    
54
  // Current pad level (0, 1, 2, ...).
55
  private int m_padLevel = 0;
56

    
57
  /*
58
   * Create the pad strings.
59
   */
60
  static
61
  {
62
    s_padStrings = new String[NUM_PADSTRINGS];
63
    String pad = "";
64

    
65
    for (int i = 0; i < NUM_PADSTRINGS; i++)
66
    {
67
      s_padStrings[i] = "\n" + pad;
68
      pad += PAD;
69
    }
70

    
71
    StringBuffer tmp = new StringBuffer();
72

    
73
    for (int i = 0; i < NEWLINE_BYTES.length; i++)
74
    {
75
      tmp.append("&#");
76
      tmp.append(NEWLINE_BYTES[i]);
77
      tmp.append(";");
78
    }
79

    
80
    s_newlineXmlEnc = tmp.toString();
81
  }
82

    
83

    
84
  /**
85
  * Constructor. The XML document to be generated will automatically be
86
  * indented.
87
  */
88
  public XmlBuilder()
89
  {
90
    this(true);
91
  }
92

    
93
  /**
94
  * Constructor.
95
  *
96
  * @param  autoPad  if set, the XML document to be generated will
97
  *                  automatically be indented.
98
  */
99
  public XmlBuilder(boolean autoPad)
100
  {
101
    m_autoPad = autoPad;
102
    m_padLevel = 0;
103
    m_pad = s_padStrings[m_padLevel];
104
  }
105

    
106
  /**
107
   * Reset this XmlBuilder.
108
   */
109
  public void reset()
110
  {
111
    m_padLevel = 0;
112
    m_pad = s_padStrings[m_padLevel];
113
    m_xml.setLength(0);
114
  }
115

    
116
  /**
117
  * Adds raw data to the xml.
118
  */
119
  public void writeRaw(String raw)
120
  {
121
    m_xml.append(raw);
122
  }
123

    
124
  /**
125
  * Adds a comment to the xml.
126
  */
127
  public void writeComment(String comment)
128
  {
129
    if (m_autoPad)
130
    {
131
      m_xml.append(m_pad);
132
    }
133

    
134
    m_xml.append("<!-- ");
135
    encode(comment, m_xml);
136
    m_xml.append(" -->\n");
137
  }
138

    
139
  /**
140
   * Writes the XML document header.
141
   */
142
  public void writeHeader()
143
  {
144
    m_xml.append(HEADER);
145
  }
146
  
147
  /**
148
  * Adds a opening and closing tag with charcter data.
149
  */
150
  public void writeTag(String name, String data)
151
  {
152
    name = encode(name);
153

    
154
    if (m_autoPad)
155
    {
156
      m_xml.append(m_pad);
157
    }
158

    
159
    m_xml.append("<");
160
    m_xml.append(name);
161
    m_xml.append(">");
162
    encode(data, m_xml);
163
    m_xml.append("</");
164
    m_xml.append(name);
165
    m_xml.append(">");
166
  }
167

    
168
  /**
169
  * Adds a opening and closing tag with attributes.
170
  */
171
  public void writeTag(String name, HashMap attributes)
172
  {
173
    if (m_autoPad)
174
    {
175
      m_xml.append(m_pad);
176
    }
177

    
178
    m_xml.append("<");
179
    encode(name, m_xml);
180
    m_xml.append(" ");
181

    
182
    Object elems[] = attributes.keySet().toArray();
183
    
184
    for (int i = 0; i < elems.length; i++)
185
    {
186
      String nm = (String)elems[i];
187
      String val = (String)attributes.get(nm);
188

    
189
      encode(nm, m_xml);
190
      m_xml.append("=\"");
191
      encode(val, m_xml);
192
      m_xml.append("\" ");
193
    }
194

    
195
    m_xml.append("/>");
196
  }
197

    
198
  /**
199
  * Adds a opening and closing tag with an attribute and character data.
200
  */
201
  public void writeTag(String name, String attr1Name, String attr1Value
202
          , String attr2Name, String attr2Value)
203
  {
204
    if (m_autoPad)
205
    {
206
      m_xml.append(m_pad);
207
    }
208

    
209
    m_xml.append("<");
210
    encode(name, m_xml);
211
    m_xml.append(" ");
212

    
213
    encode(attr1Name, m_xml);
214
    m_xml.append("=\"");
215
    encode(attr1Value, m_xml);
216
    m_xml.append("\" ");
217

    
218
    encode(attr2Name, m_xml);
219
    m_xml.append("=\"");
220
    encode(attr2Value, m_xml);
221
    m_xml.append("\" ");
222

    
223
    m_xml.append("/>");
224
  }
225

    
226
  /**
227
  * Adds a opening and closing tag with an attribute and character data.
228
  */
229
  public void writeTag(String name, String data, String attrName, String attrValue)
230
  {
231
    name = encode(name);
232

    
233
    if (m_autoPad)
234
    {
235
      m_xml.append(m_pad);
236
    }
237

    
238
    m_xml.append("<");
239
    m_xml.append(name);
240
    m_xml.append(" ");
241

    
242
    encode(attrName, m_xml);
243
    m_xml.append("=\"");
244
    encode(attrValue, m_xml);
245
    m_xml.append("\" ");
246

    
247
    m_xml.append(">");
248
    encode(data, m_xml);
249
    m_xml.append("</");
250
    m_xml.append(name);
251
    m_xml.append(">");
252
  }
253

    
254
  /**
255
  * Adds a opening and closing tag with two attributes and character data.
256
  */
257
  public void writeTag(String name, String data, String attr1Name, String attr1Value
258
                      , String attr2Name, String attr2Value)
259
  {
260
    name = encode(name);
261

    
262
    if (m_autoPad)
263
    {
264
      m_xml.append(m_pad);
265
    }
266

    
267
    m_xml.append("<");
268
    m_xml.append(name);
269
    m_xml.append(" ");
270

    
271
    encode(attr1Name, m_xml);
272
    m_xml.append("=\"");
273
    encode(attr1Value, m_xml);
274
    m_xml.append("\" ");
275

    
276
    encode(attr2Name, m_xml);
277
    m_xml.append("=\"");
278
    encode(attr2Value, m_xml);
279
    m_xml.append("\" ");
280

    
281
    m_xml.append(">");
282
    encode(data, m_xml);
283
    m_xml.append("</");
284
    m_xml.append(name);
285
    m_xml.append(">");
286
  }
287

    
288
  /**
289
  * Adds a opening and closing tag with attributes and character data.
290
  */
291
  public void writeTag(String name, String data, HashMap attributes)
292
  {
293
    name = encode(name);
294

    
295
    if (m_autoPad)
296
    {
297
      m_xml.append(m_pad);
298
    }
299

    
300
    m_xml.append("<");
301
    m_xml.append(name);
302
    m_xml.append(" ");
303

    
304
    Object elems[] = attributes.keySet().toArray();
305
    
306
    for (int i = 0; i < elems.length; i++)
307
    {
308
      String nm = (String)elems[i];
309
      String val = (String)attributes.get(nm);
310

    
311
      encode(nm, m_xml);
312
      m_xml.append("=\"");
313
      encode(val, m_xml);
314
      m_xml.append("\" ");
315
    }
316

    
317
    m_xml.append(">");
318
    encode(data, m_xml);
319
    m_xml.append("</");
320
    m_xml.append(name);
321
    m_xml.append(">");
322
  }
323

    
324
  /**
325
  * Writes an opening tag
326
  */
327
  public void openTag(String name)
328
  {
329
    name = encode(name);
330

    
331
    m_openElements.push(name);              // must be encoded!
332

    
333
    if (m_autoPad)
334
    {
335
      m_xml.append(m_pad);
336
    }
337

    
338
    m_xml.append("<");
339
    m_xml.append(name);
340
    m_xml.append(">");
341

    
342
    if (m_autoPad)
343
    {
344
      m_padLevel++;
345

    
346
      if (m_padLevel < NUM_PADSTRINGS)
347
      {
348
        m_pad = s_padStrings[m_padLevel];
349
      }
350
      else                                  // really deep nesting level
351
      {
352
        m_pad += PAD;
353
      }
354
    }
355
  }
356

    
357
  /**
358
  * Writes an opening tag with one attribute.
359
  */
360
  public void openTag(String name, String attrName, String attrValue)
361
  {
362
    name = encode(name);
363

    
364
    m_openElements.push(name);              // must be encoded!
365

    
366
    if (m_autoPad)
367
    {
368
      m_xml.append(m_pad);
369
    }
370

    
371
    m_xml.append("<");
372
    m_xml.append(name);
373
    m_xml.append(" ");
374

    
375
    encode(attrName, m_xml);
376
    m_xml.append("=\"");
377
    encode(attrValue, m_xml);
378
    m_xml.append("\" ");
379

    
380
    m_xml.append(">");
381

    
382
    if (m_autoPad)
383
    {
384
      m_padLevel++;
385

    
386
      if (m_padLevel < NUM_PADSTRINGS)
387
      {
388
        m_pad = s_padStrings[m_padLevel];
389
      }
390
      else                                  // really deep nesting level
391
      {
392
        m_pad += PAD;
393
      }
394
    }
395
  }
396

    
397
  /**
398
  * Writes an opening tag with two attributes.
399
  */
400
  public void openTag(String name, String attr1Name, String attr1Value
401
                      , String attr2Name, String attr2Value)
402
  {
403
    name = encode(name);
404

    
405
    m_openElements.push(name);              // must be encoded!
406

    
407
    if (m_autoPad)
408
    {
409
      m_xml.append(m_pad);
410
    }
411

    
412
    m_xml.append("<");
413
    m_xml.append(name);
414
    m_xml.append(" ");
415

    
416
    encode(attr1Name, m_xml);
417
    m_xml.append("=\"");
418
    encode(attr1Value, m_xml);
419
    m_xml.append("\" ");
420

    
421
    encode(attr2Name, m_xml);
422
    m_xml.append("=\"");
423
    encode(attr2Value, m_xml);
424
    m_xml.append("\" ");
425

    
426
    m_xml.append(">");
427

    
428
    if (m_autoPad)
429
    {
430
      m_padLevel++;
431

    
432
      if (m_padLevel < NUM_PADSTRINGS)
433
      {
434
        m_pad = s_padStrings[m_padLevel];
435
      }
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, HashMap attributes)
447
  {
448
    name = encode(name);
449

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

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

    
457
    m_xml.append("<");
458
    m_xml.append(name);
459
    m_xml.append(" ");
460

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

    
468
      encode(nm, m_xml);
469
      m_xml.append("=\"");
470
      encode(val, m_xml);
471
      m_xml.append("\" ");
472
    }
473

    
474
    m_xml.append(">");
475

    
476
    if (m_autoPad)
477
    {
478
      m_padLevel++;
479

    
480
      if (m_padLevel < NUM_PADSTRINGS)
481
      {
482
        m_pad = s_padStrings[m_padLevel];
483
      }
484
      else                                  // really deep nesting level
485
      {
486
        m_pad += PAD;
487
      }
488
    }
489
  }
490

    
491
  /**
492
  * Closes an open tag.
493
  */
494
  public void closeTag()
495
  {
496
    if (m_autoPad)
497
    {
498
      if (m_padLevel > 0)
499
      {
500
        m_padLevel--;
501
      }
502

    
503
      if (m_padLevel < NUM_PADSTRINGS)
504
      {
505
        m_pad = s_padStrings[m_padLevel];
506
      }
507
      else                                  // really deep nesting level
508
      {
509
        int len = m_pad.length() - PAD.length();
510
        if (len > 0)
511
        {
512
          m_pad = m_pad.substring(0, len);
513
        }
514
      }
515

    
516
      m_xml.append(m_pad);
517
    }
518

    
519
        String name = (String)m_openElements.pop();      // already encoded
520

    
521
    m_xml.append("</");
522
    m_xml.append(name);
523
    m_xml.append(">");
524
  }
525

    
526
  /**
527
  * Get the xml.
528
  */
529
  public String getXML()
530
  {
531
    return m_xml.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
   * @return the encoded string.
540
   */
541
  private String encode(String src)
542
  {
543
    m_encodeBuf.setLength(0);                        // clear old contents
544
    encode(src, m_encodeBuf);
545
    return m_encodeBuf.toString();
546
  }
547

    
548
  /**
549
   * Encodes the funny characters (e.g., '&', '<', '\"') in an XML
550
   * string.
551
   *
552
   * @param  src  XML string to encode.
553
   * @param  dst  string buffer to write the encoded XML string to.
554
   */
555
  private static final void encode(String src, StringBuffer dst)
556
  {
557
    int n = src.length();
558
          
559
    for (int i = 0; i < n; i++)
560
    {
561
      char c = src.charAt(i);
562

    
563
      switch(c)
564
      {
565
      case '&':
566
        dst.append("&amp;");
567
        break;
568
      case '<':
569
        dst.append("&lt;");
570
        break;
571
      case '>':
572
        dst.append("&gt;");
573
        break;
574
      case '\'':
575
        dst.append("&apos;");
576
        break;
577
      case '\"':
578
        dst.append("&quot;");
579
        break;
580
      case '\n':
581
        dst.append(s_newlineXmlEnc);
582
        break;
583
      default:
584
        dst.append(c); 
585
      }
586
    }
587
  }
588
}
589