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 James Strachan
68 * @author paulk
69 */
70 public class DomToGroovy {
71
72 private IndentPrinter out;
73
74 public DomToGroovy(PrintWriter out) {
75 this(new IndentPrinter(out));
76 }
77
78
79 public DomToGroovy(IndentPrinter out) {
80 this.out = out;
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(hasAttributes ? ")" : "()", endWithComma);
125 } else {
126 Node node = list.item(0);
127 if (length == 1 && node instanceof Text) {
128 Text textNode = (Text) node;
129 String text = getTextNodeData(textNode);
130 if (hasAttributes) print(", '");
131 else print("('");
132 print(text);
133 printEnd("')", endWithComma);
134 } else if (mixedContent(list)) {
135 println(" [");
136 out.incrementIndent();
137 for (node = element.getFirstChild(); node != null; node = node.getNextSibling()) {
138 boolean useComma = node.getNextSibling() != null;
139 print(node, namespaces, useComma);
140 }
141 out.decrementIndent();
142 printIndent();
143 printEnd("]", endWithComma);
144 } else {
145 println(") {");
146 out.incrementIndent();
147 printChildren(element, namespaces);
148 out.decrementIndent();
149 printIndent();
150 printEnd("}", endWithComma);
151 }
152 }
153 }
154
155 protected void printPI(ProcessingInstruction instruction, boolean endWithComma) {
156 printIndent();
157 print("xml.pi('");
158 print(instruction.getTarget());
159 print("', '");
160 print(instruction.getData());
161 printEnd("');", endWithComma);
162 }
163
164 protected void printComment(Comment comment, boolean endWithComma) {
165 String text = comment.getData().trim();
166 if (text.length() >0) {
167 printIndent();
168 print("/* ");
169 print(text);
170 printEnd(" */", endWithComma);
171 }
172 }
173
174 protected void printText(Text node, boolean endWithComma) {
175 String text = getTextNodeData(node);
176 if (text.length() > 0) {
177 printIndent();
178
179
180
181 print("'");
182 print(text);
183 printEnd("'", endWithComma);
184 }
185 }
186
187 protected Map defineNamespaces(Element element, Map namespaces) {
188 Map answer = null;
189 String prefix = element.getPrefix();
190 if (prefix != null && prefix.length() > 0 && !namespaces.containsKey(prefix)) {
191 answer = new HashMap(namespaces);
192 defineNamespace(answer, prefix, element.getNamespaceURI());
193 }
194 NamedNodeMap attributes = element.getAttributes();
195 int length = attributes.getLength();
196 for (int i = 0; i < length; i++) {
197 Attr attribute = (Attr) attributes.item(i);
198 prefix = attribute.getPrefix();
199 if (prefix != null && prefix.length() > 0 && !namespaces.containsKey(prefix)) {
200 if (answer == null) {
201 answer = new HashMap(namespaces);
202 }
203 defineNamespace(answer, prefix, attribute.getNamespaceURI());
204 }
205 }
206 return (answer != null) ? answer : namespaces;
207 }
208
209 protected void defineNamespace(Map namespaces, String prefix, String uri) {
210 namespaces.put(prefix, uri);
211 if (!prefix.equals("xmlns") && !prefix.equals("xml")) {
212 printIndent();
213 print(prefix);
214 print(" = xmlns.namespace('");
215 print(uri);
216 println("')");
217 }
218 }
219
220 protected boolean printAttributes(Element element) {
221 boolean hasAttribute = false;
222 NamedNodeMap attributes = element.getAttributes();
223 int length = attributes.getLength();
224 if (length > 0) {
225 StringBuffer buffer = new StringBuffer();
226 for (int i = 0; i < length; i++) {
227 printAttributeWithPrefix((Attr) attributes.item(i), buffer);
228 }
229 print("(");
230 for (int i = 0; i < length; i++) {
231 hasAttribute = printAttributeWithoutPrefix((Attr) attributes.item(i), hasAttribute);
232 }
233 if (buffer.length() > 0) {
234 if (hasAttribute) {
235 print(", ");
236 }
237 print("xmlns=[");
238 print(buffer.toString());
239 print("]");
240 hasAttribute = true;
241 }
242 }
243 return hasAttribute;
244 }
245
246 private void printAttributeWithPrefix(Attr attribute, StringBuffer buffer) {
247 String prefix = attribute.getPrefix();
248 if (prefix != null && prefix.length() > 0) {
249 if (buffer.length() > 0) {
250 buffer.append(", ");
251 }
252 buffer.append(prefix);
253 buffer.append(".");
254 buffer.append(getLocalName(attribute));
255 buffer.append(":'");
256 buffer.append(getAttributeValue(attribute));
257 buffer.append("'");
258 }
259 }
260
261 private String getAttributeValue(Attr attribute) {
262 return attribute.getValue();
263 }
264
265 private boolean printAttributeWithoutPrefix(Attr attribute, boolean hasAttribute) {
266 String prefix = attribute.getPrefix();
267 if (prefix == null || prefix.length() == 0) {
268 if (!hasAttribute) {
269 hasAttribute = true;
270 } else {
271 print(", ");
272 }
273 print(getLocalName(attribute));
274 print(":'");
275 print(getAttributeValue(attribute));
276 print("'");
277 }
278 return hasAttribute;
279 }
280
281 protected String getTextNodeData(Text node) {
282 return node.getData().trim();
283 }
284
285 protected boolean mixedContent(NodeList list) {
286 boolean hasText = false;
287 boolean hasElement = false;
288 for (int i = 0, size = list.getLength(); i < size; i++) {
289 Node node = list.item(i);
290 if (node instanceof Element) {
291 hasElement = true;
292 } else if (node instanceof Text) {
293 String text = getTextNodeData((Text) node);
294 if (text.length() > 0) {
295 hasText = true;
296 }
297 }
298 }
299 return hasText && hasElement;
300 }
301
302 protected void printChildren(Node parent, Map namespaces) {
303 for (Node node = parent.getFirstChild(); node != null; node = node.getNextSibling()) {
304 print(node, namespaces, false);
305 }
306 }
307
308 protected String getLocalName(Node node) {
309 String answer = node.getLocalName();
310 if (answer == null) {
311 answer = node.getNodeName();
312 }
313 return answer.trim();
314 }
315
316 protected void printEnd(String text, boolean endWithComma) {
317 if (endWithComma) {
318 print(text);
319 println(",");
320 } else {
321 println(text);
322 }
323 }
324
325 protected void println(String text) {
326 out.println(text);
327 }
328
329 protected void print(String text) {
330 out.print(text);
331 }
332
333 protected void printIndent() {
334 out.printIndent();
335 }
336 }