Statistics
| Revision:

root / branches / v2_0_0_prep / libFMap_mapcontext / src / org / gvsig / fmap / mapcontext / rendering / legend / XmlBuilder.java @ 21200

History | View | Annotate | Download (12.4 KB)

1
package org.gvsig.fmap.mapcontext.rendering.legend;
2

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

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

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

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

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

    
28

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

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

    
35

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

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

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

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

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

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

    
56
  private String encoding = "UTF-8";
57

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

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

    
72
    StringBuffer tmp = new StringBuffer();
73

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

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

    
84

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

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

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

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

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

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

    
140
  /**
141
   * Writes the XML document header.
142
   */
143
  public void writeHeader()
144
  {
145
        // XML document header.
146
        final String HEADER = "<?xml version=\"1.0\" encoding=\""+encoding+"\"?>\n";
147

    
148
    m_xml.append(HEADER);
149
  }
150
  
151
  /**
152
   * Sets the encoding used in the XML. By default UTF-8 is used.
153
   * @param encoding
154
   */
155
  public void setEncoding(String encoding) {
156
          this.encoding  = encoding;
157
  }
158
  
159
  /**
160
  * Adds a opening and closing tag with charcter data.
161
  */
162
  public void writeTag(String name, String data)
163
  {
164
    name = encode(name);
165

    
166
    if (m_autoPad)
167
    {
168
      m_xml.append(m_pad);
169
    }
170

    
171
    m_xml.append("<");
172
    m_xml.append(name);
173
    m_xml.append(">");
174
    encode(data, m_xml);
175
    m_xml.append("</");
176
    m_xml.append(name);
177
    m_xml.append(">");
178
  }
179

    
180
  /**
181
  * Adds a opening and closing tag with attributes.
182
  */
183
  public void writeTag(String name, HashMap attributes)
184
  {
185
    if (m_autoPad)
186
    {
187
      m_xml.append(m_pad);
188
    }
189

    
190
    m_xml.append("<");
191
    encode(name, m_xml);
192
    m_xml.append(" ");
193

    
194
    Object elems[] = attributes.keySet().toArray();
195
    
196
    for (int i = 0; i < elems.length; i++)
197
    {
198
      String nm = (String)elems[i];
199
      String val = (String)attributes.get(nm);
200

    
201
      encode(nm, m_xml);
202
      m_xml.append("=\"");
203
      encode(val, m_xml);
204
      m_xml.append("\" ");
205
    }
206

    
207
    m_xml.append("/>");
208
  }
209

    
210
  /**
211
  * Adds a opening and closing tag with an attribute and character data.
212
  */
213
  public void writeTag(String name, String attr1Name, String attr1Value
214
          , String attr2Name, String attr2Value)
215
  {
216
    if (m_autoPad)
217
    {
218
      m_xml.append(m_pad);
219
    }
220

    
221
    m_xml.append("<");
222
    encode(name, m_xml);
223
    m_xml.append(" ");
224

    
225
    encode(attr1Name, m_xml);
226
    m_xml.append("=\"");
227
    encode(attr1Value, m_xml);
228
    m_xml.append("\" ");
229

    
230
    encode(attr2Name, m_xml);
231
    m_xml.append("=\"");
232
    encode(attr2Value, m_xml);
233
    m_xml.append("\" ");
234

    
235
    m_xml.append("/>");
236
  }
237

    
238
  /**
239
  * Adds a opening and closing tag with an attribute and character data.
240
  */
241
  public void writeTag(String name, String data, String attrName, String attrValue)
242
  {
243
    name = encode(name);
244

    
245
    if (m_autoPad)
246
    {
247
      m_xml.append(m_pad);
248
    }
249

    
250
    m_xml.append("<");
251
    m_xml.append(name);
252
    m_xml.append(" ");
253

    
254
    encode(attrName, m_xml);
255
    m_xml.append("=\"");
256
    encode(attrValue, m_xml);
257
    m_xml.append("\" ");
258

    
259
    m_xml.append(">");
260
    encode(data, m_xml);
261
    m_xml.append("</");
262
    m_xml.append(name);
263
    m_xml.append(">");
264
  }
