Browse Source

Add NS support to DOMElementWriter

git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@357117 13f79535-47bb-0310-9956-ffa450edef68
master
Stefan Bodewig 19 years ago
parent
commit
b7b59490a8
2 changed files with 267 additions and 2 deletions
  1. +157
    -2
      src/main/org/apache/tools/ant/util/DOMElementWriter.java
  2. +110
    -0
      src/testcases/org/apache/tools/ant/util/DOMElementWriterTest.java

+ 157
- 2
src/main/org/apache/tools/ant/util/DOMElementWriter.java View File

@@ -21,6 +21,9 @@ import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.OutputStreamWriter; import java.io.OutputStreamWriter;
import java.io.Writer; import java.io.Writer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import org.w3c.dom.Attr; import org.w3c.dom.Attr;
import org.w3c.dom.Element; import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap; import org.w3c.dom.NamedNodeMap;
@@ -30,7 +33,6 @@ import org.w3c.dom.Text;


/** /**
* Writes a DOM tree to a given Writer. * Writes a DOM tree to a given Writer.
* warning: this utility currently does not declare XML Namespaces.
* <p>Utility class used by {@link org.apache.tools.ant.XmlLogger * <p>Utility class used by {@link org.apache.tools.ant.XmlLogger
* XmlLogger} and * XmlLogger} and
* org.apache.tools.ant.taskdefs.optional.junit.XMLJUnitResultFormatter * org.apache.tools.ant.taskdefs.optional.junit.XMLJUnitResultFormatter
@@ -39,24 +41,99 @@ import org.w3c.dom.Text;
*/ */
public class DOMElementWriter { public class DOMElementWriter {


/** prefix for genefrated prefixes */
private static final String NS = "ns";

/** xml declaration is on by default */ /** xml declaration is on by default */
private boolean xmlDeclaration=true; private boolean xmlDeclaration=true;


/**
* XML Namespaces are ignored by default.
*/
private XmlNamespacePolicy namespacePolicy = XmlNamespacePolicy.IGNORE;

/**
* Map (URI to prefix) of known namespaces.
*/
private HashMap nsPrefixMap = new HashMap();

/**
* Number of generated prefix to use next.
*/
private int nextPrefix = 0;

/**
* Map (Element to URI) of namespaces defined on a given element.
*/
private HashMap nsURIByElement = new HashMap();

/**
* Whether namespaces should be ignored for elements and attributes.
*
* @since Ant 1.7
*/
public static class XmlNamespacePolicy {
private boolean qualifyElements;
private boolean qualifyAttributes;

/**
* Ignores namespaces for elements and attributes, the default.
*/
public static final XmlNamespacePolicy IGNORE =
new XmlNamespacePolicy(false, false);

/**
* Ignores namespaces for attributes.
*/
public static final XmlNamespacePolicy ONLY_QUALIFY_ELEMENTS =
new XmlNamespacePolicy(true, false);

/**
* Qualifies namespaces for elements and attributes.
*/
public static final XmlNamespacePolicy QUALIFY_ALL =
new XmlNamespacePolicy(true, true);

/**
* @param qualifyElements whether to qualify elements
* @param qualifyAttributes whether to qualify elements
*/
public XmlNamespacePolicy(boolean qualifyElements,
boolean qualifyAttributes) {
this.qualifyElements = qualifyElements;
this.qualifyAttributes = qualifyAttributes;
}
}

/** /**
* Create an element writer. * Create an element writer.
* The ?xml? declaration will be included.
* The ?xml? declaration will be included, namespaces ignored.
*/ */
public DOMElementWriter() { public DOMElementWriter() {
} }


/** /**
* Create an element writer * Create an element writer
* XML namespaces will be ignored.
* @param xmlDeclaration flag to indicate whether the ?xml? declaration * @param xmlDeclaration flag to indicate whether the ?xml? declaration
* should be included. * should be included.
* @since Ant1.7 * @since Ant1.7
*/ */
public DOMElementWriter(boolean xmlDeclaration) { public DOMElementWriter(boolean xmlDeclaration) {
this(xmlDeclaration, XmlNamespacePolicy.IGNORE);
}

/**
* Create an element writer
* XML namespaces will be ignored.
* @param xmlDeclaration flag to indicate whether the ?xml? declaration
* should be included.
* @since Ant1.7
*/
public DOMElementWriter(boolean xmlDeclaration,
XmlNamespacePolicy namespacePolicy) {
this.xmlDeclaration = xmlDeclaration; this.xmlDeclaration = xmlDeclaration;
this.namespacePolicy = namespacePolicy;
} }


private static String lSep = System.getProperty("line.separator"); private static String lSep = System.getProperty("line.separator");
@@ -200,6 +277,23 @@ public class DOMElementWriter {


// Write element // Write element
out.write("<"); out.write("<");
if (namespacePolicy.qualifyElements) {
String prefix = (String) nsPrefixMap.get(element.getNamespaceURI());
if (prefix == null) {
if (nsPrefixMap.isEmpty()) {
// steal default namespace
prefix = "";
} else {
prefix = NS + (nextPrefix++);
}
nsPrefixMap.put(element.getNamespaceURI(), prefix);
addNSDefinition(element, element.getNamespaceURI());
}
if (!"".equals(prefix)) {
out.write(prefix);
out.write(":");
}
}
out.write(element.getTagName()); out.write(element.getTagName());


// Write attributes // Write attributes
@@ -207,14 +301,45 @@ public class DOMElementWriter {
for (int i = 0; i < attrs.getLength(); i++) { for (int i = 0; i < attrs.getLength(); i++) {
Attr attr = (Attr) attrs.item(i); Attr attr = (Attr) attrs.item(i);
out.write(" "); out.write(" ");
if (namespacePolicy.qualifyAttributes) {
String prefix =
(String) nsPrefixMap.get(attr.getNamespaceURI());
if (prefix == null) {
prefix = NS + (nextPrefix++);
nsPrefixMap.put(attr.getNamespaceURI(), prefix);
addNSDefinition(element, attr.getNamespaceURI());
}
out.write(prefix);
out.write(":");
}
out.write(attr.getName()); out.write(attr.getName());
out.write("=\""); out.write("=\"");
out.write(encode(attr.getValue())); out.write(encode(attr.getValue()));
out.write("\""); out.write("\"");
} }

// write namespace declarations
ArrayList al = (ArrayList) nsURIByElement.get(element);
if (al != null) {
Iterator iter = al.iterator();
while (iter.hasNext()) {
String uri = (String) iter.next();
String prefix = (String) nsPrefixMap.get(uri);
out.write(" xmlns");
if (!"".equals(prefix)) {
out.write(":");
out.write(prefix);
}
out.write("=\"");
out.write(uri);
out.write("\"");
}
}

if (hasChildren) { if (hasChildren) {
out.write(">"); out.write(">");
} else { } else {
removeNSDefinitions(element);
out.write(" />"); out.write(" />");
out.write(lSep); out.write(lSep);
out.flush(); out.flush();
@@ -245,6 +370,16 @@ public class DOMElementWriter {


// Write element close // Write element close
out.write("</"); out.write("</");
if (namespacePolicy.qualifyElements
|| namespacePolicy.qualifyAttributes) {
String prefix =
(String) nsPrefixMap.get(element.getNamespaceURI());
if (prefix != null && !"".equals(prefix)) {
out.write(prefix);
out.write(":");
}
removeNSDefinitions(element);
}
out.write(element.getTagName()); out.write(element.getTagName());
out.write(">"); out.write(">");
out.write(lSep); out.write(lSep);
@@ -393,4 +528,24 @@ public class DOMElementWriter {
} }
return false; return false;
} }

private void removeNSDefinitions(Element element) {
ArrayList al = (ArrayList) nsURIByElement.get(element);
if (al != null) {
Iterator iter = al.iterator();
while (iter.hasNext()) {
nsPrefixMap.remove(iter.next());
}
nsURIByElement.remove(element);
}
}

private void addNSDefinition(Element element, String uri) {
ArrayList al = (ArrayList) nsURIByElement.get(element);
if (al == null) {
al = new ArrayList();
nsURIByElement.put(element, al);
}
al.add(uri);
}
} }

+ 110
- 0
src/testcases/org/apache/tools/ant/util/DOMElementWriterTest.java View File

@@ -143,4 +143,114 @@ public class DOMElementWriterTest extends TestCase {
sw.toString()); sw.toString());
} }


