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("&");
|
550 |
break;
|
551 |
case '<': |
552 |
dst.append("<");
|
553 |
break;
|
554 |
case '>': |
555 |
dst.append(">");
|
556 |
break;
|
557 |
case '\'': |
558 |
dst.append("'");
|
559 |
break;
|
560 |
case '\"': |
561 |
dst.append(""");
|
562 |
break;
|
563 |
case '\n': |
564 |
dst.append(s_newlineXmlEnc); |
565 |
break;
|
566 |
default:
|
567 |
dst.append(c); |
568 |
} |
569 |
} |
570 |
} |
571 |
} |