View Javadoc

1   /*
2    $Id: DomToGroovy.java,v 1.5 2003/11/04 12:00:48 jstrachan 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 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      // Implementation methods
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             //            print("xml.append('");
188             //            print(text);
189             //            println("');");
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 }