`Xml2Groovy.java`
`001 /* 002 * Copyright 2011-2012 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 package griffon.util; 017 018 import groovy.util.IndentPrinter; 019 import groovy.util.XmlSlurper; 020 import groovy.util.slurpersupport.GPathResult; 021 import groovy.util.slurpersupport.Node; 022 import groovy.util.slurpersupport.NodeChild; 023 import org.codehaus.groovy.runtime.DefaultGroovyMethods; 024 import org.xml.sax.InputSource; 025 import org.xml.sax.SAXException; 026 027 import javax.xml.parsers.ParserConfigurationException; 028 import java.io.*; 029 import java.util.ArrayList; 030 import java.util.Iterator; 031 import java.util.List; 032 import java.util.Map; 033 034 /** 035 * Translates an XML file into a Groovy script that is suitable for a Groovy builder. 036 * String literals must be escaped either using single or double quotes. <p> 037 * This helper class is useful for translating an XML View definition into a Groovy 038 * script that can be handled by an UberBuilder, for example this View 039 * 040 * <xmp> 041 <application title="app.config.application.title" 042 pack="true"> 043 <actions> 044 <action id="'clickAction'" 045 name="'Click'" 046 closure="{controller.click(it)}"/> 047 </actions> 048 049 <gridLayout cols="1" rows="3"/> 050 <textField id="'input'" columns="20" 051 text="bind('value', target: model)"/> 052 <textField id="'output'" columns="20" 053 text="bind{model.value}" editable="false"/> 054 <button action="clickAction"/> 055 </application> 056 * </xmp> 057 * 058 * results in the following script 059 * 060 * <pre> 061 application(title: app.config.application.title, pack: true) { 062 actions { 063 action(id: 'clickAction', name: 'Click', closure: {controller.click(it)}) 064 } 065 gridLayout(cols: 1, rows: 3) 066 textField(id: 'input', text: bind('value', target: model), columns: 20) 067 textField(id: 'output', text: bind{model.value}, columns: 20, editable: false) 068 button(action: clickAction) 069 } 070 * </pre> 071 * 072 * @author Andres Almiray 073 */ 074 public final class Xml2Groovy { 075 private static final Xml2Groovy INSTANCE; 076 077 static { 078 INSTANCE = new Xml2Groovy(); 079 } 080 081 public static Xml2Groovy getInstance() { 082 return INSTANCE; 083 } 084 085 private Xml2Groovy() { 086 087 } 088 089 public String parse(File file) { 090 try { 091 return translate(newXmlSlurper().parse(file)); 092 } catch (IOException e) { 093 throw new IllegalArgumentException(e); 094 } catch (SAXException e) { 095 throw new IllegalArgumentException(e); 096 } 097 } 098 099 public String parse(InputSource source) { 100 try { 101 return translate(newXmlSlurper().parse(source)); 102 } catch (IOException e) { 103 throw new IllegalArgumentException(e); 104 } catch (SAXException e) { 105 throw new IllegalArgumentException(e); 106 } 107 } 108 109 public String parse(InputStream stream) { 110 try { 111 return translate(newXmlSlurper().parse(stream)); 112 } catch (IOException e) { 113 throw new IllegalArgumentException(e); 114 } catch (SAXException e) { 115 throw new IllegalArgumentException(e); 116 } 117 } 118 119 public String parse(Reader reader) { 120 try { 121 return translate(newXmlSlurper().parse(reader)); 122 } catch (IOException e) { 123 throw new IllegalArgumentException(e); 124 } catch (SAXException e) { 125 throw new IllegalArgumentException(e); 126 } 127 } 128 129 public String parse(String uri) { 130 try { 131 return translate(newXmlSlurper().parse(uri)); 132 } catch (IOException e) { 133 throw new IllegalArgumentException(e); 134 } catch (SAXException e) { 135 throw new IllegalArgumentException(e); 136 } 137 } 138 139 public String parse(GPathResult root) { 140 return translate(root); 141 } 142 143 public String parseText(String text) { 144 try { 145 return translate(newXmlSlurper().parseText(text)); 146 } catch (IOException e) { 147 throw new IllegalArgumentException(e); 148 } catch (SAXException e) { 149 throw new IllegalArgumentException(e); 150 } 151 } 152 153 private XmlSlurper newXmlSlurper() { 154 try { 155 return new XmlSlurper(); 156 } catch (ParserConfigurationException e) { 157 throw new IllegalArgumentException(e); 158 } catch (SAXException e) { 159 throw new IllegalArgumentException(e); 160 } 161 } 162 163 private String translate(GPathResult root) { 164 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 165 IndentPrinter printer = createIndentPrinter(baos); 166 walkXml(printer, (NodeChild) root); 167 printer.flush(); 168 169 return baos.toString(); 170 } 171 172 private IndentPrinter createIndentPrinter(OutputStream os) { 173 PrintWriter pw = new PrintWriter(new OutputStreamWriter(os)); 174 return new IndentPrinter(pw); 175 } 176 177 private void walkXml(IndentPrinter printer, NodeChild node) { 178 printer.printIndent(); 179 printer.print(node.name()); 180 if (!node.attributes().isEmpty()) { 181 printer.print("("); 182 List<String> attrs = new ArrayList<String>(); 183 for (Object o : node.attributes().entrySet()) { 184 Map.Entry entry = (Map.Entry) o; 185 attrs.add(entry.getKey() + ": " + entry.getValue()); 186 } 187 printer.print(DefaultGroovyMethods.join(attrs, ",")); 188 printer.print(")"); 189 } 190 191 if (node.children().size() > 0) { 192 printer.println(" {"); 193 printer.incrementIndent(); 194 for (Iterator iter = node.childNodes(); iter.hasNext(); ) { 195 Object child = iter.next(); 196 if (child instanceof NodeChild) { 197 walkXml(printer, (NodeChild) child); 198 } else if (child instanceof Node) { 199 walkXml(printer, (Node) child); 200 } 201 } 202 printer.decrementIndent(); 203 printer.printIndent(); 204 printer.println("}"); 205 } else if (!node.attributes().isEmpty()) { 206 printer.println(""); 207 } else { 208 printer.println("()"); 209 } 210 } 211 212 private void walkXml(IndentPrinter printer, Node node) { 213 printer.printIndent(); 214 printer.print(node.name()); 215 if (!node.attributes().isEmpty()) { 216 printer.print("("); 217 List<String> attrs = new ArrayList<String>(); 218 for (Object o : node.attributes().entrySet()) { 219 Map.Entry entry = (Map.Entry) o; 220 attrs.add(entry.getKey() + ": " + entry.getValue()); 221 } 222 printer.print(DefaultGroovyMethods.join(attrs, ",")); 223 printer.print(")"); 224 } 225 226 if (node.children().size() > 0) { 227 printer.println(" {"); 228 printer.incrementIndent(); 229 for (Iterator iter = node.childNodes(); iter.hasNext(); ) { 230 Object child = iter.next(); 231 if (child instanceof NodeChild) { 232 walkXml(printer, (NodeChild) child); 233 } else if (child instanceof Node) { 234 walkXml(printer, (Node) child); 235 } 236 } 237 printer.decrementIndent(); 238 printer.printIndent(); 239 printer.println("}"); 240 } else if (!node.attributes().isEmpty()) { 241 printer.println(""); 242 } else { 243 printer.println("()"); 244 } 245 } 246 }`