KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > batik > svggen > XmlWriter


1 /*
2
3    Copyright 1999-2003 The Apache Software Foundation
4
5    Licensed under the Apache License, Version 2.0 (the "License");
6    you may not use this file except in compliance with the License.
7    You may obtain a copy of the License at
8
9        http://www.apache.org/licenses/LICENSE-2.0
10
11    Unless required by applicable law or agreed to in writing, software
12    distributed under the License is distributed on an "AS IS" BASIS,
13    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14    See the License for the specific language governing permissions and
15    limitations under the License.
16
17 */

18
19 package org.apache.batik.svggen;
20
21 import java.io.IOException JavaDoc;
22 import java.io.OutputStreamWriter JavaDoc;
23 import java.io.Writer JavaDoc;
24
25 import org.apache.batik.util.SVGConstants;
26 import org.w3c.dom.Attr JavaDoc;
27 import org.w3c.dom.CDATASection JavaDoc;
28 import org.w3c.dom.Comment JavaDoc;
29 import org.w3c.dom.Document JavaDoc;
30 import org.w3c.dom.Element JavaDoc;
31 import org.w3c.dom.NamedNodeMap JavaDoc;
32 import org.w3c.dom.Node JavaDoc;
33 import org.w3c.dom.NodeList JavaDoc;
34 import org.w3c.dom.Text JavaDoc;
35
36 /**
37  * Writes a Node as text output. Package access. This is
38  * *not* a full Xml printout implementation. It only covers
39  * what is needed by the Graphics2D class.
40  * The code for this class draws heavily from the work done
41  * for Sun's Project X by David Brownell.
42  *
43  * @author <a HREF="mailto:vincent.hardy@eng.sun.com">Vincent Hardy</a>
44  * @version $Id: XmlWriter.java,v 1.11 2005/02/17 11:47:05 deweese Exp $
45  */