public void testNoNSPrefixByDefault() throws IOException {
Document d = DOMUtils.newDocument();
Element root = d.createElementNS("urn:foo", "root");
root.setAttributeNS("urn:foo2", "bar", "baz");

StringWriter sw = new StringWriter();
DOMElementWriter w = new DOMElementWriter();
w.write(root, sw, 0, " ");
assertEquals("<root bar=\"baz\" />"
+ StringUtils.LINE_SEP, sw.toString());
}

public void testNSOnElement() throws IOException {
Document d = DOMUtils.newDocument();
Element root = d.createElementNS("urn:foo", "root");
root.setAttributeNS("urn:foo2", "bar", "baz");

StringWriter sw = new StringWriter();
DOMElementWriter w =
new DOMElementWriter(false,
DOMElementWriter.XmlNamespacePolicy
.ONLY_QUALIFY_ELEMENTS);
w.write(root, sw, 0, " ");
assertEquals("<root bar=\"baz\" xmlns=\"urn:foo\" />"
+ StringUtils.LINE_SEP, sw.toString());
}

public void testNSPrefixOnAttribute() throws IOException {
Document d = DOMUtils.newDocument();
Element root = d.createElementNS("urn:foo", "root");
root.setAttributeNS("urn:foo2", "bar", "baz");

StringWriter sw = new StringWriter();
DOMElementWriter w =
new DOMElementWriter(false,
DOMElementWriter.XmlNamespacePolicy
.QUALIFY_ALL);
w.write(root, sw, 0, " ");
assertEquals("<root ns0:bar=\"baz\" xmlns=\"urn:foo\""
+ " xmlns:ns0=\"urn:foo2\" />"
+ StringUtils.LINE_SEP, sw.toString());
}

