summaryrefslogtreecommitdiffstats
path: root/xml/src
diff options
context:
space:
mode:
authorJesse Wilson <jessewilson@google.com>2010-03-11 15:07:44 -0800
committerAndroid Git Automerger <android-git-automerger@android.com>2010-03-11 15:07:44 -0800
commit1e6bc5dd2eb246c96c19ee0b16d6d61b825a8c8c (patch)
tree7fdb03f5d01f0bf66461496922371b12ac4dd017 /xml/src
parentb0085739f5fa7a416840bc7722ef40d30d8d10f3 (diff)
parentc6dc33d084214a07fb5599832f3bfb266d06fbf9 (diff)
downloadlibcore-1e6bc5dd2eb246c96c19ee0b16d6d61b825a8c8c.zip
libcore-1e6bc5dd2eb246c96c19ee0b16d6d61b825a8c8c.tar.gz
libcore-1e6bc5dd2eb246c96c19ee0b16d6d61b825a8c8c.tar.bz2
am 6f9b4d2b: Merge "Implementing getBaseUri() for DOM."
Merge commit '6f9b4d2bdccb2ea5e548b908e5cc882d262d0940' into dalvik-dev * commit '6f9b4d2bdccb2ea5e548b908e5cc882d262d0940': Implementing getBaseUri() for DOM.
Diffstat (limited to 'xml/src')
-rw-r--r--xml/src/main/java/org/apache/harmony/xml/dom/NodeImpl.java109
-rw-r--r--xml/src/test/java/tests/xml/DomTest.java132
2 files changed, 212 insertions, 29 deletions
diff --git a/xml/src/main/java/org/apache/harmony/xml/dom/NodeImpl.java b/xml/src/main/java/org/apache/harmony/xml/dom/NodeImpl.java
index 5940417..2a8e1fa 100644
--- a/xml/src/main/java/org/apache/harmony/xml/dom/NodeImpl.java
+++ b/xml/src/main/java/org/apache/harmony/xml/dom/NodeImpl.java
@@ -16,6 +16,8 @@
package org.apache.harmony.xml.dom;
+import org.apache.xml.serializer.utils.SystemIDResolver;
+import org.apache.xml.utils.URI;
import org.w3c.dom.Attr;
import org.w3c.dom.CharacterData;
import org.w3c.dom.DOMException;
@@ -27,6 +29,7 @@ import org.w3c.dom.NodeList;
import org.w3c.dom.ProcessingInstruction;
import org.w3c.dom.UserDataHandler;
+import javax.xml.transform.TransformerException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -244,35 +247,83 @@ public abstract class NodeImpl implements Node {
return matchesName(namespaceURI, getNamespaceURI(), wildcard) && matchesName(localName, getLocalName(), wildcard);
}
- public String getBaseURI() {
- /*
- * TODO: implement. For reference, here's Xerces' behaviour:
- *
- * In all cases, the returned URI should be sanitized before it is
- * returned. If the URI is malformed, null should be returned instead.
- *
- * For document nodes, this should return a member field that's
- * initialized by the parser.
- *
- * For element nodes, this should first look for the xml:base attribute.
- * if that exists and is absolute, it should be returned.
- * if that exists and is relative, it should be resolved to the parent's base URI
- * if it doesn't exist, the parent's baseURI should be returned
- *
- * For entity nodes, if a base URI exists that should be returned.
- * Otherwise the document's base URI should be returned
- *
- * For entity references, if a base URI exists that should be returned
- * otherwise it dereferences the entity (via the document) and uses the
- * entity's base URI.
- *
- * For notations, it returns the base URI field.
- *
- * For processing instructions, it returns the parent's base URI.
- *
- * For all other node types, it returns null.
- */
- return null;
+ public final String getBaseURI() {
+ switch (getNodeType()) {
+ case DOCUMENT_NODE:
+ return sanitizeUri(((Document) this).getDocumentURI());
+
+ case ELEMENT_NODE:
+ Element element = (Element) this;
+ String uri = element.getAttributeNS(
+ "http://www.w3.org/XML/1998/namespace", "base"); // or "xml:base"
+
+ // if this node has no base URI, return the parent's.
+ if (uri == null || uri.length() == 0) {
+ return getParentBaseUri();
+ }
+
+ // if this node's URI is absolute, return that
+ if (SystemIDResolver.isAbsoluteURI(uri)) {
+ return uri;
+ }
+
+ // this node has a relative URI. Try to resolve it against the
+ // parent, but if that doesn't work just give up and return null.
+ String parentUri = getParentBaseUri();
+ if (parentUri == null) {
+ return null;
+ }
+ try {
+ return SystemIDResolver.getAbsoluteURI(uri, parentUri);
+ } catch (TransformerException e) {
+ return null; // the spec requires that we swallow exceptions
+ }
+
+ case PROCESSING_INSTRUCTION_NODE:
+ return getParentBaseUri();
+
+ case NOTATION_NODE:
+ case ENTITY_NODE:
+ // When we support these node types, the parser should
+ // initialize a base URI field on these nodes.
+ return null;
+
+ case ENTITY_REFERENCE_NODE:
+ // TODO: get this value from the parser, falling back to the
+ // referenced entity's baseURI if that doesn't exist
+ return null;
+
+ case DOCUMENT_TYPE_NODE:
+ case DOCUMENT_FRAGMENT_NODE:
+ case ATTRIBUTE_NODE:
+ case TEXT_NODE:
+ case CDATA_SECTION_NODE:
+ case COMMENT_NODE:
+ return null;
+
+ default:
+ throw new DOMException(DOMException.NOT_SUPPORTED_ERR,
+ "Unsupported node type " + getNodeType());
+ }
+ }
+
+ private String getParentBaseUri() {
+ Node parentNode = getParentNode();
+ return parentNode != null ? parentNode.getBaseURI() : null;
+ }
+
+ /**
+ * Returns the sanitized input if it is a URI, or {@code null} otherwise.
+ */
+ private String sanitizeUri(String uri) {
+ if (uri == null || uri.length() == 0) {
+ return null;
+ }
+ try {
+ return new URI(uri).toString();
+ } catch (URI.MalformedURIException e) {
+ return null;
+ }
}
public short compareDocumentPosition(Node other)
diff --git a/xml/src/test/java/tests/xml/DomTest.java b/xml/src/test/java/tests/xml/DomTest.java
index a5fdbd8..0f67c64 100644
--- a/xml/src/test/java/tests/xml/DomTest.java
+++ b/xml/src/test/java/tests/xml/DomTest.java
@@ -45,6 +45,8 @@ import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
+import java.io.File;
+import java.io.FileWriter;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.ArrayList;
@@ -1006,6 +1008,136 @@ public class DomTest extends TestCase {
assertEquals(expected, handler.calls);
}
+ public void testBaseUriRelativeUriResolution() throws Exception {
+ File file = File.createTempFile("DomTest.java", "xml");
+ File parentFile = file.getParentFile();
+ FileWriter writer = new FileWriter(file);
+ writer.write("<a>"
+ + " <b xml:base=\"b1/b2\">"
+ + " <c>"
+ + " <d xml:base=\"../d1/d2\"><e/></d>"
+ + " </c>"
+ + " </b>"
+ + " <h xml:base=\"h1/h2/\">"
+ + " <i xml:base=\"../i1/i2\"/>"
+ + " </h>"
+ + "</a>");
+ writer.close();
+ document = builder.parse(file);
+
+ assertFileUriEquals("", file.getPath(), document.getBaseURI());
+ assertFileUriEquals("", file.getPath(), document.getDocumentURI());
+ Element a = document.getDocumentElement();
+ assertFileUriEquals("", file.getPath(), a.getBaseURI());
+
+ String message = "This implementation's getBaseURI() doesn't handle relative URIs";
+ Element b = (Element) a.getChildNodes().item(1);
+ Element c = (Element) b.getChildNodes().item(1);
+ Element d = (Element) c.getChildNodes().item(1);
+ Element e = (Element) d.getChildNodes().item(0);
+ Element h = (Element) a.getChildNodes().item(3);
+ Element i = (Element) h.getChildNodes().item(1);
+ assertFileUriEquals(message, parentFile + "/b1/b2", b.getBaseURI());
+ assertFileUriEquals(message, parentFile + "/b1/b2", c.getBaseURI());
+ assertFileUriEquals(message, parentFile + "/d1/d2", d.getBaseURI());
+ assertFileUriEquals(message, parentFile + "/d1/d2", e.getBaseURI());
+ assertFileUriEquals(message, parentFile + "/h1/h2/", h.getBaseURI());
+ assertFileUriEquals(message, parentFile + "/h1/i1/i2", i.getBaseURI());
+ }
+
+ /**
+ * Regrettably both "file:/tmp/foo.txt" and "file:///tmp/foo.txt" are
+ * legal URIs, and different implementations emit different forms.
+ */
+ private void assertFileUriEquals(
+ String message, String expectedFile, String actual) {
+ if (!("file:" + expectedFile).equals(actual)
+ && !("file://" + expectedFile).equals(actual)) {
+ fail("Expected URI for: " + expectedFile
+ + " but was " + actual + ". " + message);
+ }
+ }
+
+ /**
+ * According to the <a href="http://www.w3.org/TR/xmlbase/">XML Base</a>
+ * spec, fragments (like "#frag" or "") should not be dereferenced.
+ */
+ public void testBaseUriResolutionWithHashes() throws Exception {
+ document = builder.parse(new InputSource(new StringReader(
+ "<a xml:base=\"http://a1/a2\">"
+ + " <b xml:base=\"b1#b2\"/>"
+ + " <c xml:base=\"#c1\">"
+ + " <d xml:base=\"\"/>"
+ + " </c>"
+ + " <e xml:base=\"\"/>"
+ + "</a>")));
+ Element a = document.getDocumentElement();
+ assertEquals("http://a1/a2", a.getBaseURI());
+
+ String message = "This implementation's getBaseURI() doesn't handle "
+ + "relative URIs with hashes";
+ Element b = (Element) a.getChildNodes().item(1);
+ Element c = (Element) a.getChildNodes().item(3);
+ Element d = (Element) c.getChildNodes().item(1);
+ Element e = (Element) a.getChildNodes().item(5);
+ assertEquals(message, "http://a1/b1#b2", b.getBaseURI());
+ assertEquals(message, "http://a1/a2#c1", c.getBaseURI());
+ assertEquals(message, "http://a1/a2#c1", d.getBaseURI());
+ assertEquals(message, "http://a1/a2", e.getBaseURI());
+ }
+
+ public void testBaseUriInheritedForProcessingInstructions() {
+ document.setDocumentURI("http://d1/d2");
+ assertEquals("http://d1/d2", wafflemaker.getBaseURI());
+ }
+
+ public void testBaseUriInheritedForEntities() {
+ if (sp == null) {
+ return;
+ }
+ document.setDocumentURI("http://d1/d2");
+ assertEquals("http://d1/d2", sp.getBaseURI());
+ }
+
+ public void testBaseUriNotInheritedForNotations() {
+ if (png == null) {
+ return;
+ }
+ document.setDocumentURI("http://d1/d2");
+ assertNull(png.getBaseURI());
+ }
+
+ public void testBaseUriNotInheritedForDoctypes() {
+ document.setDocumentURI("http://d1/d2");
+ assertNull(doctype.getBaseURI());
+ }
+
+ public void testBaseUriNotInheritedForAttributes() {
+ document.setDocumentURI("http://d1/d2");
+ assertNull(itemXmlns.getBaseURI());
+ assertNull(itemXmlnsA.getBaseURI());
+ assertNull(standard.getBaseURI());
+ assertNull(vitaminsXmlnsA.getBaseURI());
+ }
+
+ public void testBaseUriNotInheritedForTextsOrCdatas() {
+ document.setDocumentURI("http://d1/d2");
+ assertNull(descriptionText1.getBaseURI());
+ assertNull(descriptionText2.getBaseURI());
+ assertNull(option2Reference.getBaseURI());
+ }
+
+ public void testBaseUriNotInheritedForComments() {
+ document.setDocumentURI("http://d1/d2");
+ assertNull(descriptionText1.getBaseURI());
+ assertNull(descriptionText2.getBaseURI());
+ }
+
+ public void testBaseUriNotInheritedForEntityReferences() {
+ document.setDocumentURI("http://d1/d2");
+ assertNull(option2Reference.getBaseURI());
+ }
+
private class RecordingHandler implements UserDataHandler {
final Set<String> calls = new HashSet<String>();
public void handle(short operation, String key, Object data, Node src, Node dst) {