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>&lt;root xmlns:ns="urn:ns">&lt;element attr="ns:someThing"/>&lt;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>&lt;root xmlns:ns="urn:ns">&lt;element attr="ns:someThing"/>&lt;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>