46 class XmlWriter implements SVGConstants {
47
48     static private String JavaDoc EOL;
49     static private final String JavaDoc TAG_END = " />";
50     static private final String JavaDoc TAG_START = "</";
51     static private final String JavaDoc SPACE = " ";
52
53     static private final char[] SPACES =
54     { ' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',
55       ' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ' };
56     static private final int SPACES_LEN = SPACES.length;
57
58     static {
59         String JavaDoc temp;
60         try { temp = System.getProperty ("line.separator", "\n"); }
61         catch (SecurityException JavaDoc e) { temp = "\n"; }
62         EOL = temp;
63     }
64
65     static class IndentWriter extends Writer JavaDoc {
66         protected Writer JavaDoc proxied;
67         protected int indentLevel;
68         protected int column;
69
70         public IndentWriter(Writer JavaDoc proxied){
71             if (proxied == null)
72                 throw new SVGGraphics2DRuntimeException(ErrorConstants.ERR_PROXY);
73
74             this.proxied = proxied;
75         }
76
77         public void setIndentLevel(int indentLevel){
78             this.indentLevel = indentLevel;
79         }
80
81         public int getIndentLevel(){
82             return indentLevel;
83         }
84
85         public void printIndent() throws IOException JavaDoc{
86             proxied.write(EOL);
87             int temp = indentLevel;
88             while(temp > 0){
89                 if (temp > SPACES_LEN) {
90                     proxied.write(SPACES, 0, SPACES_LEN);
91                     temp -= SPACES_LEN;
92                 } else {
93                     proxied.write(SPACES, 0, temp);
94                     break;
95                 }
96             }
97             column = indentLevel;
98         }
99
100         public Writer JavaDoc getProxied(){
101             return proxied;
102         }
103
104         public int getColumn() { return column; }
105
106         public void write(int c) throws IOException JavaDoc {
107             column++;
108             proxied.write(c);
109         }
110
111         public void write(char cbuf[]) throws IOException JavaDoc {
112             column+=cbuf.length;
113             proxied.write(cbuf);
114         }
115
116         public void write(char cbuf[], int off, int len) throws IOException JavaDoc{
117             column+=len;
118             proxied.write(cbuf, off, len);
119         }
120
121         public void write(String JavaDoc str) throws IOException JavaDoc {
122             column+=str.length();
123             proxied.write(str);
124         }
125
126         public void write(String JavaDoc str, int off, int len) throws IOException JavaDoc {
127             column+=len;
128             proxied.write(str, off, len);
129         }
130
131         public void flush() throws IOException JavaDoc{
132             proxied.flush();
133         }
134
135         public void close() throws IOException JavaDoc{
136             column = -1;
137             proxied.close();
138         }
139     }
140
141     private static void writeXml(Attr JavaDoc attr, IndentWriter out)
142         throws IOException JavaDoc{
143         String JavaDoc name = attr.getName();
144         out.write (name);
145         out.write ("=\"");
146         writeChildrenXml(attr, out);
147         out.write ('"');
148     }
149
150     /**
151      * Writes the attribute's value.
152      */

153     private static void writeChildrenXml(Attr JavaDoc attr, IndentWriter out)
154         throws IOException JavaDoc {
155         char data[] = attr.getValue().toCharArray();
156         if (data == null) return;
157
158         int length = data.length;
159         int start=0, last=0;
160         while (last < length) {
161             char c = data[last];
162             switch (c) {
163             case '<':
164                 out.write (data, start, last - start);
165                 start = last + 1;
166                 out.write ("&lt;");
167                 break;
168             case '>':
169                 out.write (data, start, last - start);
170                 start = last + 1;
171                 out.write ("&gt;");
172                 break;
173             case '&':
174                 out.write (data, start, last - start);
175                 start = last + 1;
176                 out.write ("&amp;");
177                 break;
178             case '\'':
179                 out.write (data, start, last - start);
180                 start = last + 1;
181                 out.write ("&apos;");
182                 break;
183             case '"':
184                 out.write (data, start, last - start);
185                 start = last + 1;
186                 out.write ("&quot;");
187                 break;
188             default:
189             }
190             last++;
191         }
192         out.write (data, start, last - start);
193     }
194
195     /**
196      * Writes out the comment. Note that spaces may be added to
197      * prevent illegal comments: between consecutive dashes ("--")
198      * or if the last character of the comment is a dash.
199      */

200     private static void writeXml(Comment JavaDoc comment, IndentWriter out)
201         throws IOException JavaDoc {
202
203         char data[] = comment.getData().toCharArray();
204
205         if (data == null) {
206             out.write("<!---->");
207             return;
208         }
209
210         out.write ("<!--");
211         boolean sawDash = false;
212         int length = data.length;
213         int start=0, last=0;
214         
215         // "--" illegal in comments, insert a space.
216
while (last < length) {
217             char c = data[last];
218             if (c == '-') {
219                 if (sawDash) {
220                     out.write (data, start, last - start);
221                     start = last;
222                     out.write (' ');
223                 }
224                 sawDash = true;
225             } else {
226                 sawDash = false;
227             }
228             last++;
229         }
230         out.write (data, start, last - start);
231         if (sawDash)
232             out.write (' ');
233         out.write ("-->");
234     }
235
236     private static void writeXml(Text JavaDoc text, IndentWriter out)
237         throws IOException JavaDoc {
238         writeXml(text, out, false);
239     }
240
241     private static void writeXml(Text JavaDoc text, IndentWriter out, boolean trimWS)
242         throws IOException JavaDoc {
243         char data[] = text.getData().toCharArray();
244
245         // XXX saw this once -- being paranoid
246
if (data == null)
247             { System.err.println ("Null text data??"); return; }
248
249         int length = data.length;
250         int start = 0, last = 0;
251         if (trimWS) {
252             while (last < length) {
253                 char c = data[last];
254                 switch (c) {
255                 case ' ': case '\t': case '\n': case '\r': last++; continue;
256                 default: break;
257                 }
258                 break;
259             }
260             start = last;
261         }
262          
263         while (last < length) {
264             char c = data [last];
265
266             // escape markup delimiters only ... and do bulk
267
// writes wherever possible, for best performance
268
//
269
// note that character data can't have the CDATA
270
// termination "]]>"; escaping ">" suffices, and
271
// doing it very generally helps simple parsers
272
// that may not be quite correct.
273
//
274
switch(c) {
275             case ' ': case '\t': case '\n': case '\r':
276                 if (trimWS) {
277                     int wsStart = last; last++;
278                     while (last < length) {
279                         switch(data[last]) {
280                         case ' ': case '\t': case '\n': case '\r':
281                             last++; continue;
282                         default: break;
283                         }
284                         break;
285                     }
286                     if (last == length) {
287                         out.write(data, start, wsStart-start);
288                         return;
289                     } else {
290                         continue;
291                     }
292                 }
293                 break;
294             case '<': // not legal in char data
295
out.write (data, start, last - start);
296                 start = last + 1;
297                 out.write ("&lt;");
298                 break;
299             case '>': // see above
300
out.write (data, start, last - start);
301                 start = last + 1;
302                 out.write ("&gt;");
303                 break;
304             case '&': // not legal in char data
305
out.write (data, start, last - start);
306                 start = last + 1;
307                 out.write ("&amp;");
308                 break;
309             }
310             last++;
311         }
312         out.write (data, start, last - start);
313     }
314
315     private static void writeXml(CDATASection JavaDoc cdataSection, IndentWriter out)
316         throws IOException JavaDoc {
317         char[] data = cdataSection.getData().toCharArray();
318         if (data == null) {
319             out.write ("<![CDATA[]]>");
320             return;
321         }
322
323         out.write ("<![CDATA[");
324         int length = data.length;
325         int start = 0, last = 0;
326         while (last < length) {
327             char c = data [last];
328
329             // embedded "]]>" needs to be split into adjacent
330
// CDATA blocks ... can be split at either point
331
if (c == ']') {
332                 if (((last + 2) < data.length) &&
333                     (data [last + 1] == ']') &&
334                     (data [last + 2] == '>')) {
335                     out.write (data, start, last - start);
336                     start = last + 1;
337                     out.write ("]]]]><![CDATA[>");
338                     continue;
339                 }
340             }
341             last++;
342         }
343         out.write (data, start, last - start);
344         out.write ("]]>");
345     }
346
347     private static void writeXml(Element JavaDoc element, IndentWriter out)
348         throws IOException JavaDoc, SVGGraphics2DIOException {
349         out.write (TAG_START, 0, 1); // "<"
350
out.write (element.getTagName());
351
352         NamedNodeMap JavaDoc attributes = element.getAttributes();
353         if (attributes != null){
354             int nAttr = attributes.getLength();
355             for(int i=0; i<nAttr; i++){
356                 Attr JavaDoc attr = (Attr JavaDoc)attributes.item(i);
357                 out.write(' ');
358                 writeXml(attr, out);
359             }
360         }
361
362         //
363
// Write empty nodes as "<EMPTY />" to make sure version 3
364
// and 4 web browsers can read empty tag output as HTML.
365
// XML allows "<EMPTY/>" too, of course.
366
//
367
if (!element.hasChildNodes())
368             out.write(TAG_END, 0, 3); // " />"
369
else {
370             out.write(TAG_END, 2, 1); // ">"
371
writeChildrenXml(element, out);
372             out.write (TAG_START, 0, 2); // "</"
373
out.write (element.getTagName());
374             out.write (TAG_END, 2, 1); // ">"
375
}
376     }
377
378     private static void writeChildrenXml(Element JavaDoc element, IndentWriter out)
379         throws IOException JavaDoc, SVGGraphics2DIOException {
380         NodeList JavaDoc children = element.getChildNodes();
381         if (children == null)
382             return;
383
384         int length = children.getLength();
385         int oldIndent = 0;
386         oldIndent = out.getIndentLevel();
387         try {
388             out.setIndentLevel(oldIndent + 2);
389             for(int i = 0; i < length; i++) {
390                 if(children.item(i).getNodeType () != Node.TEXT_NODE) {
391                     out.printIndent ();
392                 }
393                 writeXml(children.item(i), out);
394             }
395         } finally {
396             out.setIndentLevel(oldIndent);
397             if (length > 0 && children.item(length-1).getNodeType() != Node.TEXT_NODE){
398                 out.printIndent(); // for ETag
399
}
400         }
401     }
402
403     private static void writeDocumentHeader(IndentWriter out)
404         throws IOException JavaDoc {
405         String JavaDoc encoding = null;
406
407         if (out.getProxied() instanceof OutputStreamWriter JavaDoc)
408             encoding =
409                 java2std(((OutputStreamWriter JavaDoc)out.getProxied()).getEncoding());
410
411         out.write ("<?xml version=\"1.0\"");
412         if (encoding != null) {
413             out.write (" encoding=\"");
414             out.write (encoding);
415             out.write ('\"');
416         }
417         out.write ("?>");
418         out.write (EOL);
419         out.write (EOL);
420
421         // Write DOCTYPE declaration here. Skip until specification is released.
422
out.write ("<!DOCTYPE svg PUBLIC '");
423         out.write (SVG_PUBLIC_ID);
424         out.write ("' '");
425         out.write (SVG_SYSTEM_ID);
426         out.write ("'");
427
428         out.write (">");
429         out.write (EOL);
430     }
431
432     private static void writeXml(Document JavaDoc document, IndentWriter out)
433         throws IOException JavaDoc, SVGGraphics2DIOException {
434         writeDocumentHeader(out);
435         NodeList JavaDoc childList = document.getChildNodes();
436         writeXml(childList, out);
437     }
438
439     private static void writeXml(NodeList JavaDoc childList, IndentWriter out)
440         throws IOException JavaDoc, SVGGraphics2DIOException {
441         int length = childList.getLength ();
442
443         if (length == 0)
444             return;
445         for (int i = 0; i < length; i++) {
446             Node JavaDoc child = childList.item(i);
447             writeXml(child, out);
448             out.write (EOL);
449         }
450     }
451
452     static String JavaDoc java2std(String JavaDoc encodingName) {
453         if (encodingName == null)
454             return null;
455
456         //
457
// ISO-8859-N is a common family of 8 bit encodings;
458
// N=1 is the eight bit subset of UNICODE, and there
459
// seem to be at least drafts for some N >10.
460
//
461
if (encodingName.startsWith ("ISO8859_")) // JDK 1.2
462
return "ISO-8859-" + encodingName.substring (8);
463         if (encodingName.startsWith ("8859_")) // JDK 1.1
464
return "ISO-8859-" + encodingName.substring (5);
465
466         // XXX seven bit encodings ISO-2022-* ...
467
// XXX EBCDIC encodings ...
468

469         if ("ASCII7".equalsIgnoreCase (encodingName)
470             || "ASCII".equalsIgnoreCase (encodingName))
471             return "US-ASCII";
472
473         //
474
// All XML parsers _must_ support UTF-8 and UTF-16.
475
// (UTF-16 ~= ISO-10646-UCS-2 plus surrogate pairs)
476
//
477
if ("UTF8".equalsIgnoreCase (encodingName))
478             return "UTF-8";
479         if (encodingName.startsWith ("Unicode"))
480             return "UTF-16";
481
482         //
483
// Some common Japanese character sets.
484
//
485
if ("SJIS".equalsIgnoreCase (encodingName))
486             return "Shift_JIS";
487         if ("JIS".equalsIgnoreCase (encodingName))
488             return "ISO-2022-JP";
489         if ("EUCJIS".equalsIgnoreCase (encodingName))
490             return "EUC-JP";
491
492         // else we can't really do anything
493
return encodingName;
494     }
495
496     public static void writeXml(Node JavaDoc node, Writer JavaDoc writer)
497         throws SVGGraphics2DIOException {
498         try {
499             IndentWriter out = null;
500             if (writer instanceof IndentWriter)
501                 out = (IndentWriter)writer;
502             else
503                 out = new IndentWriter(writer);
504
505             switch (node.getNodeType()) {
506             case Node.ATTRIBUTE_NODE:
507                 writeXml((Attr JavaDoc)node, out);
508                 break;
509             case Node.COMMENT_NODE:
510                 writeXml((Comment JavaDoc)node, out);
511                 break;
512             case Node.TEXT_NODE:
513                 writeXml((Text JavaDoc)node, out);
514                 break;
515             case Node.CDATA_SECTION_NODE:
516                 writeXml((CDATASection JavaDoc)node, out);
517                 break;
518             case Node.DOCUMENT_NODE:
519                 writeXml((Document JavaDoc)node, out);
520                 break;
521             case Node.DOCUMENT_FRAGMENT_NODE:
522                 writeDocumentHeader(out);
523                 NodeList JavaDoc childList = node.getChildNodes();
524                 writeXml(childList, out);
525                 break;
526             case Node.ELEMENT_NODE:
527                 writeXml((Element JavaDoc)node, out);
528                 break;
529             default:
530                 throw
531                     new SVGGraphics2DRuntimeException(ErrorConstants.INVALID_NODE+
532                                                       node.getClass().
533                                                       getName());
534             }
535         } catch (IOException JavaDoc io) {
536             throw new SVGGraphics2DIOException(io);
537         }
538     }
539 }
540
Popular Tags