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 }