~ubuntu-branches/ubuntu/precise/xom/precise

« back to all changes in this revision

Viewing changes to src/nu/xom/samples/WrappingSerializer.java

  • Committer: Bazaar Package Importer
  • Author(s): Varun Hiremath
  • Date: 2007-11-25 15:50:40 UTC
  • Revision ID: james.westby@ubuntu.com-20071125155040-r75ikcqf1vu0cei7
Tags: upstream-1.1
ImportĀ upstreamĀ versionĀ 1.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright 2003, 2004 Elliotte Rusty Harold
 
2
   
 
3
   This library is free software; you can redistribute it and/or modify
 
4
   it under the terms of version 2.1 of the GNU Lesser General Public 
 
5
   License as published by the Free Software Foundation.
 
6
   
 
7
   This library is distributed in the hope that it will be useful,
 
8
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
9
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 
10
   GNU Lesser General Public License for more details.
 
11
   
 
12
   You should have received a copy of the GNU Lesser General Public
 
13
   License along with this library; if not, write to the 
 
14
   Free Software Foundation, Inc., 59 Temple Place, Suite 330, 
 
15
   Boston, MA 02111-1307  USA
 
16
   
 
17
   You can contact Elliotte Rusty Harold by sending e-mail to
 
18
   elharo@metalab.unc.edu. Please include the word "XOM" in the
 
19
   subject line. The XOM home page is located at http://www.xom.nu/
 
20
*/
 
21
 
 
22
package nu.xom.samples;
 
23
 
 
24
import java.io.IOException;
 
25
import java.io.OutputStream;
 
26
import java.io.UnsupportedEncodingException;
 
27
 
 
28
import nu.xom.Attribute;
 
29
import nu.xom.Builder;
 
30
import nu.xom.DocType;
 
31
import nu.xom.Document;
 
32
import nu.xom.Element;
 
33
import nu.xom.ParsingException;
 
34
import nu.xom.ProcessingInstruction;
 
35
import nu.xom.Serializer;
 
36
 
 
37
/**
 
38
 * <p>
 
39
 *   This class writes XML with a maximum line length,
 
40
 *   but only breaks lines inside tags. It does
 
41
 *   not change a document's infoset. 
 
42
 * </p>
 
43
 * 
 
44
 * @author Elliotte Rusty Harold
 
45
 * @version 1.0
 
46
 *
 
47
 */
 
