You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@cocoon.apache.org by sy...@apache.org on 2005/08/16 11:22:51 UTC

svn commit: r232969 - in /cocoon/branches/BRANCH_2_1_X/src: java/org/apache/cocoon/xml/NamespacesTable.java test/org/apache/cocoon/xml/NamespacesTableTestCase.java

Author: sylvain
Date: Tue Aug 16 02:22:46 2005
New Revision: 232969

URL: http://svn.apache.org/viewcvs?rev=232969&view=rev
Log:
Declared prefix mappings can be known after leaveScope()

Modified:
    cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/xml/NamespacesTable.java
    cocoon/branches/BRANCH_2_1_X/src/test/org/apache/cocoon/xml/NamespacesTableTestCase.java

Modified: cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/xml/NamespacesTable.java
URL: http://svn.apache.org/viewcvs/cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/xml/NamespacesTable.java?rev=232969&r1=232968&r2=232969&view=diff
==============================================================================
--- cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/xml/NamespacesTable.java (original)
+++ cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/xml/NamespacesTable.java Tue Aug 16 02:22:46 2005
@@ -49,7 +49,7 @@
  *   }
  *
  *   public void endPrefixMapping(String prefix) throws SAXException {
- *       namespaces.removeDeclaration(prefix);
+ *       // Ignore, it is handled by leaveScope()
  *   }
  * </pre>
  *
