blob: 872f8c87859721e84891e369da16ab4b73bdd745 [file] [log] [blame]
/*
* Copyright 2003-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.codehaus.groovy.tools.xml;
import groovy.util.IndentPrinter;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
import org.w3c.dom.Attr;
import org.w3c.dom.Comment;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.ProcessingInstruction;
import org.w3c.dom.Text;
/**
* A SAX handler for turning XML into Groovy scripts
*
* @author James Strachan
* @author paulk
*/
public class DomToGroovy {
private IndentPrinter out;
public DomToGroovy(PrintWriter out) {
this(new IndentPrinter(out));
}
// TODO allow string quoting delimiter to be specified, e.g. ' vs "
public DomToGroovy(IndentPrinter out) {
this.out = out;
}
public void print(Document document) {
printChildren(document, new HashMap());
}
// Implementation methods
//-------------------------------------------------------------------------
protected void print(Node node, Map namespaces, boolean endWithComma) {
switch (node.getNodeType()) {
case Node.ELEMENT_NODE :
printElement((Element) node, namespaces, endWithComma);
break;
case Node.PROCESSING_INSTRUCTION_NODE :
printPI((ProcessingInstruction) node, endWithComma);
break;
case Node.TEXT_NODE :
printText((Text) node, endWithComma);
break;
case Node.COMMENT_NODE :
printComment((Comment) node, endWithComma);
break;
}
}
protected void printElement(Element element, Map namespaces, boolean endWithComma) {
namespaces = defineNamespaces(element, namespaces);
element.normalize();
printIndent();
String prefix = element.getPrefix();
if (prefix != null && prefix.length() > 0) {
print(prefix);
print(".");
}
print(getLocalName(element));
boolean hasAttributes = printAttributes(element);
NodeList list = element.getChildNodes();
int length = list.getLength();
if (length == 0) {
printEnd(hasAttributes ? ")" : "()", endWithComma);
} else {
Node node = list.item(0);
if (length == 1 && node instanceof Text) {
Text textNode = (Text) node;
String text = getTextNodeData(textNode);
if (hasAttributes) print(", '");
else print("('");
print(text);
printEnd("')", endWithComma);
} else if (mixedContent(list)) {
println(" [");
out.incrementIndent();
for (node = element.getFirstChild(); node != null; node = node.getNextSibling()) {
boolean useComma = node.getNextSibling() != null;
print(node, namespaces, useComma);
}
out.decrementIndent();
printIndent();
printEnd("]", endWithComma);
} else {
println(") {");
out.incrementIndent();
printChildren(element, namespaces);
out.decrementIndent();
printIndent();
printEnd("}", endWithComma);
}
}
}
protected void printPI(ProcessingInstruction instruction, boolean endWithComma) {
printIndent();
print("xml.pi('");
print(instruction.getTarget());
print("', '");
print(instruction.getData());
printEnd("');", endWithComma);
}
protected void printComment(Comment comment, boolean endWithComma) {
String text = comment.getData().trim();
if (text.length() >0) {
printIndent();
print("/* ");
print(text);
printEnd(" */", endWithComma);
}
}
protected void printText(Text node, boolean endWithComma) {
String text = getTextNodeData(node);
if (text.length() > 0) {
printIndent();
// print("xml.append('");
// print(text);
// println("');");
print("'");
print(text);
printEnd("'", endWithComma);
}
}
protected Map defineNamespaces(Element element, Map namespaces) {
Map answer = null;
String prefix = element.getPrefix();
if (prefix != null && prefix.length() > 0 && !namespaces.containsKey(prefix)) {
answer = new HashMap(namespaces);
defineNamespace(answer, prefix, element.getNamespaceURI());
}
NamedNodeMap attributes = element.getAttributes();
int length = attributes.getLength();
for (int i = 0; i < length; i++) {
Attr attribute = (Attr) attributes.item(i);
prefix = attribute.getPrefix();
if (prefix != null && prefix.length() > 0 && !namespaces.containsKey(prefix)) {
if (answer == null) {
answer = new HashMap(namespaces);
}
defineNamespace(answer, prefix, attribute.getNamespaceURI());
}
}
return (answer != null) ? answer : namespaces;
}
protected void defineNamespace(Map namespaces, String prefix, String uri) {
namespaces.put(prefix, uri);
if (!prefix.equals("xmlns") && !prefix.equals("xml")) {
printIndent();
print(prefix);
print(" = xmlns.namespace('");
print(uri);
println("')");
}
}
protected boolean printAttributes(Element element) {
boolean hasAttribute = false;
NamedNodeMap attributes = element.getAttributes();
int length = attributes.getLength();
if (length > 0) {
StringBuffer buffer = new StringBuffer();
for (int i = 0; i < length; i++) {
printAttributeWithPrefix((Attr) attributes.item(i), buffer);
}
print("(");
for (int i = 0; i < length; i++) {
hasAttribute = printAttributeWithoutPrefix((Attr) attributes.item(i), hasAttribute);
}
if (buffer.length() > 0) {
if (hasAttribute) {
print(", ");
}
print("xmlns=[");
print(buffer.toString());
print("]");
hasAttribute = true;
}
}
return hasAttribute;
}
private void printAttributeWithPrefix(Attr attribute, StringBuffer buffer) {
String prefix = attribute.getPrefix();
if (prefix != null && prefix.length() > 0) {
if (buffer.length() > 0) {
buffer.append(", ");
}
buffer.append(prefix);
buffer.append(".");
buffer.append(getLocalName(attribute));
buffer.append(":'");
buffer.append(getAttributeValue(attribute));
buffer.append("'");
}
}
private String getAttributeValue(Attr attribute) {
return attribute.getValue();
}
private boolean printAttributeWithoutPrefix(Attr attribute, boolean hasAttribute) {
String prefix = attribute.getPrefix();
if (prefix == null || prefix.length() == 0) {
if (!hasAttribute) {
hasAttribute = true;
} else {
print(", ");
}
print(getLocalName(attribute));
print(":'");
print(getAttributeValue(attribute));
print("'");
}
return hasAttribute;
}
protected String getTextNodeData(Text node) {
return node.getData().trim();
}
protected boolean mixedContent(NodeList list) {
boolean hasText = false;
boolean hasElement = false;
for (int i = 0, size = list.getLength(); i < size; i++) {
Node node = list.item(i);
if (node instanceof Element) {
hasElement = true;
} else if (node instanceof Text) {
String text = getTextNodeData((Text) node);
if (text.length() > 0) {
hasText = true;
}
}
}
return hasText && hasElement;
}
protected void printChildren(Node parent, Map namespaces) {
for (Node node = parent.getFirstChild(); node != null; node = node.getNextSibling()) {
print(node, namespaces, false);
}
}
protected String getLocalName(Node node) {
String answer = node.getLocalName();
if (answer == null) {
answer = node.getNodeName();
}
return answer.trim();
}
protected void printEnd(String text, boolean endWithComma) {
if (endWithComma) {
print(text);
println(",");
} else {
println(text);
}
}
protected void println(String text) {
out.println(text);
}
protected void print(String text) {
out.print(text);
}
protected void printIndent() {
out.printIndent();
}
}