48
public class WrappingSerializer extends Serializer {
 
49
 
 
50
    public WrappingSerializer(OutputStream out) {
 
51
        super(out);
 
52
    }
 
53
 
 
54
    public WrappingSerializer(OutputStream out, String encoding) 
 
55
      throws UnsupportedEncodingException {
 
56
        super(out, encoding);
 
57
    }
 
58
    
 
59
    private int maxLength;
 
60
    
 
61
    /**
 
62
     * <p>
 
63
     * Returns the preferred maximum line length.
 
64
     * </p>
 
65
     * 
 
66
     * @return the maximum line length.
 
67
     */
 
68
    public int getMaxLength() {
 
69
        return this.maxLength;
 
70
    }
 
71
 
 
72
    /**
 
73
     * <p>
 
74
     * Sets the suggested maximum line length for this serializer.
 
75
     * Setting this to 0 indicates that no automatic wrapping is to be
 
76
     * performed. When a line approaches this length, the serializer 
 
77
     * begins looking for opportunities to break the line. 
 
78
     * It will only break inside a tag, at places that do not
 
79
     * affect the infoset, such as between attribute values or
 
80
     * before the closing <code>></code>. In some circumstances the 
 
81
     * serializer may not be able to break the line before the maximum
 
82
     * length is reached. In this case,
 
83
     *  the serializer will exceed the maximum line length.
 
84
     * </p>
 
85
     * 
 
86
     * <p>
 
87
     * The default value for maxLength is 0, which is  
 
88
     * interpreted as no maximum line length. 
 
89
     * Setting this to a negative value just sets it to 0. 
 
90
     * </p>
 
91
     * 
 
92
     * @param maxLength the suggested maximum line length
 
93
     */
 
94
    public void setMaxLength(int maxLength) {
 
95
        this.maxLength = maxLength;
 
96
    }
 
97
 
 
98
    protected void writeStartTag(Element element) 
 
99
      throws IOException {
 
100
        writeRaw("<");
 
101
        writeRaw(element.getQualifiedName());
 
102
        writeAttributes(element);           
 
103
        writeNamespaceDeclarations(element);
 
104
        if (needsBreak()) breakLine();
 
105
        writeRaw(">");
 
106
    }
 
107
 
 
108
    protected void writeEmptyElementTag(Element element) 
 
109
      throws IOException {
 
110
        writeRaw("<");
 
111
        writeRaw(element.getQualifiedName());
 
112
        writeAttributes(element);           
 
113
        writeNamespaceDeclarations(element);
 
114
        if (needsBreak()) breakLine();
 
115
        writeRaw("/>");
 
116
    }
 
117
 
 
118
    public void writeEndTag(Element element) throws IOException {
 
119
        writeRaw("<");
 
120
        writeRaw(element.getQualifiedName());
 
121
        if (needsBreak()) breakLine();
 
122
        writeRaw("/>");
 
123
    }
 
124
 
 
125
    /**
 
126
     * <p>
 
127
     *   This method writes an attribute in the form 
 
128
     *   <code><i>name</i>="<i>value</i>"</code>.
 
129
     *   Characters in the attribute value are escaped as necessary.
 
130
     * </p>
 
131
     * 
 
132
     * @param attribute the <code>Attribute</code> to write
 
133
     * 
 
134
     * @throws IOException if the underlying <code>OutputStream</code>
 
135
     *     encounters an I/O error
 
136
     */
 
137
    protected void write(Attribute attribute) throws IOException {
 
138
        
 
139
        String name = attribute.getQualifiedName();
 
140
        if (maxLength <= this.getColumnNumber() + name.length()) {
 
141
            breakLine();   
 
142
        }
 
143
        writeRaw(name);
 
144
        if (this.getColumnNumber() == maxLength) {
 
145
            breakLine();   
 
146
        }
 
147
        writeRaw("=");
 
148
        String value = attribute.getValue();
 
149
        if (maxLength < value.length() + 2) {
 
150
            breakLine();   
 
151
        }
 
152
        writeRaw("\""); 
 
153
        writeAttributeValue(attribute.getValue());
 
154
        writeRaw("\"");  
 
155
        
 
156
    }
 
157
 
 
158
    /**
 
159
     * <p>
 
160
     *   This writes a namespace declaration in the form
 
161
     *   <code>xmlns:<i>prefix</i>="<i>uri</i>"</code> or 
 
162
     *   <code>xmlns="<i>uri</i>"</code>.
 
163
     * </p>
 
164
     * 
 
165
     * @param prefix the namespace prefix; the empty string for the
 
166
     *     default namespace
 
167
     * @param uri the namespace URI
 
168
     * 
 
169
     * @throws IOException if the underlying <code>OutputStream</code>
 
170
     *     encounters an I/O error
 
171
     */
 
172
    protected void writeNamespaceDeclaration(String prefix, String uri)
 
173
      throws IOException {
 
174
          
 
175
        String name;
 
176
        if ("".equals(prefix)) {
 
177
            name = "xmlns"; 
 
178
        }
 
179
        else {
 
180
            name = "xmlns:" + prefix; 
 
181
        } 
 
182
        if (this.maxLength < this.getColumnNumber() + name.length()) {
 
183
            breakLine();   
 
184
        }
 
185
        writeRaw(name);
 
186
 
 
187
        if (this.getColumnNumber() == maxLength) {
 
188
            breakLine();   
 
189
        }
 
190
        writeRaw("=");
 
191
        
 
192
        if (this.maxLength < this.getColumnNumber() + uri.length() + 2) {
 
193
            breakLine();   
 
194
        }
 
195
        writeRaw("\"");
 
196
        writeEscaped(uri);   
 
197
        writeRaw("\"");
 
198
    }
 
199
 
 
200
    private boolean needsBreak() {
 
201
        if (maxLength > 0) {
 
202
            return this.maxLength - this.getColumnNumber() <= 10;  
 
203
        }
 
204
        return false;
 
205
    }
 
206
 
 
207
    /**
 
208
     * <p>
 
209
     * Serializes a <code>ProcessingInstruction</code> object
 
210
     * onto the output stream. Line breaks may be inserted 
 
211
     * following the target.
 
212
     * </p>
 
213
     * 
 
214
     * <p>
 
215
     *   Since character and entity references are not resolved
 
216
     *   in processing instructions, processing instructions
 
217
     *   can only be serialized when all
 
218
     *   characters they contain are available in the current 
 
219
     *   encoding.
 
220
     * </p>
 
221
     * 
 
222
     * @param instruction the <code>ProcessingInstruction</code> 
 
223
     *     to serialize.
 
224
     * 
 
225
     * @throws IOException  if the underlying <code>OutputStream</code>
 
226
     *     encounters an I/O error
 
227
     */
 
228
    protected void write(ProcessingInstruction instruction) 
 
229
      throws IOException {
 
230
        writeRaw("<?");
 
231
        writeRaw(instruction.getTarget());
 
232
        String value = instruction.getValue();
 
233
        if (maxLength < getColumnNumber() + value.length() + 3) {
 
234
            breakLine();
 
235
        }
 
236
        else {
 
237
            writeRaw(" ");   
 
238
        }
 
239
        writeRaw(value);
 
240
        writeRaw("?>");      
 
241
    }
 
242
 
 
243
    /**
 
244
     * <p>
 
245
     * Serializes a <code>DocType</code> object
 
246
     * onto the output stream.
 
247
     * </p>
 
248
     * 
 
249
     * @param doctype the document type declaration to serialize
 
250
     * 
 
251
     * @throws IOException if the underlying 
 
252
     *     <code>OutputStream</code> encounters an I/O error
 
253
     */
 
254
    protected void write(DocType doctype) throws IOException {
 
255
        writeRaw("<!DOCTYPE");
 
256
        String rootElementName = doctype.getRootElementName();
 
257
        if (maxLength < getColumnNumber() + rootElementName.length() + 1) {
 
258
            breakLine();
 
259
        }
 
260
        else {
 
261
            writeRaw(" ");   
 
262
        }
 
263
        writeRaw(rootElementName);
 
264
        
 
265
        String publicID = doctype.getPublicID();
 
266
        String systemID = doctype.getSystemID();
 
267
        if (publicID != null) {
 
268
            if (maxLength < getColumnNumber() + 6) {
 
269
                breakLine();  
 
270
            }
 
271
            else {
 
272
                writeRaw(" ");   
 
273
            }
 
274
            writeRaw("PUBLIC"); 
 
275
              
 
276
            if (maxLength < getColumnNumber() + publicID.length() + 2) {
 
277
                breakLine();  
 
278
            }
 
279
            else {
 
280
                writeRaw(" ");   
 
281
            }
 
282
            writeRaw("\"");   
 
283
            writeRaw(publicID);
 
284
            writeRaw("\"");   
 
285
            
 
286
            if (maxLength < getColumnNumber() + systemID.length() + 2) {
 
287
                breakLine();  
 
288
            }
 
289
            else {
 
290
                writeRaw(" ");   
 
291
            }
 
292
            writeRaw("\"");   
 
293
            writeRaw(systemID);
 
294
            writeRaw("\"");   
 
295
        } 
 
296
        else if (systemID != null) {
 
297
            if (maxLength < getColumnNumber() + 6) {
 
298
                breakLine();  
 
299
            }
 
300
            else {
 
301
                writeRaw(" ");   
 
302
            }
 
303
            writeRaw("SYSTEM");    
 
304
            
 
305
            if (maxLength < getColumnNumber() + systemID.length() + 2) {
 
306
                breakLine();  
 
307
            }
 
308
            else {
 
309
                writeRaw(" ");   
 
310
            }
 
311
            writeRaw("\"");   
 
312
            writeRaw(systemID);
 
313
            writeRaw("\"");   
 
314
        } 
 
315
        
 
316
        String internalDTDSubset = doctype.getInternalDTDSubset();
 
317
        if (!internalDTDSubset.equals("")) {
 
318
            if (maxLength < getColumnNumber() + 2) {
 
319
                breakLine();  
 
320
            }
 
321
            else writeRaw(" ");
 
322
            writeRaw("[");    
 
323
            breakLine();
 
324
            writeRaw(internalDTDSubset); 
 
325
            breakLine();  
 
326
            writeRaw("]"); 
 
327
        }
 
328
 
 
329
        if (maxLength < getColumnNumber() + 1) {
 
330
            breakLine();  
 
331
        }
 
332
        writeRaw(">");
 
333
 
 
334
    } 
 
335
    
 
336
    public static void main(String[] args) {
 
337
  
 
338
        if (args.length <= 0) {
 
339
          System.out.println("Usage: java nu.xom.samples.WrappingSerializer URL");
 
340
          return;
 
341
        }
 
342
        
 
343
        try {
 
344
          Builder parser = new Builder();
 
345
          Document doc = parser.build(args[0]);
 
346
          Serializer serializer = new WrappingSerializer(System.out, "ISO-8859-1");
 
347
          serializer.setIndent(4);
 
348
          serializer.setMaxLength(24);
 
349
          serializer.setPreserveBaseURI(true);
 
350
          serializer.write(doc);
 
351
          serializer.flush();
 
352
        }
 
353
        catch (ParsingException ex) {
 
354
          System.out.println(args[0] + " is not well-formed.");
 
355
          System.out.println(ex.getMessage());
 
356
        }
 
357
        catch (IOException ex) { 
 
358
          System.out.println(
 
359
           "Due to an IOException, the parser could not read " 
 
360
           + args[0]
 
361
          ); 
 
362
        }
 
363
  
 
364
    }
 
365
 
 
366
}