public void testNSPrefixOnAttributeEvenWithoutElement() throws IOException {
Document d = DOMUtils.newDocument();
Element root = d.createElementNS("urn:foo", "root");
root.setAttributeNS("urn:foo2", "bar", "baz");

StringWriter sw = new StringWriter();
DOMElementWriter w =
new DOMElementWriter(false,
new DOMElementWriter.XmlNamespacePolicy(false,
true)
);
w.write(root, sw, 0, " ");
assertEquals("<root ns0:bar=\"baz\" xmlns:ns0=\"urn:foo2\" />"
+ StringUtils.LINE_SEP, sw.toString());
}

public void testNSGetsReused() throws IOException {
Document d = DOMUtils.newDocument();
Element root = d.createElementNS("urn:foo", "root");
Element child = d.createElementNS("urn:foo", "child");
root.appendChild(child);
StringWriter sw = new StringWriter();
DOMElementWriter w =
new DOMElementWriter(false,
DOMElementWriter.XmlNamespacePolicy
.ONLY_QUALIFY_ELEMENTS);
w.write(root, sw, 0, " ");
assertEquals("<root xmlns=\"urn:foo\">"
+ StringUtils.LINE_SEP
+ " <child />"
+ StringUtils.LINE_SEP
+ "</root>"
+ StringUtils.LINE_SEP, sw.toString());
}

public void testNSGoesOutOfScope() throws IOException {
Document d = DOMUtils.newDocument();
Element root = d.createElementNS("urn:foo", "root");
Element child = d.createElementNS("urn:foo2", "child");
root.appendChild(child);
Element child2 = d.createElementNS("urn:foo2", "child");
root.appendChild(child2);
Element grandChild = d.createElementNS("urn:foo2", "grandchild");
child2.appendChild(grandChild);
Element child3 = d.createElementNS("urn:foo2", "child");
root.appendChild(child3);
StringWriter sw = new StringWriter();
DOMElementWriter w =
new DOMElementWriter(false,
DOMElementWriter.XmlNamespacePolicy
.ONLY_QUALIFY_ELEMENTS);
w.write(root, sw, 0, " ");
assertEquals("<root xmlns=\"urn:foo\">"
+ StringUtils.LINE_SEP
+ " <ns0:child xmlns:ns0=\"urn:foo2\" />"
+ StringUtils.LINE_SEP
+ " <ns1:child xmlns:ns1=\"urn:foo2\">"
+ StringUtils.LINE_SEP
+ " <ns1:grandchild />"
+ StringUtils.LINE_SEP
+ " </ns1:child>"
+ StringUtils.LINE_SEP
+ " <ns2:child xmlns:ns2=\"urn:foo2\" />"
+ StringUtils.LINE_SEP
+ "</root>"
+ StringUtils.LINE_SEP, sw.toString());
}
} }

Loading…
Cancel
Save