~ubuntu-branches/ubuntu/jaunty/ant/jaunty-proposed

« back to all changes in this revision

Viewing changes to src/main/org/apache/tools/ant/util/DOMElementWriter.java

  • Committer: Bazaar Package Importer
  • Author(s): Stefan Gybas
  • Date: 2002-02-14 14:28:48 UTC
  • Revision ID: james.westby@ubuntu.com-20020214142848-2ww7ynmqkj31vlmn
Tags: upstream-1.4.1
ImportĀ upstreamĀ versionĀ 1.4.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * The Apache Software License, Version 1.1
 
3
 *
 
4
 * Copyright (c) 2000 The Apache Software Foundation.  All rights
 
5
 * reserved.
 
6
 *
 
7
 * Redistribution and use in source and binary forms, with or without
 
8
 * modification, are permitted provided that the following conditions
 
9
 * are met:
 
10
 *
 
11
 * 1. Redistributions of source code must retain the above copyright
 
12
 *    notice, this list of conditions and the following disclaimer.
 
13
 *
 
14
 * 2. Redistributions in binary form must reproduce the above copyright
 
15
 *    notice, this list of conditions and the following disclaimer in
 
16
 *    the documentation and/or other materials provided with the
 
17
 *    distribution.
 
18
 *
 
19
 * 3. The end-user documentation included with the redistribution, if
 
20
 *    any, must include the following acknowlegement:
 
21
 *       "This product includes software developed by the
 