@@ -58,6 +58,11 @@
 public class NamespacesTable {
     /** The last namespace declaration. */
     private Entry lastEntry;
+    
+    /** The entry that start the prefix mappings for the scope that's about to be entered
+     * or was just left.
+     */
+    private Entry lastDeclaredEntry;
 
     private boolean usesScopes = false;
 
@@ -74,7 +79,7 @@
      * @since 2.1.8
      */
     public void clear() {
-        this.lastEntry=Entry.create("","");
+        this.lastEntry = Entry.create("","");
         this.addDeclaration("xml", "http://www.w3.org/XML/1998/namespace");
         // Lock this scope
         this.lastEntry.closedScopes = 1;
@@ -103,16 +108,19 @@
         e.previous = this.lastEntry;
         e.overrides = dup;
         this.lastEntry = e;
+        // this always starts the declared prefix chain
+        this.lastDeclaredEntry = e;
         return e;
     }
 
     /**
-     * Undeclare a namespace prefix-uri mapping.
-     * <br>
-     * If the prefix was previously declared mapping another URI, its value
-     * is restored.
+     * Undeclare a namespace prefix-uri mapping. If the prefix was previously declared
+     * mapping another URI, its value is restored.
+     * <p>
+     * When using {@link #enterScope()}/{@link #leaveScope()}, this method does nothing and always
+     * returns <code>null</code>, as declaration removal is handled in {@link #leaveScope()}.
      *
-     * @return The removed <code>Declaration</code> or <b>null</b>.
+     * @return the removed <code>Declaration</code> or <b>null</b>.
      */
     public Declaration removeDeclaration(String prefix) {
         if (usesScopes) {
@@ -142,6 +150,14 @@
                     overrides.overriden = false;
                 }
 
+                if (this.lastDeclaredEntry == current) {
+                    if (current.previous.closedScopes == 0) {
+                        this.lastDeclaredEntry = current.previous;
+                    } else {
+                        this.lastDeclaredEntry = null;
+                    }
+                }
+
                 if (this.lastEntry == current) {
                     this.lastEntry = current.previous;
                 }
@@ -158,18 +174,23 @@
     }
 
     /**
-     * Enter a new scope, with no declared mappings.
+     * Enter a new scope. This starts a new, empty list of declarations for the new scope.
+     * <p>
+     * Typically called in a SAX handler <em>before</em> sending a <code>startElement()</code>
+     * event.
      *
-     * @see #getCurrentScopeDeclarations()
      * @since 2.1.8
      */
     public void enterScope() {
         this.usesScopes = true;
         this.lastEntry.closedScopes++;
+        this.lastDeclaredEntry = null;
     }
 
     /**
-     * Start all declared mappings of the current scope and enter a new scope.
+     * Start all declared mappings of the current scope and enter a new scope.  This starts a new,
+     * empty list of declarations for the new scope.
+     * <p>
      * Typically called in a SAX handler <em>before</em> sending a <code>startElement()</code>
      * event.
      *
@@ -185,37 +206,54 @@
             current = current.previous;
         }
         this.lastEntry.closedScopes++;
+        this.lastDeclaredEntry = null;
     }
 
     /**
-     * Leave a scope. If <code>autoRemove</code> is true, all declared mappings for the
-     * scope that is left are automatically removed, without having to explicitely call
-     * {@link #removeDeclaration(String)}.
+     * Leave a scope. The namespace declarations that occured before the corresponding
+     * <code>enterScope()</code> are no more visible using the resolution methods, but
+     * still available using {@link #getCurrentScopeDeclarations()} until the next call
+     * to {@link #addDeclaration(String, String)} or {@link #enterScope()}.
+     * <p>
+     * Typically called in a SAX handler <em>after</em> sending a <code>endElement()</code>
+     * event.
      *
-     * @param autoUndeclare if <code>true</code>, remove all mappings for the current scope.
      * @since 2.1.8
      */
     public void leaveScope() {
         Entry current = this.lastEntry;
-        if (current.closedScopes <= 0) {
-            throw new IllegalStateException("Misbalanced enter and leaving of scope.");
+
+        // Purge declarations that were added but not included in a scope
+        while (current.closedScopes == 0) {
+            current = current.previous;
         }
+
         current.closedScopes--;
-        if (usesScopes) {
-            while (current != null && current.closedScopes == 0) {
-                Entry overrides = current.overrides;
-                if (overrides != null) {
-                    // No more overriden
-                    overrides.overriden = false;
-                }
-                current = current.previous;
+
+        if (current.closedScopes == 0) {
+            this.lastDeclaredEntry = current;
+        } else {
+            // More than one scope closed here: no local declarations
+            this.lastDeclaredEntry = null;
+        }
+
+        while (current != null && current.closedScopes == 0) {
+            Entry overrides = current.overrides;
+            if (overrides != null) {
+                // No more overriden
+                overrides.overriden = false;
             }
+            current = current.previous;
         }
         this.lastEntry = current;
     }
 
     /**
-     * Leave a scope and end all declared mappings of the new scope.
+     * Leave a scope. The namespace declarations that occured before the corresponding
+     * <code>enterScope()</code> are no more visible using the resolution methods, but
+     * still available using {@link #getCurrentScopeDeclarations()} until the next call
+     * to {@link #addDeclaration(String, String)} or {@link #enterScope()}.
+     * <p>
      * Typically called in a SAX handler <em>after</em> sending a <code>endElement()</code>
      * event.
      *
@@ -225,10 +263,21 @@
      */
     public void leaveScope(ContentHandler handler) throws SAXException {
         Entry current = this.lastEntry;
-        if (current.closedScopes <= 0) {
-            throw new IllegalStateException("Misbalanced enter and leaving of scope.");
+        
+        // Purge declarations that were added but not included in a scope
+        while (current.closedScopes == 0) {
+            current = current.previous;
         }
+
         current.closedScopes--;
+
+        if (current.closedScopes == 0) {
+            this.lastDeclaredEntry = current;
+        } else {
+            // More than one scope closed here: no local declarations
+            this.lastDeclaredEntry = null;
+        }
+
         while (current != null && current.closedScopes == 0) {
             handler.endPrefixMapping(current.prefix);
             Entry overrides = current.overrides;
@@ -247,12 +296,12 @@
     /**
      * Get the declarations that were declared within the current scope.
      *
-     * @return the declarations (never null)
+     * @return the declarations (possibly empty, but never null)
      * @since 2.1.8
      */
     public Declaration[] getCurrentScopeDeclarations() {
         int count = 0;
-        Entry current = this.lastEntry;
+        Entry current = this.lastDeclaredEntry;
         while (current != null && current.closedScopes == 0) {
             count++;
             current = current.previous;
@@ -262,7 +311,7 @@
 
         Declaration[] decls = new Declaration[count];
         count = 0;
-        current = this.lastEntry;
+        current = this.lastDeclaredEntry;
         while (current != null && current.closedScopes == 0) {
             decls[count++] = current;
             current = current.previous;

Modified: cocoon/branches/BRANCH_2_1_X/src/test/org/apache/cocoon/xml/NamespacesTableTestCase.java
URL: http://svn.apache.org/viewcvs/cocoon/branches/BRANCH_2_1_X/src/test/org/apache/cocoon/xml/NamespacesTableTestCase.java?rev=232969&r1=232968&r2=232969&view=diff
==============================================================================
--- cocoon/branches/BRANCH_2_1_X/src/test/org/apache/cocoon/xml/NamespacesTableTestCase.java (original)
+++ cocoon/branches/BRANCH_2_1_X/src/test/org/apache/cocoon/xml/NamespacesTableTestCase.java Tue Aug 16 02:22:46 2005
@@ -1,3 +1,18 @@
+/*
+ * Copyright 1999-2004 The Apache Software Foundation.
+ *
+ * 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.cocoon.xml;
 
 import junit.framework.TestCase;
@@ -5,6 +20,11 @@
 import org.xml.sax.ContentHandler;
 import org.xml.sax.helpers.DefaultHandler;
 
+/**
+ * Test case for NamespacesTable
+ * 
+ * @version $Id$
+ */
 public class NamespacesTableTestCase extends TestCase {
     public NamespacesTableTestCase(String name) {
         super(name);
@@ -18,40 +38,50 @@
         
         ns.enterScope();
         
-        assertEquals("http://ns1", ns.getUri("ns1"));
-        assertEquals("ns1", ns.getPrefix("http://ns1"));
+          assertEquals("http://ns1", ns.getUri("ns1"));
+          assertEquals("ns1", ns.getPrefix("http://ns1"));
         
-        assertEquals("http://ns2", ns.getUri("ns2"));
-        assertEquals("ns2", ns.getPrefix("http://ns2"));
+          assertEquals("http://ns2", ns.getUri("ns2"));
+          assertEquals("ns2", ns.getPrefix("http://ns2"));
         
-        assertNull(ns.getPrefix(ns.getPrefix("http://ns3")));
-        assertNull(ns.getUri("ns3"));
+          ns.enterScope();
         
-        ns.leaveScope();
-        // Declarations that occured before this scope are no more visible
-        assertNull(ns.removeDeclaration("ns1"));
-        assertNull(ns.removeDeclaration("ns2"));
-        assertNull(ns.removeDeclaration("ns3"));
-    }
-    
-    public void testWrongUndeclare() {
-        NamespacesTable ns = new NamespacesTable();
+            ns.addDeclaration("ns3", "http://ns3");
+            ns.enterScope();
         
-        ns.enterScope();
-        ns.addDeclaration("ns1", "http://ns1");
-        ns.addDeclaration("ns2", "http://ns2");
+              assertEquals("ns1", ns.getPrefix("http://ns1"));
+              assertEquals("ns3", ns.getPrefix("http://ns3"));
+              assertEquals(0, ns.getCurrentScopeDeclarations().length);
+            ns.leaveScope();
+            
+            // Declarations in this scope are no more visible...
+            assertNull(ns.getUri("ns3"));
+            // ... but still listed in the declared mappings
+            assertEquals(1, ns.getCurrentScopeDeclarations().length);
+            assertEquals("ns3", ns.getCurrentScopeDeclarations()[0].getPrefix());
         
-        ns.enterScope(); // increments closedScopes on ns2
+          ns.leaveScope();
         
-        ns.addDeclaration("ns3", "http://ns3");
+          assertNull(ns.getPrefix(ns.getPrefix("http://ns3")));
+          assertNull(ns.getUri("ns3"));
         
-        try {
-            ns.leaveScope();
-        } catch(IllegalStateException e) {
-            return;
-        }
+        ns.leaveScope();
+        // Declarations that occured before this scope are no more visible...
+        assertNull(ns.getUri("ns1"));
+        assertNull(ns.getPrefix("http://ns1"));
+        
+        assertNull(ns.getUri("ns2"));
+        assertNull(ns.getPrefix("http://ns2"));
+        
+        //... but are still available in getDeclaredPrefixes
+        NamespacesTable.Declaration[] prefixes = ns.getCurrentScopeDeclarations();
+        assertEquals(2, prefixes.length);
+
+        assertEquals("ns2", prefixes[0].getPrefix());
+        assertEquals("http://ns2", prefixes[0].getUri());
+        assertEquals("ns1", prefixes[1].getPrefix());
+        assertEquals("http://ns1", prefixes[1].getUri());
         
-        fail();
     }
     
     public void testOverride() {
@@ -128,20 +158,21 @@
         ns.addDeclaration("ft", "http://apache.org/cocoon/forms/1.0#template");
         ns.addDeclaration("fi", "http://apache.org/cocoon/forms/1.0#instance");
         ns.addDeclaration("jx", "http://apache.org/cocoon/templates/jx/1.0");
-//        ns.enterScope(handler);
+        ns.enterScope(handler);
+          assertEquals("ft", ns.getPrefix("http://apache.org/cocoon/forms/1.0#template"));
+          assertEquals("fi", ns.getPrefix("http://apache.org/cocoon/forms/1.0#instance"));
+          assertEquals("jx", ns.getPrefix("http://apache.org/cocoon/templates/jx/1.0"));
+          
+          // Add declarations that won't be used
           ns.addDeclaration("jx", "http://apache.org/cocoon/templates/jx/1.0");
           ns.addDeclaration("fi", "http://apache.org/cocoon/forms/1.0#instance");
           ns.addDeclaration("bu", "http://apache.org/cocoon/browser-update/1.0");
-          ns.removeDeclaration("jx");
-          ns.removeDeclaration("fi");
-          ns.removeDeclaration("bu");
-//        ns.leaveScope(handler);
-        assertEquals("ft", ns.getPrefix("http://apache.org/cocoon/forms/1.0#template"));
-        assertEquals("fi", ns.getPrefix("http://apache.org/cocoon/forms/1.0#instance"));
-        assertEquals("jx", ns.getPrefix("http://apache.org/cocoon/templates/jx/1.0"));
-        ns.removeDeclaration("ft");
-        ns.removeDeclaration("fi");
-        ns.removeDeclaration("jx");
+
+        ns.leaveScope(handler);
+        assertNull(ns.getPrefix("http://apache.org/cocoon/forms/1.0#template"));
+        assertNull(ns.getPrefix("http://apache.org/cocoon/forms/1.0#instance"));
+        assertNull(ns.getPrefix("http://apache.org/cocoon/templates/jx/1.0"));
+        assertEquals(3, ns.getCurrentScopeDeclarations().length);
 
     }