1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46 package org.codehaus.groovy.tools.xml;
47
48 import groovy.util.IndentPrinter;
49
50 import java.io.PrintWriter;
51 import java.util.HashMap;
52 import java.util.Map;
53
54 import org.w3c.dom.Attr;
55 import org.w3c.dom.Comment;
56 import org.w3c.dom.Document;
57 import org.w3c.dom.Element;
58 import org.w3c.dom.NamedNodeMap;
59 import org.w3c.dom.Node;
60 import org.w3c.dom.NodeList;
61 import org.w3c.dom.ProcessingInstruction;
62 import org.w3c.dom.Text;
63
64 /***
65 * A SAX handler for turning XML into Groovy scripts
66 *
67 * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
68 * @version $Revision: 1.5 $
69 */
70 public class DomToGroovy {
71
72 private IndentPrinter out;
73
74 public DomToGroovy(PrintWriter out) {
75 this(new IndentPrinter(out));
76 }
77
78 public DomToGroovy(IndentPrinter out) {
79 this.out = out;
80 }
81
82
83 public void print(Document document) {
84 printChildren(document, new HashMap());
85 }
86
87
88
89 protected void print(Node node, Map namespaces, boolean endWithComma) {
90 switch (node.getNodeType()) {
91 case Node.ELEMENT_NODE :
92 printElement((Element) node, namespaces, endWithComma);
93 break;
94 case Node.PROCESSING_INSTRUCTION_NODE :
95 printPI((ProcessingInstruction) node, endWithComma);
96 break;
97 case Node.TEXT_NODE :
98 printText((Text) node, endWithComma);
99 break;
100 case Node.COMMENT_NODE :
101 printComment((Comment) node, endWithComma);
102 break;
103 }
104 }
105
106 protected void printElement(Element element, Map namespaces, boolean endWithComma) {
107 namespaces = defineNamespaces(element, namespaces);
108
109 element.normalize();
110 printIndent();
111
112 String prefix = element.getPrefix();
113 if (prefix != null && prefix.length() > 0) {
114 print(prefix);
115 print(".");
116 }
117 print(getLocalName(element));
118
119 boolean hasAttributes = printAttributes(element);
120
121 NodeList list = element.getChildNodes();
122 int length = list.getLength();
123 if (length == 0) {
124 printEnd("", endWithComma);
125 }
126 else {
127 Node node = list.item(0);
128 if (length == 1 && node instanceof Text) {
129 Text textNode = (Text) node;
130 String text = getTextNodeData(textNode);
131 if (hasAttributes) {
132 print(" [\"");
133 print(text);
134 printEnd("\"]", endWithComma);
135 }
136 else {
137 print("(\"");
138 print(text);
139 printEnd("\")", endWithComma);
140 }
141 }
142 else if (mixedContent(list)) {
143 println(" [");
144 out.incrementIndent();
145 for (node = element.getFirstChild(); node != null; node = node.getNextSibling()) {
146 boolean useComma = node.getNextSibling() != null;
147 print(node, namespaces, useComma);
148 }
149 out.decrementIndent();
150 printIndent();
151 printEnd("]", endWithComma);
152 }
153 else {
154 println(" {");
155 out.incrementIndent();
156 printChildren(element, namespaces);
157 out.decrementIndent();
158 printIndent();
159 printEnd("}", endWithComma);
160 }
161 }
162 }
163
164 protected void printPI(ProcessingInstruction instruction, boolean endWithComma) {
165 printIndent();
166 print("xml.pi('");
167 print(instruction.getTarget());
168 print("', '");
169 print(instruction.getData());
170 printEnd("');", endWithComma);
171 }
172
173 protected void printComment(Comment comment, boolean endWithComma) {
174 String text = comment.getData().trim();
175 if (text.length() >0) {
176 printIndent();
177 print("/* ");
178 print(text);
179 printEnd(" */", endWithComma);
180 }
181 }
182
183 protected void printText(Text node, boolean endWithComma) {
184 String text = getTextNodeData(node);
185 if (text.length() > 0) {
186 printIndent();
187
188
189
190 print("\"");
191 print(text);
192 printEnd("\"", endWithComma);
193 }
194 }
195
196 protected Map defineNamespaces(Element element, Map namespaces) {
197 Map answer = null;
198 String prefix = element.getPrefix();
199 if (prefix != null && prefix.length() > 0 && !namespaces.containsKey(prefix)) {
200 answer = new HashMap(namespaces);
201 defineNamespace(answer, prefix, element.getNamespaceURI());
202 }
203 NamedNodeMap attributes = element.getAttributes();
204 int length = attributes.getLength();
205 for (int i = 0; i < length; i++) {
206 Attr attribute = (Attr) attributes.item(i);
207 prefix = attribute.getPrefix();
208 if (prefix != null && prefix.length() > 0 && !namespaces.containsKey(prefix)) {
209 if (answer == null) {
210 answer = new HashMap(namespaces);
211 }
212 defineNamespace(answer, prefix, attribute.getNamespaceURI());
213 }
214 }
215 return (answer != null) ? answer : namespaces;
216 }
217
218 protected void defineNamespace(Map namespaces, String prefix, String uri) {
219 namespaces.put(prefix, uri);
220 if (!prefix.equals("xmlns") && !prefix.equals("xml")) {
221 printIndent();
222 print(prefix);
223 print(" = xmlns.namespace('");
224 print(uri);
225 println("')");
226 }
227 }
228
229 protected boolean printAttributes(Element element) {
230 boolean hasAttribute = false;
231
232 NamedNodeMap attributes = element.getAttributes();
233 int length = attributes.getLength();
234 if (length > 0) {
235 StringBuffer buffer = new StringBuffer();
236 for (int i = 0; i < length; i++) {
237 Attr attribute = (Attr) attributes.item(i);
238 String prefix = attribute.getPrefix();
239 if (prefix != null && prefix.length() > 0) {
240 if (buffer.length() > 0) {
241 buffer.append(", ");
242 }
243 buffer.append(prefix);
244 buffer.append(".");
245 buffer.append(getLocalName(attribute));
246 buffer.append(":'");
247 buffer.append(attribute.getValue());
248 buffer.append("'");
249 }
250 }
251
252 print("(");
253 for (int i = 0; i < length; i++) {
254 Attr attribute = (Attr) attributes.item(i);
255 String prefix = attribute.getPrefix();
256 if (prefix == null || prefix.length() == 0) {
257 if (!hasAttribute) {
258 hasAttribute = true;
259 }
260 else {
261 print(", ");
262 }
263 print(getLocalName(attribute));
264 print(":'");
265 print(attribute.getValue());
266 print("'");
267 }
268 }
269 if (buffer.length() > 0) {
270 if (hasAttribute) {
271 print(", ");
272 }
273 print("xmlns=[");
274 print(buffer.toString());
275 print("]");
276 hasAttribute = true;
277 }
278 print(")");
279 }
280 return hasAttribute;
281 }
282
283 protected String getTextNodeData(Text node) {
284 String text = node.getData().trim();
285 return text;
286 }
287
288 protected boolean mixedContent(NodeList list) {
289 boolean hasText = false;
290 boolean hasElement = false;
291 for (int i = 0, size = list.getLength(); i < size; i++) {
292 Node node = list.item(i);
293 if (node instanceof Element) {
294 hasElement = true;
295 }
296 else if (node instanceof Text) {
297 String text = getTextNodeData((Text) node);
298 if (text.length() > 0) {
299 hasText = true;
300 }
301 }
302 }
303 return hasText && hasElement;
304 }
305
306 protected void printChildren(Node parent, Map namespaces) {
307 for (Node node = parent.getFirstChild(); node != null; node = node.getNextSibling()) {
308 print(node, namespaces, false);
309 }
310 }
311
312 protected String getLocalName(Node node) {
313 String answer = node.getLocalName();
314 if (answer == null) {
315 answer = node.getNodeName();
316 }
317 return answer.trim();
318 }
319
320 protected void printEnd(String text, boolean endWithComma) {
321 if (endWithComma) {
322 print(text);
323 println(",");
324 }
325 else {
326 println(text);
327 }
328 }
329
330 protected void println(String text) {
331 out.println(text); }
332
333 protected void print(String text) {
334 out.print(text);
335 }
336
337 protected void printIndent() {
338 out.printIndent();
339 }
340 }