265

    
266
  /**
267
  * Adds a opening and closing tag with two attributes and character data.
268
  */
269
  public void writeTag(String name, String data, String attr1Name, String attr1Value
270
                      , String attr2Name, String attr2Value)
271
  {
272
    name = encode(name);
273

    
274
    if (m_autoPad)
275
    {
276
      m_xml.append(m_pad);
277
    }
278

    
279
    m_xml.append("<");
280
    m_xml.append(name);
281
    m_xml.append(" ");
282

    
283
    encode(attr1Name, m_xml);
284
    m_xml.append("=\"");
285
    encode(attr1Value, m_xml);
286
    m_xml.append("\" ");
287

    
288
    encode(attr2Name, m_xml);
289
    m_xml.append("=\"");
290
    encode(attr2Value, m_xml);
291
    m_xml.append("\" ");
292

    
293
    m_xml.append(">");
294
    encode(data, m_xml);
295
    m_xml.append("</");
296
    m_xml.append(name);
297
    m_xml.append(">");
298
  }
299

    
300
  /**
301
  * Adds a opening and closing tag with attributes and character data.
302
  */
303
  public void writeTag(String name, String data, HashMap attributes)
304
  {
305
    name = encode(name);
306

    
307
    if (m_autoPad)
308
    {
309
      m_xml.append(m_pad);
310
    }
311

    
312
    m_xml.append("<");
313
    m_xml.append(name);
314
    m_xml.append(" ");
315

    
316
    Object elems[] = attributes.keySet().toArray();
317
    
318
    for (int i = 0; i < elems.length; i++)
319
    {
320
      String nm = (String)elems[i];
321
      String val = (String)attributes.get(nm);
322

    
323
      encode(nm, m_xml);
324
      m_xml.append("=\"");
325
      encode(val, m_xml);
326
      m_xml.append("\" ");
327
    }
328

    
329
    m_xml.append(">");
330
    encode(data, m_xml);
331
    m_xml.append("</");
332
    m_xml.append(name);
333
    m_xml.append(">");
334
  }
335

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

    
343
    m_openElements.push(name);              // must be encoded!
344

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

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

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

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

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

    
376
    m_openElements.push(name);              // must be encoded!
377

    
378
    if (m_autoPad)
379
    {
380
      m_xml.append(m_pad);
381
    }
382

    
383
    m_xml.append("<");
384
    m_xml.append(name);
385
    m_xml.append(" ");
386

    
387
    encode(attrName, m_xml);
388
    m_xml.append("=\"");
389
    encode(attrValue, m_xml);
390
    m_xml.append("\" ");
391

    
392
    m_xml.append(">");
393

    
394
    if (m_autoPad)
395
    {
396
      m_padLevel++;
397

    
398
      if (m_padLevel < NUM_PADSTRINGS)
399
      {
400
        m_pad = s_padStrings[m_padLevel];
401
      }
402
      else                                  // really deep nesting level
403
      {
404
        m_pad += PAD;
405
      }
406
    }
407
  }
408

    
409
  /**
410
  * Writes an opening tag with two attributes.
411
  */
412
  public void openTag(String name, String attr1Name, String attr1Value
413
                      , String attr2Name, String attr2Value)
414
  {
415
    name = encode(name);
416

    
417
    m_openElements.push(name);              // must be encoded!
418

    
419
    if (m_autoPad)
420
    {
421
      m_xml.append(m_pad);
422
    }
423

    
424
    m_xml.append("<");
425
    m_xml.append(name);
426
    m_xml.append(" ");
427

    
428
    encode(attr1Name, m_xml);
429
    m_xml.append("=\"");
430
    encode(attr1Value, m_xml);
431
    m_xml.append("\" ");
432

    
433
    encode(attr2Name, m_xml);
434
    m_xml.append("=\"");
435
    encode(attr2Value, m_xml);
436
    m_xml.append("\" ");
437

    
438
    m_xml.append(">");
439

    
440
    if (m_autoPad)
441
    {
442
      m_padLevel++;
443

    
444
      if (m_padLevel < NUM_PADSTRINGS)
445
      {
446
        m_pad = s_padStrings[m_padLevel];
447
      }
448
      else                                  // really deep nesting level
449
      {
450
        m_pad += PAD;
451
      }
452
    }
453
  }