22
 *        Apache Software Foundation (http://www.apache.org/)."
 
23
 *    Alternately, this acknowlegement may appear in the software itself,
 
24
 *    if and wherever such third-party acknowlegements normally appear.
 
25
 *
 
26
 * 4. The names "The Jakarta Project", "Ant", and "Apache Software
 
27
 *    Foundation" must not be used to endorse or promote products derived
 
28
 *    from this software without prior written permission. For written
 
29
 *    permission, please contact apache@apache.org.
 
30
 *
 
31
 * 5. Products derived from this software may not be called "Apache"
 
32
 *    nor may "Apache" appear in their names without prior written
 
33
 *    permission of the Apache Group.
 
34
 *
 
35
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 
36
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 
37
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 
38
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 
39
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 
40
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 
41
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 
42
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 
43
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 
44
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 
45
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 
46
 * SUCH DAMAGE.
 
47
 * ====================================================================
 
48
 *
 
49
 * This software consists of voluntary contributions made by many
 
50
 * individuals on behalf of the Apache Software Foundation.  For more
 
51
 * information on the Apache Software Foundation, please see
 
52
 * <http://www.apache.org/>.
 
53
 */
 
54
 
 
55
package org.apache.tools.ant.util;
 
56
 
 
57
import java.io.*;
 
58
import org.w3c.dom.*;
 
59
 
 
60
/**
 
61
 * Writes a DOM tree to a given Writer.
 
62
 *
 
63
 * <p>Utility class used by {@link org.apache.tools.ant.XmlLogger
 
64
 * XmlLogger} and
 
65
 * org.apache.tools.ant.taskdefs.optional.junit.XMLJUnitResultFormatter
 
66
 * XMLJUnitResultFormatter}.</p>
 
67
 *
 
68
 * @author The original author of XmlLogger
 
69
 * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a>
 
70
 * @author <a href="mailto:sbailliez@imediation.com">Stephane Bailliez</tt>
 
71
 */
 
72
public class DOMElementWriter {
 
73
 
 
74
    private static String lSep = System.getProperty("line.separator");
 
75
    private StringBuffer sb = new StringBuffer();
 
76
 
 
77
    /**
 
78
     * Don't try to be too smart but at least recognize the predefined
 
79
     * entities.
 
80
     */
 
81
    protected String[] knownEntities = {"gt", "amp", "lt", "apos", "quot"};
 
82
    
 
83
    /**
 
84
     * Writes a DOM tree to a stream.
 
85
     *
 
86
     * @param element the Root DOM element of the tree
 
87
     * @param out where to send the output
 
88
     * @param indent number of 
 
89
     * @param indentWith strings, 
 
90
     *       that should be used to indent the corresponding tag.
 
91
     */
 
92
    public void write(Element element, Writer out, int indent, 
 
93
                      String indentWith)
 
94
        throws IOException {
 
95
 
 
96
        // Write indent characters
 
97
        for (int i = 0; i < indent; i++) {
 
98
            out.write(indentWith);
 
99
        }
 
100
 
 
101
        // Write element
 
102
        out.write("<");
 
103
        out.write(element.getTagName());
 
104
 
 
105
        // Write attributes
 
106
        NamedNodeMap attrs = element.getAttributes();
 
107
        for (int i = 0; i < attrs.getLength(); i++) {
 
108
            Attr attr = (Attr) attrs.item(i);
 
109
            out.write(" ");
 
110
            out.write(attr.getName());
 
111
            out.write("=\"");
 
112
            out.write(encode(attr.getValue()));
 
113
            out.write("\"");
 
114
        }
 
115
        out.write(">");
 
116
 
 
117
        // Write child elements and text
 
118
        boolean hasChildren = false;
 
119
        NodeList children = element.getChildNodes();
 
120
        for (int i = 0; i < children.getLength(); i++) {
 
121
            Node child = children.item(i);
 
122
 
 
123
            switch (child.getNodeType()) {
 
124
                
 
125
            case Node.ELEMENT_NODE:
 
126
                if (!hasChildren) {
 
127
                    out.write(lSep);
 
128
                    hasChildren = true;
 
129
                }
 
130
                write((Element)child, out, indent + 1, indentWith);
 
131
                break;
 
132
                
 
133
            case Node.TEXT_NODE:
 
134
                out.write(encode(child.getNodeValue()));
 
135
                break;
 
136
                
 
137
            case Node.CDATA_SECTION_NODE:
 
138
                out.write("<![CDATA[");
 
139
                out.write(((Text)child).getData());
 
140
                out.write("]]>");
 
141
                break;
 
142
 
 
143
            case Node.ENTITY_REFERENCE_NODE:
 
144
                out.write('&');
 
145
                out.write(child.getNodeName());
 
146
                out.write(';');
 
147
                break;
 
148
 
 
149
            case Node.PROCESSING_INSTRUCTION_NODE:
 
150
                out.write("<?");
 
151
                out.write(child.getNodeName());
 
152
                String data = child.getNodeValue();
 
153
                if ( data != null && data.length() > 0 ) {
 
154
                    out.write(' ');
 
155
                    out.write(data);
 
156
                }
 
157
                out.write("?>");
 
158
                break;
 
159
            }
 
160
        }
 
161
 
 
162
        // If we had child elements, we need to indent before we close
 
163
        // the element, otherwise we're on the same line and don't need
 
164
        // to indent
 
165
        if (hasChildren) {
 
166
            for (int i = 0; i < indent; i++) {
 
167
                out.write(indentWith);
 
168
            }
 
169
        }
 
170
 
 
171
        // Write element close
 
172
        out.write("</");
 
173
        out.write(element.getTagName());
 
174
        out.write(">");
 
175
        out.write(lSep);
 
176
        out.flush();
 
177
    }
 
178
 
 
179
    /**
 
180
     * Escape &lt;, &gt; &amp; &apos; and &quot; as their entities.
 
181
     */
 
182
    public String encode(String value) {
 
183
        sb.setLength(0);
 
184
        for (int i=0; i<value.length(); i++) {
 
185
            char c = value.charAt(i);
 
186
            switch (c) {
 
187
            case '<':
 
188
                sb.append("&lt;");
 
189
                break;
 
190
            case '>':
 
191
                sb.append("&gt;");
 
192
                break;
 
193
            case '\'':
 
194
                sb.append("&apos;");
 
195
                break;
 
196
            case '\"':
 
197
                sb.append("&quot;");
 
198
                break;
 
199
            case '&':
 
200
                int nextSemi = value.indexOf(";", i);
 
201
                if (nextSemi < 0
 
202
                    || !isReference(value.substring(i, nextSemi+1))) {
 
203
                    sb.append("&amp;");
 
204
                } else {
 
205
                    sb.append('&');
 
206
                }
 
207
                break;
 
208
            default:
 
209
                sb.append(c);
 
210
                break;
 
211
            }
 
212
        }
 
213
        return sb.toString();
 
214
    }
 
215
 
 
216
    /**
 
217
     * Is the given argument a character or entity reference?
 
218
     */
 
219
    public boolean isReference(String ent) {
 
220
        if (!(ent.charAt(0) == '&') || !ent.endsWith(";")) {
 
221
            return false;
 
222
        }
 
223
 
 
224
        if (ent.charAt(1) == '#') {
 
225
            if (ent.charAt(2) == 'x') {
 
226
                try {
 
227
                    Integer.parseInt(ent.substring(3, ent.length()-1), 16);
 
228
                    return true;
 
229
                } catch (NumberFormatException nfe) {
 
230
                    return false;
 
231
                }
 
232
            } else {
 
233
                try {
 
234
                    Integer.parseInt(ent.substring(2, ent.length()-1));
 
235
                    return true;
 
236
                } catch (NumberFormatException nfe) {
 
237
                    return false;
 
238
                }
 
239
            }
 
240
        }
 
241
 
 
242
        String name = ent.substring(1, ent.length() - 1);
 
243
        for (int i=0; i<knownEntities.length; i++) {
 
244
            if (name.equals(knownEntities[i])) {
 
245
                return true;
 
246
            }
 
247
        }
 
248
        return false;
 
249
    }
 
250
}