1 /*
2 $Id: MarkupBuilder.java,v 1.8 2004/12/09 22:07:51 glaforge Exp $
3
4 Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
5
6 Redistribution and use of this software and associated documentation
7 ("Software"), with or without modification, are permitted provided
8 that the following conditions are met:
9
10 1. Redistributions of source code must retain copyright
11 statements and notices. Redistributions must also contain a
12 copy of this document.
13
14 2. Redistributions in binary form must reproduce the
15 above copyright notice, this list of conditions and the
16 following disclaimer in the documentation and/or other
17 materials provided with the distribution.
18
19 3. The name "groovy" must not be used to endorse or promote
20 products derived from this Software without prior written
21 permission of The Codehaus. For written permission,
22 please contact info@codehaus.org.
23
24 4. Products derived from this Software may not be called "groovy"
25 nor may "groovy" appear in their names without prior written
26 permission of The Codehaus. "groovy" is a registered
27 trademark of The Codehaus.
28
29 5. Due credit should be given to The Codehaus -
30 http://groovy.codehaus.org/
31
32 THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
33 ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
34 NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
35 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
36 THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
37 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
38 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
39 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
40 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
41 STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
42 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
43 OF THE POSSIBILITY OF SUCH DAMAGE.
44
45 */
46 package groovy.xml;
47
48 import groovy.util.BuilderSupport;
49 import groovy.util.IndentPrinter;
50
51 import java.io.PrintWriter;
52 import java.io.Writer;
53 import java.util.Iterator;
54 import java.util.Map;
55
56 /***
57 * A helper class for creating XML or HTML markup
58 *
59 * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
60 * @author Stefan Matthias Aust
61 * @version $Revision: 1.8 $
62 */
63 public class MarkupBuilder extends BuilderSupport {
64
65 private IndentPrinter out;
66 private boolean nospace;
67 private int state;
68 private boolean nodeIsEmpty = true;
69
70 public MarkupBuilder() {
71 this(new IndentPrinter());
72 }
73
74 public MarkupBuilder(PrintWriter writer) {
75 this(new IndentPrinter(writer));
76 }
77
78 public MarkupBuilder(Writer writer) {
79 this(new IndentPrinter(new PrintWriter(writer)));
80 }
81
82 public MarkupBuilder(IndentPrinter out) {
83 this.out = out;
84 }
85
86 protected void setParent(Object parent, Object child) {
87 }
88
89 /*
90 public Object getProperty(String property) {
91 if (property.equals("_")) {
92 nospace = true;
93 return null;
94 } else {
95 Object node = createNode(property);
96 nodeCompleted(getCurrent(), node);
97 return node;
98 }
99 }
100 */
101
102 protected Object createNode(Object name) {
103 toState(1, name);
104 return name;
105 }
106
107 protected Object createNode(Object name, Object value) {
108 toState(2, name);
109 out.print(">");
110 out.print(value.toString());
111 return name;
112 }
113
114 protected Object createNode(Object name, Map attributes, Object value) {
115 toState(1, name);
116 for (Iterator iter = attributes.entrySet().iterator(); iter.hasNext();) {
117 Map.Entry entry = (Map.Entry) iter.next();
118 out.print(" ");
119 print(transformName(entry.getKey().toString()));
120 out.print("='");
121 print(transformValue(entry.getValue().toString()));
122 out.print("'");
123 }
124 if (value != null)
125 {
126 nodeIsEmpty = false;
127 out.print(">" + value + "</" + name + ">");
128 }
129 return name;
130 }
131
132 protected Object createNode(Object name, Map attributes) {
133 return createNode(name, attributes, null);
134 }
135
136 protected void nodeCompleted(Object parent, Object node) {
137 toState(3, node);
138 out.flush();
139 }
140
141 protected void print(Object node) {
142 out.print(node == null ? "null" : node.toString());
143 }
144
145 protected Object getName(String methodName) {
146 return super.getName(transformName(methodName));
147 }
148
149 protected String transformName(String name) {
150 if (name.startsWith("_")) name = name.substring(1);
151 return name.replace('_', '-');
152 }
153
154 protected String transformValue(String value) {
155 return value.replaceAll("//'", """);
156 }
157
158 private void toState(int next, Object name) {
159 switch (state) {
160 case 0:
161 switch (next) {
162 case 1:
163 case 2:
164 out.print("<");
165 print(name);
166 break;
167 case 3:
168 throw new Error();
169 }
170 break;
171 case 1:
172 switch (next) {
173 case 1:
174 case 2:
175 out.print(">");
176 if (nospace) {
177 nospace = false;
178 } else {
179 out.println();
180 out.incrementIndent();
181 out.printIndent();
182 }
183 out.print("<");
184 print(name);
185 break;
186 case 3:
187 if (nodeIsEmpty) {
188 out.print(" />");
189 }
190 break;
191 }
192 break;
193 case 2:
194 switch (next) {
195 case 1:
196 case 2:
197 throw new Error();
198 case 3:
199 out.print("</");
200 print(name);
201 out.print(">");
202 break;
203 }
204 break;
205 case 3:
206 switch (next) {
207 case 1:
208 case 2:
209 if (nospace) {
210 nospace = false;
211 } else {
212 out.println();
213 out.printIndent();
214 }
215 out.print("<");
216 print(name);
217 break;
218 case 3:
219 if (nospace) {
220 nospace = false;
221 } else {
222 out.println();
223 out.decrementIndent();
224 out.printIndent();
225 }
226 out.print("</");
227 print(name);
228 out.print(">");
229 break;
230 }
231 break;
232 }
233 state = next;
234 }
235
236 }