454

    
455
  /**
456
  * Writes an opening tag with attributes.
457
  */
458
  public void openTag(String name, HashMap attributes)
459
  {
460
    name = encode(name);
461

    
462
    m_openElements.push(name);              // must be encoded!
463

    
464
    if (m_autoPad)
465
    {
466
      m_xml.append(m_pad);
467
    }
468

    
469
    m_xml.append("<");
470
    m_xml.append(name);
471
    m_xml.append(" ");
472

    
473
    Object elems[] = attributes.keySet().toArray();
474
    
475
    for (int i = 0; i < elems.length; i++)
476
    {
477
      String nm = (String)elems[i];
478
      String val = (String)attributes.get(nm);
479

    
480
      encode(nm, m_xml);
481
      m_xml.append("=\"");
482
      encode(val, m_xml);
483
      m_xml.append("\" ");
484
    }
485

    
486
    m_xml.append(">");
487

    
488
    if (m_autoPad)
489
    {
490
      m_padLevel++;
491

    
492
      if (m_padLevel < NUM_PADSTRINGS)
493
      {
494
        m_pad = s_padStrings[m_padLevel];
495
      }
496
      else                                  // really deep nesting level
497
      {
498
        m_pad += PAD;
499
      }
500
    }
501
  }
502

    
503
  /**
504
  * Closes an open tag.
505
  */
506
  public void closeTag()
507
  {
508
    if (m_autoPad)
509
    {
510
      if (m_padLevel > 0)
511
      {
512
        m_padLevel--;
513
      }
514

    
515
      if (m_padLevel < NUM_PADSTRINGS)
516
      {
517
        m_pad = s_padStrings[m_padLevel];
518
      }
519
      else                                  // really deep nesting level
520
      {
521
        int len = m_pad.length() - PAD.length();
522
        if (len > 0)
523
        {
524
          m_pad = m_pad.substring(0, len);
525
        }
526
      }
527

    
528
      m_xml.append(m_pad);
529
    }
530

    
531
        String name = (String)m_openElements.pop();      // already encoded
532

    
533
    m_xml.append("</");
534
    m_xml.append(name);
535
    m_xml.append(">");
536
  }
537

    
538
  /**
539
  * Get the xml.
540
  */
541
  public String getXML()
542
  {
543
    return m_xml.toString();
544
  }
545

    
546
  /**
547
   * Encodes the funny characters (e.g., '&', '<', '\"') in an XML
548
   * string.
549
   *
550
   * @param  src  XML string to encode.
551
   * @return the encoded string.
552
   */
553
  private String encode(String src)
554
  {
555
    m_encodeBuf.setLength(0);                        // clear old contents
556
    encode(src, m_encodeBuf);
557
    return m_encodeBuf.toString();
558
  }
559

    
560
  /**
561
   * Encodes the funny characters (e.g., '&', '<', '\"') in an XML
562
   * string.
563
   *
564
   * @param  src  XML string to encode.
565
   * @param  dst  string buffer to write the encoded XML string to.
566
   */
567
  private static final void encode(String src, StringBuffer dst)
568
  {
569
    int n = src.length();
570
          
571
    for (int i = 0; i < n; i++)
572
    {
573
      char c = src.charAt(i);
574

    
575
      switch(c)
576
      {
577
      case '&':
578
        dst.append("&amp;");
579
        break;
580
      case '<':
581
        dst.append("&lt;");
582
        break;
583
      case '>':
584
        dst.append("&gt;");
585
        break;
586
      case '\'':
587
        dst.append("&apos;");
588
        break;
589
      case '\"':
590
        dst.append("&quot;");
591
        break;
592
      case '\n':
593
        dst.append(s_newlineXmlEnc);
594
        break;
595
      default:
596
        dst.append(c); 
597
      }
598
    }
599
  }
600
}
601