Mercurial > public > develkit
changeset 89:15f4da8bdbd3
add ability to control order of attributes, whitespace. more cleanup up of dependencies and exclusions
author | smith@nwoca.org |
---|---|
date | Fri, 17 Feb 2012 15:09:35 +0000 |
parents | 9f2ab59a5333 |
children | c207cdcaf13e |
files | fix-ivy.groovy fixivy.groovy |
diffstat | 2 files changed, 572 insertions(+), 489 deletions(-) [+] |
line wrap: on
line diff
--- 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 <code>true</code>. - * - * @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 <code>false</code>. - * - * @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 '<br/>', '<img/> or '<hr noshade="noshade"/>. - */ - 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 <html> ... </html>. - */ - 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.print(comment); - 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<String, String> namespaceMap; - - public NamespaceContext() { - namespaceMap = new HashMap<String, String>(); - } - - 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
--- /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 <code>true</code>. + * + * @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 <code>false</code>. + * + * @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 '<br/>', '<img/> or '<hr noshade="noshade"/>. + */ + 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 <html> ... </html>. + */ + 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.print(comment); + 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<String, String> namespaceMap; + + public NamespaceContext() { + namespaceMap = new HashMap<String, String>(); + } + + 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