# HG changeset patch
# User smith@nwoca.org
# Date 1329491375 0
# Node ID 15f4da8bdbd38f6323d9601030ed115bb8a97b29
# Parent 9f2ab59a53337333425e27dc72a2a06a3ae5b47a
add ability to control order of attributes, whitespace. more cleanup up of dependencies and exclusions
diff -r 9f2ab59a5333 -r 15f4da8bdbd3 fix-ivy.groovy
--- a/fix-ivy.groovy Wed Feb 15 17:11:10 2012 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,489 +0,0 @@
-
-import groovy.xml.QName;
-import org.codehaus.groovy.runtime.InvokerHelper;
-
-import java.io.OutputStreamWriter;
-import java.io.PrintWriter;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import groovy.xml.*
-
-println args
-
-if (args.any { it.toUpperCase() == '-R'} ) {
-
-
-} else {
- processIvy(new File('ivy.xml')
-}
-
-def processIvy(file) {
-
- def xml = new XmlSlurper()
- def ivy = xml.parse( file)
-
- def cfgs = ivy.configurations
-
- // default mapping for most dependencies:
- cfgs.@defaultconfmapping = 'compile->default'
-
- // Add default config, if missing:
- if (!cfgs.children().find { it.@name == 'default' } ) {
- println "adding default config"
- cfgs.appendNode {
- conf(name:"default")
- }
- }
-
-
- ivy.dependencies.children().each { dep ->
- if ( dep.@conf.text()?.contains('test') ) {
- dep.@conf = 'compile-test->default'
- } else {
- dep.attributes().remove('conf')
- }
- }
-
- // find groovy dependencies (or null)
- groovy = ivy.dependencies.children().find { it.@org == 'org.codehaus.groovy' && it.@name.text().startsWith('groovy') }
-
- if (groovy) {
- // Add a groovy conig for groovy projects:
- if (!cfgs.children().any { it.@name == 'groovy' } ) {
- println "added private groovy conf"
- cfgs.appendNode {
- conf(name:'groovy',visibility:'private',transitive: true)
- }
- }
- // Adjust 'compile' to exend from 'groovy' conf
- cfgs.children().find { it.@name == 'compile' }.@extends = 'groovy'
- cfgs.children().find { it.@name == 'groovy' }.@transitive = 'true'
- groovy.@conf = "groovy->default"
- println "Groovy ${groovy.@rev} conf changed to ${groovy.@conf}"
- // Switch project to use groovy-all instead of groovy + deps
- if (groovy.@name == 'groovy') {
- println "changed groovy to groovy-all"
- groovy.@name = 'groovy-all'
- }
- // remove exclude for groovy-all
- ivy.dependencies.children().find { it.name() == 'exclude' && it.@module.text() == 'groovy-all' }.replaceNode {}
- }
-
- //def sameConfMappings = ivy.dependencies.children().findAll { it.@conf in ['*->@','*->*'] }
- //
- //sameConfMappings.each {
- // it.@conf = null // "default->compile;%->@"
- // println "changing conf for ${it.@name} to ${it.@conf}"
- //}
-
-
- cfgs.children().each { it.@visibility = 'private' }
- cfgs.children().find {it.@name == 'runtime' }.@extends = 'compile'
- cfgs.children().find {it.@name == 'compile-test' }.@extends = 'compile'
- cfgs.children().find {it.@name == 'runtime-test' }.@extends = 'runtime,compile-test'
- cfgs.children().find {it.@name == 'default' }.@visibility = 'public'
- cfgs.children().find {it.@name == 'default' }.@extends = 'runtime'
-
- if (!cfgs.children().any { it.@name == 'archives' } ) {
- println "added public 'archives' conf"
- cfgs.appendNode {
- conf(name:'archives',visibility:'public')
- }
- }
- cfgs.children().find {it.@name == 'archives' }.@visibility = 'public'
-
-
- def outputBuilder = new StreamingMarkupBuilder()
- //new File('ivy.xml').write( XmlUtil.serialize( outputBuilder.bind { mkp.yield ivy }).replaceAll('>','>'))
-
- def stringWriter = new StringWriter()
-
-
- def node = new XmlParser().parseText( XmlUtil.serialize( outputBuilder.bind { mkp.yield ivy }))
- new MyNodePrinter(new IndentPrinter( new PrintWriter(stringWriter))).print(node)
- file.write(stringWriter.toString())
-
-}
-/*
-The class below is a copy/paste of groovy's XmlNodePrinter customized to order Ivy.xml attributes in
-the desired order and to add some whitespace.
-*/
-class MyNodePrinter {
-
- protected void printNameAttributes(Map attributes, ctx) {
-
- if (attributes == null || attributes.isEmpty()) {
- return;
- }
- def writer = new StringBuffer()
- attributes.entrySet().sort{
- switch (it.key ) {
- case 'org':
- 1
- break
- case 'name': 2
- break
- case 'rev': 3
- break
- case 'extends': 5
- break
- default: 99
- }
- }.each { p ->
- def tmp = new StringBuffer()
- Map.Entry entry = (Map.Entry) p;
-
- tmp << " "
- tmp << getName(entry.getKey())
- tmp << "="
- Object value = entry.getValue();
- tmp << quote
- tmp << value
-// if (value instanceof String) {
-// printEscaped((String) value);
-// } else {
-// printEscaped(InvokerHelper.toString(value));
-// }
- tmp << quote
- writer << String.format(" %-35s",tmp.toString())
-// printNamespace(entry.getKey(), ctx);
- }
- out.print(" " + writer.toString().trim())
- }
-
- protected final IndentPrinter out;
- private String quote;
- private boolean namespaceAware = true;
- private boolean preserveWhitespace = false;
-
- public MyNodePrinter(PrintWriter out) {
- this(out, " ");
- }
-
- public MyNodePrinter(PrintWriter out, String indent) {
- this(out, indent, "\"");
- }
-
- public MyNodePrinter(PrintWriter out, String indent, String quote) {
- this(new IndentPrinter(out, indent), quote);
- }
-
- public MyNodePrinter(IndentPrinter out) {
- this(out, "\"");
- }
-
- public MyNodePrinter(IndentPrinter out, String quote) {
- if (out == null) {
- throw new IllegalArgumentException("Argument 'IndentPrinter out' must not be null!");
- }
- this.out = out;
- this.quote = quote;
- }
-
- public MyNodePrinter() {
- this(new PrintWriter(new OutputStreamWriter(System.out)));
- }
-
- public void print(Node node) {
- print(node, new NamespaceContext());
- }
-
- /**
- * Check if namespace handling is enabled.
- * Defaults to true
.
- *
- * @return true if namespace handling is enabled
- */
- public boolean isNamespaceAware() {
- return namespaceAware;
- }
-
- /**
- * Enable and/or disable namespace handling.
- *
- * @param namespaceAware the new desired value
- */
- public void setNamespaceAware(boolean namespaceAware) {
- this.namespaceAware = namespaceAware;
- }
-
- /**
- * Check if whitespace preservation is enabled.
- * Defaults to false
.
- *
- * @return true if whitespaces are honoured when printing simple text nodes
- */
- public boolean isPreserveWhitespace() {
- return preserveWhitespace;
- }
-
- /**
- * Enable and/or disable preservation of whitespace.
- *
- * @param preserveWhitespace the new desired value
- */
- public void setPreserveWhitespace(boolean preserveWhitespace) {
- this.preserveWhitespace = preserveWhitespace;
- }
-
- /**
- * Get Quote to use when printing attributes.
- *
- * @return the quote character
- */
- public String getQuote() {
- return quote;
- }
-
- /**
- * Set Quote to use when printing attributes.
- *
- * @param quote the quote character
- */
- public void setQuote(String quote) {
- this.quote = quote;
- }
-
- protected void print(Node node, NamespaceContext ctx) {
- /*
- * Handle empty elements like '
', ' or '
.
- */
- if (isEmptyElement(node)) {
- printLineBegin();
- out.print("<");
- out.print(getName(node));
- if (ctx != null) {
- printNamespace(node, ctx);
- }
- printNameAttributes(node.attributes(), ctx);
- out.print("/>");
- printLineEnd();
- out.flush();
- return;
- }
-
- /*
- * Hook for extra processing, e.g. GSP tag element!
- */
- if (printSpecialNode(node)) {
- out.flush();
- return;
- }
-
- /*
- * Handle normal element like ... .
- */
- Object value = node.value();
- if (value instanceof List) {
- printName(node, ctx, true, isListOfSimple((List) value));
- printList((List) value, ctx);
- printName(node, ctx, false, isListOfSimple((List) value));
- out.flush();
- return;
- }
-
- // treat as simple type - probably a String
- printName(node, ctx, true, preserveWhitespace);
- printSimpleItemWithIndent(value);
- printName(node, ctx, false, preserveWhitespace);
- out.flush();
- }
-
- private boolean isListOfSimple(List value) {
- for (Object p : value) {
- if (p instanceof Node) return false;
- }
- return preserveWhitespace;
- }
-
- protected void printLineBegin() {
- out.printIndent();
- }
-
- protected void printLineEnd() {
- printLineEnd(null);
- }
-
- protected void printLineEnd(String comment) {
- if (comment != null) {
- out.print(" ");
- }
- out.println();
- out.flush();
- }
-
- protected void printList(List list, NamespaceContext ctx) {
- out.incrementIndent();
- for (Object value : list) {
- NamespaceContext context = new NamespaceContext(ctx);
- /*
- * If the current value is a node, recurse into that node.
- */
- if (value instanceof Node) {
- print((Node) value, context);
- continue;
- }
- printSimpleItem(value);
- }
- out.decrementIndent();
- }
-
- protected void printSimpleItem(Object value) {
- if (!preserveWhitespace) printLineBegin();
- printEscaped(InvokerHelper.toString(value));
- if (!preserveWhitespace) printLineEnd();
- }
-
- protected void printName(Node node, NamespaceContext ctx, boolean begin, boolean preserve) {
- if (node == null) {
- throw new NullPointerException("Node must not be null.");
- }
- Object name = node.name();
- if (name == null) {
- throw new NullPointerException("Name must not be null.");
- }
- if (!preserve || begin) printLineBegin();
- out.print("<");
- if (!begin) {
- out.print("/");
- }
- out.print(getName(node));
- if (ctx != null) {
- printNamespace(node, ctx);
- }
- if (begin) {
- printNameAttributes(node.attributes(), ctx);
- }
- out.print(">");
- if (!preserve || !begin) printLineEnd();
- }
-
- protected boolean printSpecialNode(Node node) {
- return false;
- }
-
- protected void printNamespace(Object object, NamespaceContext ctx) {
- if (namespaceAware) {
- if (object instanceof Node) {
- printNamespace(((Node) object).name(), ctx);
- } else if (object instanceof QName) {
- QName qname = (QName) object;
- String namespaceUri = qname.getNamespaceURI();
- if (namespaceUri != null) {
- String prefix = qname.getPrefix();
- if (!ctx.isPrefixRegistered(prefix, namespaceUri)) {
- ctx.registerNamespacePrefix(prefix, namespaceUri);
- out.print(" ");
- out.print("xmlns");
- if (prefix.length() > 0) {
- out.print(":");
- out.print(prefix);
- }
- out.print("=" + quote);
- out.print(namespaceUri);
- out.print(quote);
- }
- }
- }
- }
- }
-
-
-
- private boolean isEmptyElement(Node node) {
- if (node == null) {
- throw new IllegalArgumentException("Node must not be null!");
- }
- if (!node.children().isEmpty()) {
- return false;
- }
- return node.text().length() == 0;
- }
-
- private String getName(Object object) {
- if (object instanceof String) {
- return (String) object;
- } else if (object instanceof QName) {
- QName qname = (QName) object;
- if (!namespaceAware) {
- return qname.getLocalPart();
- }
- return qname.getQualifiedName();
- } else if (object instanceof Node) {
- Object name = ((Node) object).name();
- return getName(name);
- }
- return object.toString();
- }
-
- private void printSimpleItemWithIndent(Object value) {
- if (!preserveWhitespace) out.incrementIndent();
- printSimpleItem(value);
- if (!preserveWhitespace) out.decrementIndent();
- }
-
- // For ' and " we only escape if needed. As far as XML is concerned,
- // we could always escape if we wanted to.
- private void printEscaped(String s) {
- for (int i = 0; i < s.length(); i++) {
- char c = s.charAt(i);
- switch (c) {
- case '<':
- out.print("<");
- break;
- case '>':
- out.print(">");
- break;
- case '&':
- out.print("&");
- break;
- case '\'':
- if (quote.equals("'"))
- out.print("'");
- else
- out.print(c);
- break;
- case '"':
- if (quote.equals("\""))
- out.print(""");
- else
- out.print(c);
- break;
- default:
- out.print(c);
- }
- }
- }
-
- protected class NamespaceContext {
- private final Map namespaceMap;
-
- public NamespaceContext() {
- namespaceMap = new HashMap();
- }
-
- public NamespaceContext(NamespaceContext context) {
- this();
- namespaceMap.putAll(context.namespaceMap);
- }
-
- public boolean isPrefixRegistered(String prefix, String uri) {
- return namespaceMap.containsKey(prefix) && namespaceMap.get(prefix).equals(uri);
- }
-
- public void registerNamespacePrefix(String prefix, String uri) {
- if (!isPrefixRegistered(prefix, uri)) {
- namespaceMap.put(prefix, uri);
- }
- }
-
- public String getNamespace(String prefix) {
- Object uri = namespaceMap.get(prefix);
- return (uri == null) ? null : uri.toString();
- }
- }
-}
\ No newline at end of file
diff -r 9f2ab59a5333 -r 15f4da8bdbd3 fixivy.groovy
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/fixivy.groovy Fri Feb 17 15:09:35 2012 +0000
@@ -0,0 +1,572 @@
+
+import groovy.xml.QName;
+import org.codehaus.groovy.runtime.InvokerHelper;
+
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import groovy.xml.*
+
+//args = [ '-r']
+println args
+
+ant = new AntBuilder()
+
+
+if (args.any { it.toUpperCase() == '-R'} ) {
+
+ new File('.').traverse ([ type: groovy.io.FileType.DIRECTORIES, maxDepth: 3 ]) { project ->
+ if (new File(project,'ivy.xml').exists() ) {
+ processIvy(new File(project,'ivy.xml'))
+ }
+ }
+
+} else {
+ processIvy(new File('ivy.xml'))
+}
+
+def processIvy(file) {
+ println "-" * 60
+ println "processing: $file"
+ def xml = new XmlSlurper()
+ def ivy = xml.parse(file)
+
+ def cfgs = ivy.configurations
+
+ // default mapping for most dependencies:
+ cfgs.@defaultconfmapping = 'compile->default(*)'
+
+ // Add default config, if missing:
+ if (!cfgs.children().find { it.@name == 'default' } ) {
+ println "adding default config"
+ cfgs.appendNode {
+ conf(name:"default",extends:'compile',visibility:'public')
+ }
+ }
+
+ if (ivy.dependencies.children().find { it.@name == 'org.springframework.web.servlet' } &&
+ !ivy.dependencies.children().find { it.@name == 'servlet-api' } ) {
+ ivy.dependencies.children().findAll { it.name() == 'dependency' }.list().last() + {
+ dependency(name:'servlet-api', org: 'javax.servlet', rev: '2.5')
+ dependency(name:'jsp-api', org: 'javax.servlet', rev: '2.0')
+ }
+
+ }
+
+ ivy.dependencies.children().each { dep ->
+ if ( dep.@conf.text()?.contains('test') ) {
+ dep.@conf = 'compile-test->default(*)'
+ } else if ( dep.@conf.text().contains('castor-ant') ) {
+ dep.@conf = 'castor-ant->default(*)'
+ }
+ else {
+ dep.attributes().remove('conf')
+ }
+ }
+
+ // find groovy dependencies (or null)
+ groovy = ivy.dependencies.children().find { it.@org == 'org.codehaus.groovy' && it.@name.text().startsWith('groovy') }
+
+ if (groovy) {
+ // Add a groovy conig for groovy projects:
+ if (!cfgs.children().any { it.@name == 'groovy' } ) {
+ println "added private groovy conf"
+ cfgs.appendNode {
+ conf(name:'groovy',visibility:'private',transitive: true)
+ }
+ }
+ // Adjust 'compile' to exend from 'groovy' conf
+ cfgs.children().find { it.@name == 'compile' }.@extends = 'groovy'
+ cfgs.children().find { it.@name == 'groovy' }.@transitive = 'true'
+ groovy.@conf = "groovy->default"
+ println "Groovy ${groovy.@rev} conf changed to ${groovy.@conf}"
+ // Switch project to use groovy-all instead of groovy + deps
+ if (groovy.@name == 'groovy') {
+ println "changed groovy to groovy-all"
+ groovy.@name = 'groovy-all'
+ }
+
+ def template = new File(file.parent ?: ".",'template.mf')
+ if (template.exists()) {
+ println "updating groovy in $template"
+ ant.replace(file: template, token: 'org.codehaus.groovy-groovy:major',value:'org.codehaus.groovy-groovy-all:major')
+ }
+
+ }
+
+
+ ensure(ivy.dependencies, 'hibernate-validator', ['org.slf4j:slf4j-api:1.5.6','org.slf4j:slf4j-log4j12:1.5.6'])
+
+ ensure(ivy.dependencies, 'org.springframework.test', ['junit:junit:4.8.2'])
+
+ // remove exclude for groovy-all
+ ivy.dependencies.children().find { it.name() == 'exclude' && it.@module.text() == 'groovy-all' }.replaceNode {}
+
+ // Add exclude for regular groovy:
+ ensureExcluded(ivy.dependencies,"org.codehaus.groovy:groovy")
+
+ // ensure modules covered by springsource are exluded;
+ ensureSpringSourceExcludes(ivy.dependencies)
+
+ ensureConfiguration(ivy.dependencies,'org.springframework.test','compile-test')
+
+ //remove bad junit dependencies and excludes
+ ivy.dependencies.children().find { it.@org == 'org.junit' && it.@module.text() == 'org.junit' }.replaceNode {}
+ ivy.dependencies.children().find { it.@org == 'org.junit' && it.@name.text() == 'org.junit' }.replaceNode {}
+
+
+ cfgs.children().each { it.@visibility = 'public' } // Should be 'private' after initial conversions.
+
+ cfgs.children().find {it.@name == 'runtime' }.@extends = 'compile'
+ cfgs.children().find {it.@name == 'compile-test' }.@extends = 'compile'
+ cfgs.children().find {it.@name == 'runtime-test' }.@extends = 'runtime,compile-test'
+ cfgs.children().find {it.@name == 'default' }.@visibility = 'public'
+ cfgs.children().find {it.@name == 'default' }.@extends = 'runtime'
+
+ if (!cfgs.children().any { it.@name == 'archives' } ) {
+ println "added public 'archives' conf"
+ cfgs.appendNode {
+ conf(name:'archives',visibility:'public')
+ }
+ }
+
+ cfgs.children().find {it.@name == 'archives' }.@visibility = 'public'
+
+
+ def outputBuilder = new StreamingMarkupBuilder()
+ //new File('ivy.xml').write( XmlUtil.serialize( outputBuilder.bind { mkp.yield ivy }).replaceAll('>','>'))
+
+ def stringWriter = new StringWriter()
+
+
+ def node = new XmlParser().parseText( XmlUtil.serialize( outputBuilder.bind { mkp.yield ivy }))
+ new MyNodePrinter(new IndentPrinter( new PrintWriter(stringWriter))).print(node)
+ file.write(stringWriter.toString())
+
+}
+
+def ensureConfiguration(depends,name,cfg) {
+ depends.children().findAll { it.name() == 'dependency' && it.@name == name}.each {
+ it.@conf = "$cfg->default(*)"
+ }
+}
+
+def ensureExcluded(depends,excludeModule) {
+ def (o,m) = excludeModule.split(':')
+ if (!depends.children().any { it.name() == 'exclude' && it.@module.text() == m}) {
+ depends.appendNode {
+ println "excluding $o:$m"
+ exclude(org: o, module: m)
+ }
+ }
+}
+
+def ensure(depends,exists,requires) {
+
+ if (depends.children().any { it.name() == 'dependency' && it.@name == exists } ) {
+ requires.each {
+ def (org,name,rev) = it.split(":")
+ if (!depends.children().any { it.@name == name } ) {
+ println " adding requirement $org:$name for $exists"
+ depends.children().findAll { it.name() == 'dependency' }.list().last() + {
+ dependency(name: name, org: org, rev: rev)
+ }
+ }
+ }
+ }
+}
+
+def ensureSpringSourceExcludes(depends) {
+ def exclusions = []
+ depends.children().findAll { it.name() == 'dependency' && it.@name.text().startsWith('com.springsource.') }.each {
+ exclusions << "${it.@org}:${it.@name.text() - 'com.springsource.'}"
+ }
+ exclusions.each { ensureExcluded(depends,it) }
+
+}
+
+/*
+The class below is a copy/paste of groovy's XmlNodePrinter customized to order Ivy.xml attributes in
+the desired order and to add some whitespace.
+*/
+class MyNodePrinter {
+
+ protected void printNameAttributes(Map attributes, ctx) {
+
+ if (attributes == null || attributes.isEmpty()) {
+ return;
+ }
+ def writer = new StringBuffer()
+ attributes.entrySet().sort{
+ switch (it.key ) {
+ case 'org':
+ 1
+ break
+ case 'name': 2
+ break
+ case 'rev': 3
+ break
+ case 'extends': 5
+ break
+ default: 99
+ }
+ }.each { p ->
+ def tmp = new StringBuffer()
+ Map.Entry entry = (Map.Entry) p;
+
+ tmp << " "
+ tmp << getName(entry.getKey())
+ tmp << "="
+ Object value = entry.getValue();
+ tmp << quote
+ tmp << value
+// if (value instanceof String) {
+// printEscaped((String) value);
+// } else {
+// printEscaped(InvokerHelper.toString(value));
+// }
+ tmp << quote
+ def size = entry.getKey() in ['org','name'] ? 35 : 22
+ writer << String.format(" %-${size}s",tmp.toString())
+// printNamespace(entry.getKey(), ctx);
+ }
+ out.print(" " + writer.toString().trim())
+ }
+
+ protected final IndentPrinter out;
+ private String quote;
+ private boolean namespaceAware = true;
+ private boolean preserveWhitespace = false;
+
+ public MyNodePrinter(PrintWriter out) {
+ this(out, " ");
+ }
+
+ public MyNodePrinter(PrintWriter out, String indent) {
+ this(out, indent, "\"");
+ }
+
+ public MyNodePrinter(PrintWriter out, String indent, String quote) {
+ this(new IndentPrinter(out, indent), quote);
+ }
+
+ public MyNodePrinter(IndentPrinter out) {
+ this(out, "\"");
+ }
+
+ public MyNodePrinter(IndentPrinter out, String quote) {
+ if (out == null) {
+ throw new IllegalArgumentException("Argument 'IndentPrinter out' must not be null!");
+ }
+ this.out = out;
+ this.quote = quote;
+ }
+
+ public MyNodePrinter() {
+ this(new PrintWriter(new OutputStreamWriter(System.out)));
+ }
+
+ public void print(Node node) {
+ print(node, new NamespaceContext());
+ }
+
+ /**
+ * Check if namespace handling is enabled.
+ * Defaults to true
.
+ *
+ * @return true if namespace handling is enabled
+ */
+ public boolean isNamespaceAware() {
+ return namespaceAware;
+ }
+
+ /**
+ * Enable and/or disable namespace handling.
+ *
+ * @param namespaceAware the new desired value
+ */
+ public void setNamespaceAware(boolean namespaceAware) {
+ this.namespaceAware = namespaceAware;
+ }
+
+ /**
+ * Check if whitespace preservation is enabled.
+ * Defaults to false
.
+ *
+ * @return true if whitespaces are honoured when printing simple text nodes
+ */
+ public boolean isPreserveWhitespace() {
+ return preserveWhitespace;
+ }
+
+ /**
+ * Enable and/or disable preservation of whitespace.
+ *
+ * @param preserveWhitespace the new desired value
+ */
+ public void setPreserveWhitespace(boolean preserveWhitespace) {
+ this.preserveWhitespace = preserveWhitespace;
+ }
+
+ /**
+ * Get Quote to use when printing attributes.
+ *
+ * @return the quote character
+ */
+ public String getQuote() {
+ return quote;
+ }
+
+ /**
+ * Set Quote to use when printing attributes.
+ *
+ * @param quote the quote character
+ */
+ public void setQuote(String quote) {
+ this.quote = quote;
+ }
+
+ protected void print(Node node, NamespaceContext ctx) {
+ /*
+ * Handle empty elements like '
', ' or '
.
+ */
+ if (isEmptyElement(node)) {
+ printLineBegin();
+ out.print("<");
+ out.print(getName(node));
+ if (ctx != null) {
+ printNamespace(node, ctx);
+ }
+ printNameAttributes(node.attributes(), ctx);
+ out.print("/>");
+ printLineEnd();
+ out.flush();
+ return;
+ }
+
+ /*
+ * Hook for extra processing, e.g. GSP tag element!
+ */
+ if (printSpecialNode(node)) {
+ out.flush();
+ return;
+ }
+
+ /*
+ * Handle normal element like ... .
+ */
+ Object value = node.value();
+ if (value instanceof List) {
+ printName(node, ctx, true, isListOfSimple((List) value));
+ printList((List) value, ctx);
+ printName(node, ctx, false, isListOfSimple((List) value));
+ out.flush();
+ return;
+ }
+
+ // treat as simple type - probably a String
+ printName(node, ctx, true, preserveWhitespace);
+ printSimpleItemWithIndent(value);
+ printName(node, ctx, false, preserveWhitespace);
+ out.flush();
+ }
+
+ private boolean isListOfSimple(List value) {
+ for (Object p : value) {
+ if (p instanceof Node) return false;
+ }
+ return preserveWhitespace;
+ }
+
+ protected void printLineBegin() {
+ out.printIndent();
+ }
+
+ protected void printLineEnd() {
+ printLineEnd(null);
+ }
+
+ protected void printLineEnd(String comment) {
+ if (comment != null) {
+ out.print(" ");
+ }
+ out.println();
+ out.flush();
+ }
+
+ protected void printList(List list, NamespaceContext ctx) {
+ out.incrementIndent();
+ for (Object value : list) {
+ NamespaceContext context = new NamespaceContext(ctx);
+ /*
+ * If the current value is a node, recurse into that node.
+ */
+ if (value instanceof Node) {
+ print((Node) value, context);
+ continue;
+ }
+ printSimpleItem(value);
+ }
+ out.decrementIndent();
+ }
+
+ protected void printSimpleItem(Object value) {
+ if (!preserveWhitespace) printLineBegin();
+ printEscaped(InvokerHelper.toString(value));
+ if (!preserveWhitespace) printLineEnd();
+ }
+
+ protected void printName(Node node, NamespaceContext ctx, boolean begin, boolean preserve) {
+ if (node == null) {
+ throw new NullPointerException("Node must not be null.");
+ }
+ Object name = node.name();
+ if (name == null) {
+ throw new NullPointerException("Name must not be null.");
+ }
+ if (!preserve || begin) printLineBegin();
+ out.print("<");
+ if (!begin) {
+ out.print("/");
+ }
+ out.print(getName(node));
+ if (ctx != null) {
+ printNamespace(node, ctx);
+ }
+ if (begin) {
+ printNameAttributes(node.attributes(), ctx);
+ }
+ out.print(">");
+ if (!preserve || !begin) printLineEnd();
+ }
+
+ protected boolean printSpecialNode(Node node) {
+ return false;
+ }
+
+ protected void printNamespace(Object object, NamespaceContext ctx) {
+ if (namespaceAware) {
+ if (object instanceof Node) {
+ printNamespace(((Node) object).name(), ctx);
+ } else if (object instanceof QName) {
+ QName qname = (QName) object;
+ String namespaceUri = qname.getNamespaceURI();
+ if (namespaceUri != null) {
+ String prefix = qname.getPrefix();
+ if (!ctx.isPrefixRegistered(prefix, namespaceUri)) {
+ ctx.registerNamespacePrefix(prefix, namespaceUri);
+ out.print(" ");
+ out.print("xmlns");
+ if (prefix.length() > 0) {
+ out.print(":");
+ out.print(prefix);
+ }
+ out.print("=" + quote);
+ out.print(namespaceUri);
+ out.print(quote);
+ }
+ }
+ }
+ }
+ }
+
+
+
+ private boolean isEmptyElement(Node node) {
+ if (node == null) {
+ throw new IllegalArgumentException("Node must not be null!");
+ }
+ if (!node.children().isEmpty()) {
+ return false;
+ }
+ return node.text().length() == 0;
+ }
+
+ private String getName(Object object) {
+ if (object instanceof String) {
+ return (String) object;
+ } else if (object instanceof QName) {
+ QName qname = (QName) object;
+ if (!namespaceAware) {
+ return qname.getLocalPart();
+ }
+ return qname.getQualifiedName();
+ } else if (object instanceof Node) {
+ Object name = ((Node) object).name();
+ return getName(name);
+ }
+ return object.toString();
+ }
+
+ private void printSimpleItemWithIndent(Object value) {
+ if (!preserveWhitespace) out.incrementIndent();
+ printSimpleItem(value);
+ if (!preserveWhitespace) out.decrementIndent();
+ }
+
+ // For ' and " we only escape if needed. As far as XML is concerned,
+ // we could always escape if we wanted to.
+ private void printEscaped(String s) {
+ for (int i = 0; i < s.length(); i++) {
+ char c = s.charAt(i);
+ switch (c) {
+ case '<':
+ out.print("<");
+ break;
+ case '>':
+ out.print(">");
+ break;
+ case '&':
+ out.print("&");
+ break;
+ case '\'':
+ if (quote.equals("'"))
+ out.print("'");
+ else
+ out.print(c);
+ break;
+ case '"':
+ if (quote.equals("\""))
+ out.print(""");
+ else
+ out.print(c);
+ break;
+ default:
+ out.print(c);
+ }
+ }
+ }
+
+ protected class NamespaceContext {
+ private final Map namespaceMap;
+
+ public NamespaceContext() {
+ namespaceMap = new HashMap();
+ }
+
+ public NamespaceContext(NamespaceContext context) {
+ this();
+ namespaceMap.putAll(context.namespaceMap);
+ }
+
+ public boolean isPrefixRegistered(String prefix, String uri) {
+ return namespaceMap.containsKey(prefix) && namespaceMap.get(prefix).equals(uri);
+ }
+
+ public void registerNamespacePrefix(String prefix, String uri) {
+ if (!isPrefixRegistered(prefix, uri)) {
+ namespaceMap.put(prefix, uri);
+ }
+ }
+
+ public String getNamespace(String prefix) {
+ Object uri = namespaceMap.get(prefix);
+ return (uri == null) ? null : uri.toString();
+ }
+ }
+}
\ No newline at end of file