diff options
author | Jesse Wilson <jessewilson@google.com> | 2010-03-11 15:07:44 -0800 |
---|---|---|
committer | Android Git Automerger <android-git-automerger@android.com> | 2010-03-11 15:07:44 -0800 |
commit | 1e6bc5dd2eb246c96c19ee0b16d6d61b825a8c8c (patch) | |
tree | 7fdb03f5d01f0bf66461496922371b12ac4dd017 /xml/src | |
parent | b0085739f5fa7a416840bc7722ef40d30d8d10f3 (diff) | |
parent | c6dc33d084214a07fb5599832f3bfb266d06fbf9 (diff) | |
download | libcore-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.java | 109 | ||||
-rw-r--r-- | xml/src/test/java/tests/xml/DomTest.java | 132 |
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) { |