diff options
Diffstat (limited to 'xml/src')
-rw-r--r-- | xml/src/main/native/org_apache_harmony_xml_ExpatParser.cpp | 35 | ||||
-rw-r--r-- | xml/src/test/java/org/apache/harmony/xml/NamespacedAttributesLookupTest.java | 139 |
2 files changed, 152 insertions, 22 deletions
diff --git a/xml/src/main/native/org_apache_harmony_xml_ExpatParser.cpp b/xml/src/main/native/org_apache_harmony_xml_ExpatParser.cpp index 1944bdc..4721800 100644 --- a/xml/src/main/native/org_apache_harmony_xml_ExpatParser.cpp +++ b/xml/src/main/native/org_apache_harmony_xml_ExpatParser.cpp @@ -471,7 +471,9 @@ public: } /** - * Returns the element or attribute local name, like "h1". Never empty. + * Returns the element or attribute local name, like "h1". Never empty. When + * namespace processing is disabled, this may contain a prefix, yielding a + * local name like "html:h1". In such cases, the qName will always be empty. */ jstring localName() { return internString(mEnv, mParsingContext, mLocalName); @@ -504,13 +506,17 @@ public: bool matchesQName(const char* qName) { char* lastColon = strrchr(qName, ':'); - // if the input doesn't have a colon, there's no namespace prefix. Our - // prefix must be empty and the qName must equal our localName - if (lastColon == NULL) { - return strlen(mPrefix) == 0 && strcmp(qName, mLocalName) == 0; + // Compare local names only if either: + // - the input qualified name doesn't have a colon (like "h1") + // - this element doesn't have a prefix. Such is the case when it + // doesn't belong to a namespace, or when this parser's namespace + // processing is disabled. In the latter case, this element's local + // name may still contain a colon (like "html:h1"). + if (lastColon == NULL || *mPrefix == 0) { + return strcmp(qName, mLocalName) == 0; } - // otherwise the prefixes must be equal and our localName must equal qName + // Otherwise compare both prefix and local name size_t prefixLength = lastColon - qName; return strlen(mPrefix) == prefixLength && strncmp(qName, mPrefix, prefixLength) == 0 @@ -1004,7 +1010,7 @@ static void releaseParsingContext(JNIEnv* env, ParsingContext* context) { } /** - * Creates a new Expat parser. Called from the Java ExpatParser contructor. + * Creates a new Expat parser. Called from the Java ExpatParser constructor. * * @param object the Java ExpatParser instance * @param javaEncoding the character encoding name @@ -1208,11 +1214,6 @@ static jstring getAttributeURI(JNIEnv* env, jobject clazz, jint pointer, jint attributePointer, jint index) { XML_Parser parser = (XML_Parser) pointer; ParsingContext* context = (ParsingContext*) XML_GetUserData(parser); - - if (!context->processNamespaces) { - return emptyString; - } - return ExpatElementName(env, context, attributePointer, index).uri(); } @@ -1229,11 +1230,6 @@ static jstring getAttributeLocalName(JNIEnv* env, jobject clazz, jint pointer, jint attributePointer, jint index) { XML_Parser parser = (XML_Parser) pointer; ParsingContext* context = (ParsingContext*) XML_GetUserData(parser); - - if (!context->processNamespaces) { - return emptyString; - } - return ExpatElementName(env, context, attributePointer, index).localName(); } @@ -1250,11 +1246,6 @@ static jstring getAttributeQName(JNIEnv* env, jobject clazz, jint pointer, jint attributePointer, jint index) { XML_Parser parser = (XML_Parser) pointer; ParsingContext* context = (ParsingContext*) XML_GetUserData(parser); - - if (context->processNamespaces) { - return emptyString; - } - return ExpatElementName(env, context, attributePointer, index).qName(); } diff --git a/xml/src/test/java/org/apache/harmony/xml/NamespacedAttributesLookupTest.java b/xml/src/test/java/org/apache/harmony/xml/NamespacedAttributesLookupTest.java new file mode 100644 index 0000000..4f58262 --- /dev/null +++ b/xml/src/test/java/org/apache/harmony/xml/NamespacedAttributesLookupTest.java @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.xml; + +import junit.framework.TestCase; +import org.xml.sax.Attributes; +import org.xml.sax.InputSource; +import org.xml.sax.XMLReader; +import org.xml.sax.helpers.DefaultHandler; + +import javax.xml.parsers.SAXParserFactory; +import java.io.StringReader; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * Tests that we both report and retrieve attributes using the appropriate + * names for different combinations of namespaces and namespace prefixes. + */ +public class NamespacedAttributesLookupTest extends TestCase { + + private static final String SAX_PROPERTY_NS = + "http://xml.org/sax/features/namespaces"; + private static final String SAX_PROPERTY_NS_PREFIXES = + "http://xml.org/sax/features/namespace-prefixes"; + + private static String xml = "<?xml version='1.0' encoding='UTF-8'?>" + + "<test xmlns='http://foo' xmlns:bar='http://bar' xmlns:baz='http://baz' baz:c='a'>" + + "<b c='w' bar:c='x'/>" + + "<bar:e baz:c='y' bar:c='z'/>" + + "</test>"; + + public void testNamespace() throws Exception { + List<String> expected = Arrays.asList( + "http://foo,test\n" + + " http://baz,c\n" + + " http://bar+c=null,\n" + + " bar:c=null\n", + + "http://foo,b\n" + + " ,c\n" + + " http://bar,c\n" + + " http://bar+c=x,\n" + + " bar:c=x\n", + + "http://bar,e\n" + + " http://baz,c\n" + + " http://bar,c\n" + + " http://bar+c=z,\n" + + " bar:c=z\n"); + + boolean namespace = true; + boolean namespacePrefixes = false; + assertEquals(expected, getStartElements(xml, namespace, namespacePrefixes)); + } + + public void testNamespacePrefixes() throws Exception { + List<String> expected = Arrays.asList( + "test\n" + + " xmlns\n" + + " xmlns:bar\n" + + " xmlns:baz\n" + + " baz:c\n" + + " http://bar+c=null,\n" + + " bar:c=null\n", + + "b\n" + + " c\n" + + " bar:c\n" + + " http://bar+c=null,\n" + + " bar:c=x\n", + + "bar:e\n" + + " baz:c\n" + + " bar:c\n" + + " http://bar+c=null,\n" + + " bar:c=z\n"); + + boolean namespace = false; + boolean namespacePrefixes = true; + assertEquals(expected, getStartElements(xml, namespace, namespacePrefixes)); + } + + public List<String> getStartElements(String xml, final boolean namespace, boolean namespacePrefixes) + throws Exception { + final List<String> result = new ArrayList<String>(); + XMLReader reader = SAXParserFactory.newInstance().newSAXParser().getXMLReader(); + reader.setFeature(SAX_PROPERTY_NS, namespace); + reader.setFeature(SAX_PROPERTY_NS_PREFIXES, namespacePrefixes); + reader.setContentHandler(new DefaultHandler() { + @Override public final void startElement( + String uri, String localName, String qName, Attributes attributes) { + StringBuilder serialized = new StringBuilder(); + /* + * Only supply the uri+localName or qname depending on whether namespaces are + * enabled. It's an optional parameter and the RI only supplies one or the other. + */ + if (namespace) { + serialized.append(uri).append(","); + serialized.append(localName); + } else { + serialized.append(qName); + } + for (int i = 0; i < attributes.getLength(); i++) { + serialized.append("\n "); + if (namespace) { + serialized.append(attributes.getURI(i)).append(","); + serialized.append(attributes.getLocalName(i)); + } else { + serialized.append(attributes.getQName(i)); + } + } + serialized.append("\n http://bar+c=") + .append(attributes.getValue("http://bar", "c")).append(",") + .append("\n bar:c=") + .append(attributes.getValue("bar:c")) + .append("\n"); + result.add(serialized.toString()); + } + }); + reader.parse(new InputSource(new StringReader(xml))); + return result; + } +} |