You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commons-dev@ws.apache.org by ve...@apache.org on 2009/01/22 22:13:02 UTC
svn commit: r736795 - in /webservices/commons/trunk/modules/axiom/modules:
axiom-api/src/main/java/org/apache/axiom/om/impl/serialize/
axiom-integration/src/test/java/org/apache/axiom/om/impl/jaxp/
axiom-integration/src/test/resources/org/apache/axiom/...
Author: veithen
Date: Thu Jan 22 13:13:02 2009
New Revision: 736795
URL: http://svn.apache.org/viewvc?rev=736795&view=rev
Log:
Fixed a subtle issue in OMXMLReader related to namespace declarations (see the comments in the code and unit tests for more details). Should fix SYNAPSE-501 on trunk.
Modified:
webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/om/impl/serialize/OMXMLReader.java
webservices/commons/trunk/modules/axiom/modules/axiom-integration/src/test/java/org/apache/axiom/om/impl/jaxp/TransformerTest.java
webservices/commons/trunk/modules/axiom/modules/axiom-integration/src/test/resources/org/apache/axiom/om/impl/jaxp/test.xml
Modified: webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/om/impl/serialize/OMXMLReader.java
URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/om/impl/serialize/OMXMLReader.java?rev=736795&r1=736794&r2=736795&view=diff
==============================================================================
--- webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/om/impl/serialize/OMXMLReader.java (original)
+++ webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/om/impl/serialize/OMXMLReader.java Thu Jan 22 13:13:02 2009
@@ -21,11 +21,14 @@
import java.io.IOException;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
+import java.util.Set;
import org.apache.axiom.om.OMAttribute;
import org.apache.axiom.om.OMComment;
+import org.apache.axiom.om.OMContainer;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMNamespace;
import org.apache.axiom.om.OMNode;
@@ -46,6 +49,18 @@
* SAX {@link XMLReader} implementation that traverses a given OM tree and invokes the
* callback methods on the configured {@link ContentHandler}. This can be used to
* serialize an Axiom tree to SAX.
+ * <p>
+ * This class can also generate SAX events for a subtree. This is the case if the
+ * element passed to the constructor is not the root element of the document. In this
+ * case, care is taken to properly generate <code>startPrefixMapping</code> and
+ * <code>endPrefixMapping</code> events also for namespace mappings declared on the ancestors
+ * of the element.
+ * <p>
+ * To understand why this is important, consider the following example:
+ * <pre><root xmlns:ns="urn:ns"><element attr="ns:someThing"/><root></pre>
+ * In that case, to correctly interpret the attribute value, the SAX content handler must be
+ * aware of the namespace mapping for the <tt>ns</tt> prefix, even if the serialization starts
+ * only at the child element.
*/
public class OMXMLReader implements XMLReader {
private static final String URI_LEXICAL_HANDLER = "http://xml.org/sax/properties/lexical-handler";
@@ -148,21 +163,55 @@
private void parse() throws SAXException {
contentHandler.startDocument();
+ generateParentPrefixMappingEvents(element, true);
generateEvents(element);
+ generateParentPrefixMappingEvents(element, false);
contentHandler.endDocument();
}
+ private void generatePrefixMappingEvents(OMNamespace ns, boolean start) throws SAXException {
+ String prefix = ns.getPrefix();
+ if (prefix != null) {
+ if (start) {
+ contentHandler.startPrefixMapping(prefix, ns.getNamespaceURI());
+ } else {
+ contentHandler.endPrefixMapping(prefix);
+ }
+ }
+ }
+
private void generatePrefixMappingEvents(OMElement omElement, boolean start)
throws SAXException {
for (Iterator it = omElement.getAllDeclaredNamespaces(); it.hasNext(); ) {
- OMNamespace ns = (OMNamespace)it.next();
- String prefix = ns.getPrefix();
- if (prefix != null) {
- if (start) {
- contentHandler.startPrefixMapping(prefix, ns.getNamespaceURI());
- } else {
- contentHandler.endPrefixMapping(prefix);
+ generatePrefixMappingEvents((OMNamespace)it.next(), start);
+ }
+ }
+
+ private void generateParentPrefixMappingEvents(OMElement omElement, boolean start)
+ throws SAXException {
+
+ if (!(omElement.getParent() instanceof OMElement)) {
+ return;
+ }
+ // Maintain a set of the prefixes we have already seen. This is required to take into
+ // account that a namespace mapping declared on an element can hide another one declared
+ // for the same prefix on an ancestor of the element.
+ Set/*<String>*/ seenPrefixes = new HashSet();
+ for (Iterator it = omElement.getAllDeclaredNamespaces(); it.hasNext(); ) {
+ seenPrefixes.add(((OMNamespace)it.next()).getPrefix());
+ }
+ OMElement current = omElement;
+ while (true) {
+ OMContainer parent = current.getParent();
+ if (!(parent instanceof OMElement)) {
+ return;
+ }
+ current = (OMElement)parent;
+ for (Iterator it = current.getAllDeclaredNamespaces(); it.hasNext(); ) {
+ OMNamespace ns = (OMNamespace)it.next();
+ if (seenPrefixes.add(ns.getPrefix())) {
+ generatePrefixMappingEvents(ns, start);
}
}
}
Modified: webservices/commons/trunk/modules/axiom/modules/axiom-integration/src/test/java/org/apache/axiom/om/impl/jaxp/TransformerTest.java
URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/axiom/modules/axiom-integration/src/test/java/org/apache/axiom/om/impl/jaxp/TransformerTest.java?rev=736795&r1=736794&r2=736795&view=diff
==============================================================================
--- webservices/commons/trunk/modules/axiom/modules/axiom-integration/src/test/java/org/apache/axiom/om/impl/jaxp/TransformerTest.java (original)
+++ webservices/commons/trunk/modules/axiom/modules/axiom-integration/src/test/java/org/apache/axiom/om/impl/jaxp/TransformerTest.java Thu Jan 22 13:13:02 2009
@@ -21,6 +21,8 @@
import static org.custommonkey.xmlunit.XMLAssert.assertXMLIdentical;
import static org.custommonkey.xmlunit.XMLUnit.compareXML;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
import java.io.InputStream;
import java.io.StringWriter;
@@ -32,6 +34,8 @@
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
+import org.apache.axiom.om.OMElement;
+import org.apache.axiom.om.OMNamespace;
import org.apache.axiom.om.impl.builder.StAXOMBuilder;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -59,7 +63,7 @@
}
@Test
- public void test() throws Exception {
+ public void testIdentity() throws Exception {
Transformer transformer = factory.newTransformer();
OMSource omSource = new OMSource(new StAXOMBuilder(getInput()).getDocumentElement());
@@ -73,4 +77,37 @@
assertXMLIdentical(compareXML(out.toString(), omResult.getRootElement().toString()), true);
}
+
+ /**
+ * Test that all namespace mappings in scope of the source element are available on the result.
+ * This checks for an issue that may arise under the following circumstances:
+ * <ol>
+ * <li>The source element, i.e. the element passed as argument to
+ * {@link OMSource#OMSource(OMElement)} is not the root element of the document.</li>
+ * <li>One of the ancestors declares a namespace mapping.</li>
+ * <li>The namespace mapping is not used in the name of the source element or any of its
+ * descendant elements or attributes (but may be used in the value of an attribute).</li>
+ * </ol>
+ * Example:
+ * <pre><root xmlns:ns="urn:ns"><element attr="ns:someThing"/><root></pre>
+ * In that case, when constructing an {@link OMSource} from the child element, the namespace
+ * mapping for the <tt>ns</tt> prefix should be visible to the consumer. Otherwise it would not
+ * be able to interpret the attribute value correctly. This is relevant e.g. when validating
+ * a part of a document against an XML schema (see SYNAPSE-501).
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testNamespaceMappingsOnFragment() throws Exception {
+ Transformer transformer = factory.newTransformer();
+
+ OMElement element = new StAXOMBuilder(getInput()).getDocumentElement().getFirstElement();
+ OMSource omSource = new OMSource(element);
+ OMResult omResult = new OMResult();
+ transformer.transform(omSource, omResult);
+
+ OMNamespace ns = omResult.getRootElement().findNamespaceURI("p");
+ assertNotNull(ns);
+ assertEquals("urn:some:namespace", ns.getNamespaceURI());
+ }
}
Modified: webservices/commons/trunk/modules/axiom/modules/axiom-integration/src/test/resources/org/apache/axiom/om/impl/jaxp/test.xml
URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/axiom/modules/axiom-integration/src/test/resources/org/apache/axiom/om/impl/jaxp/test.xml?rev=736795&r1=736794&r2=736795&view=diff
==============================================================================
--- webservices/commons/trunk/modules/axiom/modules/axiom-integration/src/test/resources/org/apache/axiom/om/impl/jaxp/test.xml (original)
+++ webservices/commons/trunk/modules/axiom/modules/axiom-integration/src/test/resources/org/apache/axiom/om/impl/jaxp/test.xml Thu Jan 22 13:13:02 2009
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<root>
+<root xmlns:p="urn:some:namespace">
<!-- Some comment -->
<element xmlns="urn:ns1" xmlns:ns2="urn:ns2">
<ns2:subelement attr1="test" attr2="test2">Some text</ns2:subelement>