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/10 17:44:21 UTC
svn commit: r231269 - in /cocoon:
blocks/template/trunk/java/org/apache/cocoon/components/expression/
blocks/template/trunk/java/org/apache/cocoon/components/expression/jxpath/
blocks/template/trunk/java/org/apache/cocoon/template/script/event/ trunk/
...
Author: sylvain
Date: Wed Aug 10 08:43:57 2005
New Revision: 231269
URL: http://svn.apache.org/viewcvs?rev=231269&view=rev
Log:
Propagate namespace mappings in JXTemplate to JXPath expressions. Refactor and extend NamespacesTable
Added:
cocoon/trunk/src/java/org/apache/cocoon/util/jxpath/NamespacesTablePointer.java (with props)
cocoon/trunk/src/test/org/apache/cocoon/xml/NamespacesTableTestCase.java (with props)
Modified:
cocoon/blocks/template/trunk/java/org/apache/cocoon/components/expression/ExpressionContext.java
cocoon/blocks/template/trunk/java/org/apache/cocoon/components/expression/jxpath/JXPathExpression.java
cocoon/blocks/template/trunk/java/org/apache/cocoon/template/script/event/EndElement.java
cocoon/blocks/template/trunk/java/org/apache/cocoon/template/script/event/EndPrefixMapping.java
cocoon/blocks/template/trunk/java/org/apache/cocoon/template/script/event/StartElement.java
cocoon/blocks/template/trunk/java/org/apache/cocoon/template/script/event/StartPrefixMapping.java
cocoon/trunk/src/java/org/apache/cocoon/xml/NamespacesTable.java
cocoon/trunk/src/java/org/apache/cocoon/xml/RedundantNamespacesFilter.java
cocoon/trunk/status.xml
Modified: cocoon/blocks/template/trunk/java/org/apache/cocoon/components/expression/ExpressionContext.java
URL: http://svn.apache.org/viewcvs/cocoon/blocks/template/trunk/java/org/apache/cocoon/components/expression/ExpressionContext.java?rev=231269&r1=231268&r2=231269&view=diff
==============================================================================
--- cocoon/blocks/template/trunk/java/org/apache/cocoon/components/expression/ExpressionContext.java (original)
+++ cocoon/blocks/template/trunk/java/org/apache/cocoon/components/expression/ExpressionContext.java Wed Aug 10 08:43:57 2005
@@ -18,12 +18,15 @@
import java.util.HashMap;
import java.util.Map;
+import org.apache.cocoon.xml.NamespacesTable;
+
/**
* @version SVN $Id$
*/
public class ExpressionContext extends HashMap {
private ExpressionContext closure;
private Object contextBean = null;
+ private NamespacesTable namespaces;
public ExpressionContext() {
this(null);
@@ -31,6 +34,22 @@
public ExpressionContext(ExpressionContext closure) {
this.closure = closure;
+ if (closure == null) {
+ this.namespaces = new NamespacesTable();
+ } else {
+ // Reuse the parent one. Users of the context should correctly enter and leave namespace scopes.
+ this.namespaces = closure.namespaces;
+ }
+ }
+
+ /**
+ * Get the namespace table that tracks the applicable namespace prefix mappings
+ * for the expression context.
+ *
+ * @return the namespaces table
+ */
+ public NamespacesTable getNamespaces() {
+ return this.namespaces;
}
public Object getContextBean() {
Modified: cocoon/blocks/template/trunk/java/org/apache/cocoon/components/expression/jxpath/JXPathExpression.java
URL: http://svn.apache.org/viewcvs/cocoon/blocks/template/trunk/java/org/apache/cocoon/components/expression/jxpath/JXPathExpression.java?rev=231269&r1=231268&r2=231269&view=diff
==============================================================================
--- cocoon/blocks/template/trunk/java/org/apache/cocoon/components/expression/jxpath/JXPathExpression.java (original)
+++ cocoon/blocks/template/trunk/java/org/apache/cocoon/components/expression/jxpath/JXPathExpression.java Wed Aug 10 08:43:57 2005
@@ -23,6 +23,7 @@
import org.apache.cocoon.components.expression.ExpressionContext;
import org.apache.cocoon.components.expression.ExpressionException;
import org.apache.cocoon.components.expression.jexl.JSIntrospector;
+import org.apache.cocoon.util.jxpath.NamespacesTablePointer;
import org.apache.commons.jxpath.CompiledExpression;
import org.apache.commons.jxpath.JXPathContext;
import org.apache.commons.jxpath.Pointer;
@@ -134,6 +135,7 @@
JXPathContext jxcontext = JXPathContext.newContext(context.getContextBean());
jxcontext.setVariables(new VariableAdapter(context));
jxcontext.setLenient(this.lenient);
+ jxcontext.setNamespaceContextPointer(new NamespacesTablePointer(context.getNamespaces()));
return jxcontext;
}
Modified: cocoon/blocks/template/trunk/java/org/apache/cocoon/template/script/event/EndElement.java
URL: http://svn.apache.org/viewcvs/cocoon/blocks/template/trunk/java/org/apache/cocoon/template/script/event/EndElement.java?rev=231269&r1=231268&r2=231269&view=diff
==============================================================================
--- cocoon/blocks/template/trunk/java/org/apache/cocoon/template/script/event/EndElement.java (original)
+++ cocoon/blocks/template/trunk/java/org/apache/cocoon/template/script/event/EndElement.java Wed Aug 10 08:43:57 2005
@@ -43,6 +43,9 @@
Event startEvent, Event endEvent) throws SAXException {
consumer.endElement(startElement.getNamespaceURI(), startElement
.getLocalName(), startElement.getRaw());
+
+ // Send any pending endPrefixMapping events
+ expressionContext.getNamespaces().leaveScope(consumer);
return getNext();
}
}
Modified: cocoon/blocks/template/trunk/java/org/apache/cocoon/template/script/event/EndPrefixMapping.java
URL: http://svn.apache.org/viewcvs/cocoon/blocks/template/trunk/java/org/apache/cocoon/template/script/event/EndPrefixMapping.java?rev=231269&r1=231268&r2=231269&view=diff
==============================================================================
--- cocoon/blocks/template/trunk/java/org/apache/cocoon/template/script/event/EndPrefixMapping.java (original)
+++ cocoon/blocks/template/trunk/java/org/apache/cocoon/template/script/event/EndPrefixMapping.java Wed Aug 10 08:43:57 2005
@@ -41,7 +41,8 @@
ExpressionContext expressionContext,
ExecutionContext executionContext, MacroContext macroContext,
Event startEvent, Event endEvent) throws SAXException {
- consumer.endPrefixMapping(getPrefix());
+
+ // nothing (endPrefixMapping is sent in EndElement)
return getNext();
}
}
Modified: cocoon/blocks/template/trunk/java/org/apache/cocoon/template/script/event/StartElement.java
URL: http://svn.apache.org/viewcvs/cocoon/blocks/template/trunk/java/org/apache/cocoon/template/script/event/StartElement.java?rev=231269&r1=231268&r2=231269&view=diff
==============================================================================
--- cocoon/blocks/template/trunk/java/org/apache/cocoon/template/script/event/StartElement.java (original)
+++ cocoon/blocks/template/trunk/java/org/apache/cocoon/template/script/event/StartElement.java Wed Aug 10 08:43:57 2005
@@ -119,6 +119,9 @@
.getType(), attributeValue);
}
}
+
+ // Send any pending startPrefixMapping events
+ expressionContext.getNamespaces().enterScope(consumer);
consumer.startElement(getNamespaceURI(), getLocalName(), getRaw(),
attrs);
return getNext();
Modified: cocoon/blocks/template/trunk/java/org/apache/cocoon/template/script/event/StartPrefixMapping.java
URL: http://svn.apache.org/viewcvs/cocoon/blocks/template/trunk/java/org/apache/cocoon/template/script/event/StartPrefixMapping.java?rev=231269&r1=231268&r2=231269&view=diff
==============================================================================
--- cocoon/blocks/template/trunk/java/org/apache/cocoon/template/script/event/StartPrefixMapping.java (original)
+++ cocoon/blocks/template/trunk/java/org/apache/cocoon/template/script/event/StartPrefixMapping.java Wed Aug 10 08:43:57 2005
@@ -47,7 +47,9 @@
ExpressionContext expressionContext,
ExecutionContext executionContext, MacroContext macroContext,
Event startEvent, Event endEvent) throws SAXException {
- consumer.startPrefixMapping(getPrefix(), getUri());
+
+ expressionContext.getNamespaces().addDeclaration(getPrefix(), getUri());
+ // the startPrefixMapping event will be sent in StartElement
return getNext();
}
}
Added: cocoon/trunk/src/java/org/apache/cocoon/util/jxpath/NamespacesTablePointer.java
URL: http://svn.apache.org/viewcvs/cocoon/trunk/src/java/org/apache/cocoon/util/jxpath/NamespacesTablePointer.java?rev=231269&view=auto
==============================================================================
--- cocoon/trunk/src/java/org/apache/cocoon/util/jxpath/NamespacesTablePointer.java (added)
+++ cocoon/trunk/src/java/org/apache/cocoon/util/jxpath/NamespacesTablePointer.java Wed Aug 10 08:43:57 2005
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2005 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.util.jxpath;
+
+import org.apache.cocoon.xml.NamespacesTable;
+import org.apache.commons.jxpath.ri.QName;
+import org.apache.commons.jxpath.ri.model.NodeIterator;
+import org.apache.commons.jxpath.ri.model.NodePointer;
+
+/**
+ * A JXPath <code>Pointer</code> that tracks namespaces defined by a {@link NamespacesTable}.
+ * This class is to be used to inform JXPath of the namespaces declared in a host environment
+ * (e.g. JXTemplateGenerator) using
+ * <a href="http://jakarta.apache.org/commons/jxpath/apidocs/org/apache/commons/jxpath/JXPathContext.html#setNamespaceContextPointer(org.apache.commons.jxpath.Pointer)">JXPathContext.setNamespaceContextPointer()</a>.
+ *
+ * @since 2.1.8
+ * @version $Id$
+ */
+public class NamespacesTablePointer extends NodePointer {
+
+ private NamespacesTable namespaces;
+
+ public NamespacesTablePointer(NamespacesTable namespaces) {
+ super(null);
+ this.namespaces = namespaces;
+ }
+
+ public String getNamespaceURI(String prefix) {
+ return namespaces.getUri(prefix);
+ }
+
+ protected String getDefaultNamespaceURI() {
+ return namespaces.getUri("");
+ }
+
+ public NodeIterator namespaceIterator() {
+ return null;
+ }
+
+ //-------------------------------------------------------------------------
+ // Dummy implementation of abstract methods
+ //-------------------------------------------------------------------------
+
+ public boolean isLeaf() {
+ return true;
+ }
+
+ public boolean isCollection() {
+ return false;
+ }
+
+ public int getLength() {
+ return 0;
+ }
+
+ public QName getName() {
+ return null;
+ }
+
+ public Object getBaseValue() {
+ return null;
+ }
+
+ public Object getImmediateNode() {
+ return null;
+ }
+
+ public void setValue(Object value) {
+ // ignore
+ }
+
+ public int compareChildNodePointers(NodePointer arg0, NodePointer arg1) {
+ return -1;
+ }
+}
Propchange: cocoon/trunk/src/java/org/apache/cocoon/util/jxpath/NamespacesTablePointer.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cocoon/trunk/src/java/org/apache/cocoon/util/jxpath/NamespacesTablePointer.java
------------------------------------------------------------------------------
svn:keywords = Id
Modified: cocoon/trunk/src/java/org/apache/cocoon/xml/NamespacesTable.java
URL: http://svn.apache.org/viewcvs/cocoon/trunk/src/java/org/apache/cocoon/xml/NamespacesTable.java?rev=231269&r1=231268&r2=231269&view=diff
==============================================================================
--- cocoon/trunk/src/java/org/apache/cocoon/xml/NamespacesTable.java (original)
+++ cocoon/trunk/src/java/org/apache/cocoon/xml/NamespacesTable.java Wed Aug 10 08:43:57 2005
@@ -15,30 +15,69 @@
*/
package org.apache.cocoon.xml;
+import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
/**
- * This utility class is used to keep track namespaces declarations and resolve
- * namespaces names.
+ * Keeps track of namespaces declarations and resolve namespaces names.
+ * <p>
+ * This class also provides a very convenient and safe way of handling
+ * namespace declarations in SAX pipes. It also allows to filter duplicate namespace
+ * declarations that too often clutter up XML documents that went through
+ * several transformations, and avoid useless namespace declarations that aren't followed
+ * by element events.
+ * <p>
+ * Usage example in a SAX pipe:
+ * <pre>
+ * NamespacesTable namespaces = new NamespacesTable();
+ * ContentHandler nextHandler;
*
- * @author <a href="mailto:pier@apache.org">Pierpaolo Fumagalli</a>
- * (Apache Software Foundation)
- * @version CVS $Id: NamespacesTable.java,v 1.3 2004/03/05 13:03:01 bdelacretaz Exp $
+ * public void startPrefixMapping(String prefix, String uri) throws SAXException {
+ * namespaces.addDeclaration(prefix, uri);
+ * }
+ *
+ * public void startElement(...) throws SAXException {
+ * // automatically start mappings for this scope
+ * namespaces.enterScope(nextHandler);
+ * nextHandler.startElement(...);
+ * }
+ *
+ * public void endElement(...) throws SAXException {
+ * nextHandler.endElement(...);
+ * // automatically end mappings for this scope
+ * namespaces.leaveScope(nextHandler);
+ * }
+ *
+ * public void endPrefixMapping(String prefix) throws SAXException {
+ * // Ignore, it is handled by the call to leaveScope above.
+ * }
+ * </pre>
+ *
+ * @version $Id$
*/
public class NamespacesTable {
- /** The initial namespace declaration. */
- private Entry entry=null;
+ /** The last namespace declaration. */
+ private Entry lastEntry = null;
+
+ private boolean filterDuplicate = true;
/**
* Construct a new <code>NamespacesTable</code> instance.
*/
public NamespacesTable() {
- super();
- this.entry=Entry.create("","");
- // Set the previous declaration of this namespace as self, so it will
- // not be possible to remove it :)
- this.entry.previousDeclaration=this.entry;
+ clear();
+ }
+
+ /**
+ * Clear and reinitialize this namespace table before reuse.
+ *
+ * @since 2.1.8
+ */
+ public void clear() {
+ this.lastEntry=Entry.create("","");
this.addDeclaration("xml", "http://www.w3.org/XML/1998/namespace");
+ // Lock this scope
+ this.lastEntry.closedScopes = 1;
}
/**
@@ -47,28 +86,24 @@
* @return The newly added <code>Declaration</code>.
*/
public Declaration addDeclaration(String prefix, String uri) {
- Entry e=Entry.create(prefix,uri);
- Entry previous=null;
- Entry current=this.entry;
- while (current!=null) {
- if (current.prefixHash==e.prefixHash) {
- // Set the current entry to be the previous declaration for the
- // specified prefix and remove it from the chain.
- e.previousDeclaration=current;
- e.nextEntry=current.nextEntry;
- current.nextEntry=null;
- // Set the new entry in the chain
- if (previous==null) this.entry=e;
- else previous.nextEntry=e;
- return(e);
- } else {
- previous=current;
- current=current.nextEntry;
+ // Find a previous declaration of the same prefix
+ Entry dup = this.lastEntry;
+ while (dup != null && !dup.prefix.equals(prefix)) {
+ dup = dup.previous;
+ }
+
+ if (dup != null) {
+ if (filterDuplicate && dup.uri.equals(uri)) {
+ return dup;
}
+ dup.overriden = true;
}
- if (previous==null) this.entry=e;
- else previous.nextEntry=e;
- return(e);
+
+ Entry e = Entry.create(prefix, uri);
+ e.previous = this.lastEntry;
+ e.overrides = dup;
+ this.lastEntry = e;
+ return e;
}
/**
@@ -80,26 +115,149 @@
* @return The removed <code>Declaration</code> or <b>null</b>.
*/
public Declaration removeDeclaration(String prefix) {
- int hash=prefix.hashCode();
- Entry previous=null;
- Entry current=this.entry;
- while (current!=null) {
- if (current.prefixHash==hash) {
- if (current.previousDeclaration==null) {
- if (previous==null) this.entry=current.nextEntry;
- else previous.nextEntry=current.nextEntry;
- } else {
- current.previousDeclaration.nextEntry=current.nextEntry;
- if (previous==null) this.entry=current.previousDeclaration;
- else previous.nextEntry=current.previousDeclaration;
+
+ Entry current = this.lastEntry;
+ Entry afterCurrent = null;
+ while(current != null) {
+ if (current.closedScopes > 0) {
+ // Don't undeclare mappings not declared in this scope
+ return null;
+ }
+
+ if (current.prefix.equals(prefix)) {
+ // Got it
+ // Remove it from the chain
+ if (afterCurrent != null) {
+ afterCurrent.previous = current.previous;
}
- return(current);
- } else {
- previous=current;
- current=current.nextEntry;
+ // And report closed scopes on the previous entry
+ current.previous.closedScopes += current.closedScopes;
+ Entry overrides = current.overrides;
+ if (overrides != null) {
+ // No more overriden
+ overrides.overriden = false;
+ }
+
+ return current;
}
+
+ afterCurrent = current;
+ current = current.previous;
}
- return(null);
+
+ // Not found
+ return null;
+ }
+
+ /**
+ * Enter a new scope, with no declared mappings.
+ *
+ * @see #getCurrentScopeDeclarations()
+ * @since 2.1.8
+ */
+ public void enterScope() {
+ this.lastEntry.closedScopes++;
+ }
+
+ /**
+ * Start all declared mappings of the current scope and enter a new scope.
+ * Typically called in a SAX handler <em>before</em> sending a <code>startElement()</code>
+ * event.
+ *
+ * @param handler the handler that will receive startPrefixMapping events.
+ * @throws SAXException
+ * @since 2.1.8
+ */
+ public void enterScope(ContentHandler handler) throws SAXException {
+ Entry current = this.lastEntry;
+ while (current != null && current.closedScopes == 0) {
+ handler.startPrefixMapping(current.prefix, current.uri);
+ current = current.previous;
+ }
+ enterScope();
+ }
+
+ /**
+ * 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)}.
+ *
+ * @param autoRemove if <code>true</code>, remove all mappings for the current scope.
+ * @since 2.1.8
+ */
+ public void leaveScope(boolean autoUndeclare) {
+ Entry current = this.lastEntry;
+ if (current.closedScopes <= 0) {
+ throw new IllegalStateException("Misbalanced enter and leaving of scope.");
+ }
+ current.closedScopes--;
+ if (autoUndeclare) {
+ 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.
+ * Typically called in a SAX handler <em>after</em> sending a <code>endElement()</code>
+ * event.
+ *
+ * @param handler the handler that will receive endPrefixMapping events.
+ * @throws SAXException
+ * @since 2.1.8
+ */
+ public void leaveScope(ContentHandler handler) throws SAXException {
+ Entry current = this.lastEntry;
+ if (current.closedScopes <= 0) {
+ throw new IllegalStateException("Misbalanced enter and leaving of scope.");
+ }
+ while (current != null && current.closedScopes == 0) {
+ handler.endPrefixMapping(current.prefix);
+ Entry overrides = current.overrides;
+ if (overrides != null) {
+ // No more overriden
+ overrides.overriden = false;
+ }
+ current = current.previous;
+ }
+
+ current.closedScopes--;
+ this.lastEntry = current;
+ }
+
+ private static final Declaration[] NO_DECLS = new Declaration[0];
+
+ /**
+ * Get the declarations that were declared within the current scope.
+ *
+ * @return the declarations (never null)
+ * @since 2.1.8
+ */
+ public Declaration[] getCurrentScopeDeclarations() {
+ int count = 0;
+ Entry current = this.lastEntry;
+ while (current != null && current.closedScopes == 0) {
+ count++;
+ current = current.previous;
+ }
+
+ if (count == 0) return NO_DECLS;
+
+ Declaration[] decls = new Declaration[count];
+ count = 0;
+ current = this.lastEntry;
+ while (current != null && current.closedScopes == 0) {
+ decls[count++] = current;
+ current = current.previous;
+ }
+ return decls;
}
/**
@@ -107,13 +265,16 @@
* prefix was not mapped.
*/
public String getUri(String prefix) {
- int hash=prefix.hashCode();
- Entry current=this.entry;
- while (current!=null) {
- if(current.prefixHash==hash) return(current.uri);
- else current=current.nextEntry;
+ Entry current = this.lastEntry;
+ while (current != null) {
+ if (current.prefix.equals(prefix)) {
+ return current.uri;
+ }
+ current = current.previous;
}
- return(null);
+
+ // Not found
+ return null;
}
/**
@@ -125,21 +286,25 @@
* @return A <b>non-null</b> <code>String</code> array.
*/
public String[] getPrefixes(String uri) {
- int hash=uri.hashCode();
- Entry current=this.entry;
+
+ Entry current=this.lastEntry;
int count=0;
while (current!=null) {
- if(current.uriHash==hash) count++;
- current=current.nextEntry;
+ if(!current.overriden && current.uri.equals(uri))
+ count++;
+ current=current.previous;
}
if (count==0) return(new String[0]);
+
String prefixes[]=new String[count];
count=0;
+ current = this.lastEntry;
while (current!=null) {
- if(current.uriHash==hash) prefixes[count++]=current.prefix;
- current=current.nextEntry;
+ if(!current.overriden && current.uri.equals(uri))
+ prefixes[count++] = current.prefix;
+ current = current.previous;
}
- return(prefixes);
+ return prefixes;
}
@@ -148,13 +313,13 @@
* <b>null</b>.
*/
public String getPrefix(String uri) {
- int hash=uri.hashCode();
- Entry current=this.entry;
- while (current!=null) {
- if(current.uriHash==hash) return(current.prefix);
- current=current.nextEntry;
+ Entry current = this.lastEntry;
+ while (current != null) {
+ if(!current.overriden && current.uri.equals(uri))
+ return current.prefix;
+ current = current.previous;
}
- return(null);
+ return null;
}
/**
@@ -233,37 +398,32 @@
/** The internal entry structure for this table. */
private static class Entry implements Declaration {
- /** The URI hashcode. */
- protected int uriHash=0;
- /** The prefix hashcode. */
- protected int prefixHash=0;
/** The URI string. */
protected String uri="";
/** The prefix string. */
protected String prefix="";
- /** The previous declaration for the same prefix. */
- protected Entry previousDeclaration;
- /** The declaration following this one in the table. */
- protected Entry nextEntry;
+ /** The previous declaration. */
+ protected Entry previous;
+ protected Entry overrides;
+ protected int closedScopes = 0;
+ protected boolean overriden = false;
/** Create a new namespace declaration. */
protected static Entry create(String prefix, String uri) {
// Create a new entry
- Entry e=new Entry();
- // Set the prefix string and hash code.
- if (prefix!=null) e.prefix=prefix;
- e.prefixHash=e.prefix.hashCode();
- // Set the uri string and hash code.
- if (uri!=null) e.uri=uri;
- e.uriHash=e.uri.hashCode();
+ Entry e = new Entry();
+ // Set the prefix string.
+ if (prefix != null) e.prefix=prefix;
+ // Set the uri string.
+ if (uri != null) e.uri=uri;
// Return the entry
- return(e);
+ return e;
}
/** Return the namespace URI. */
- public String getUri() { return(this.uri); }
+ public String getUri() { return this.uri; }
/** Return the namespace prefix. */
- public String getPrefix() { return(this.prefix); }
+ public String getPrefix() { return this.prefix; }
}
/** The default namespace-aware name declaration implementation */
@@ -278,13 +438,13 @@
protected String raw;
/** Return the namespace URI. */
- public String getUri() { return(this.uri); }
+ public String getUri() { return this.uri; }
/** Return the namespace prefix. */
- public String getPrefix() { return(this.prefix); }
+ public String getPrefix() { return this.prefix; }
/** Return the namespace local name. */
- public String getLocalName() { return(this.local); }
+ public String getLocalName() { return this.local; }
/** Return the namespace raw name. */
- public String getQName() { return(this.raw); }
+ public String getQName() { return this.raw; }
}
/**
Modified: cocoon/trunk/src/java/org/apache/cocoon/xml/RedundantNamespacesFilter.java
URL: http://svn.apache.org/viewcvs/cocoon/trunk/src/java/org/apache/cocoon/xml/RedundantNamespacesFilter.java?rev=231269&r1=231268&r2=231269&view=diff
==============================================================================
--- cocoon/trunk/src/java/org/apache/cocoon/xml/RedundantNamespacesFilter.java (original)
+++ cocoon/trunk/src/java/org/apache/cocoon/xml/RedundantNamespacesFilter.java Wed Aug 10 08:43:57 2005
@@ -15,8 +15,6 @@
*/
package org.apache.cocoon.xml;
-import java.util.Enumeration;
-
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
@@ -28,13 +26,15 @@
* no element inbetween) that can be produced by some components (e.g. JXTG or
* BrowserUpdateTransformer). Such empty scopes confuse the Xalan serializer which
* then produces weird namespace declarations (<code>xmlns:%@$#^@#="%@$#^@#"</code>).
+ * <p>
+ * This is a the most simple use of {@link NamespaceHelper}.
*
* @version CVS $Id$
*/
public class RedundantNamespacesFilter extends AbstractXMLPipe {
/** Layered storage for all namespace declarations */
- private NamespaceSupport ns = new NamespaceSupport();
+ private NamespacesTable ns = new NamespacesTable();
/**
* No-arg constructor. Requires an explicit call to
@@ -55,31 +55,19 @@
}
public void startPrefixMapping(String prefix, String uri) throws SAXException {
- if (!uri.equals(ns.getURI(prefix))) {
- // New declaration: store it
- ns.declarePrefix(prefix, uri);
- }
+ // Just declare it: duplicate declarations are ignorede by NamespacesTable
+ ns.addDeclaration(prefix, uri);
}
public void startElement(String uri, String loc, String raw, Attributes a) throws SAXException {
// Declare namespaces for this scope, if any
- Enumeration prefixes = ns.getDeclaredPrefixes();
- while (prefixes.hasMoreElements()) {
- String prefix = (String) prefixes.nextElement();
- super.startPrefixMapping(prefix, ns.getURI(prefix));
- }
- ns.pushContext();
+ ns.enterScope(this.contentHandler);
super.startElement(uri, loc, raw, a);
}
public void endElement(String uri, String loc, String raw) throws SAXException {
super.endElement(uri, loc, raw);
- ns.popContext();
- // Undeclare namespaces for this scope, if any
- Enumeration prefixes = ns.getDeclaredPrefixes();
- while (prefixes.hasMoreElements()) {
- super.endPrefixMapping((String) prefixes.nextElement());
- }
+ ns.leaveScope(this.contentHandler);
}
public void endPrefixMapping(String prefix) throws SAXException {
Added: cocoon/trunk/src/test/org/apache/cocoon/xml/NamespacesTableTestCase.java
URL: http://svn.apache.org/viewcvs/cocoon/trunk/src/test/org/apache/cocoon/xml/NamespacesTableTestCase.java?rev=231269&view=auto
==============================================================================
--- cocoon/trunk/src/test/org/apache/cocoon/xml/NamespacesTableTestCase.java (added)
+++ cocoon/trunk/src/test/org/apache/cocoon/xml/NamespacesTableTestCase.java Wed Aug 10 08:43:57 2005
@@ -0,0 +1,117 @@
+package org.apache.cocoon.xml;
+
+import org.xml.sax.helpers.DefaultHandler;
+
+import junit.framework.TestCase;
+
+public class NamespacesTableTestCase extends TestCase {
+ public NamespacesTableTestCase(String name) {
+ super(name);
+ }
+
+ public void testSimple() {
+ NamespacesTable ns = new NamespacesTable();
+
+ ns.addDeclaration("ns1", "http://ns1");
+ ns.addDeclaration("ns2", "http://ns2");
+
+ ns.enterScope();
+
+ assertEquals("http://ns1", ns.getUri("ns1"));
+ assertEquals("ns1", ns.getPrefix("http://ns1"));
+
+ assertEquals("http://ns2", ns.getUri("ns2"));
+ assertEquals("ns2", ns.getPrefix("http://ns2"));
+
+ assertNull(ns.getPrefix(ns.getPrefix("http://ns3")));
+ assertNull(ns.getUri("ns3"));
+
+ ns.leaveScope(false);
+ assertNotNull(ns.removeDeclaration("ns1"));
+ assertNotNull(ns.removeDeclaration("ns2"));
+ assertNull(ns.removeDeclaration("ns3"));
+ }
+
+ public void testWrongUndeclare() {
+ NamespacesTable ns = new NamespacesTable();
+
+ ns.enterScope();
+ ns.addDeclaration("ns1", "http://ns1");
+ ns.addDeclaration("ns2", "http://ns2");
+
+ ns.enterScope(); // increments closedScopes on ns2
+
+ ns.addDeclaration("ns3", "http://ns3");
+
+ try {
+ ns.leaveScope(false);
+ } catch(IllegalStateException e) {
+ return;
+ }
+
+ fail();
+ }
+
+ public void testOverride() {
+ NamespacesTable ns = new NamespacesTable();
+
+ ns.addDeclaration("ns1", "http://ns1");
+ ns.enterScope();
+ ns.addDeclaration("ns1", "http://otherns1");
+ ns.enterScope();
+ ns.addDeclaration("ns1", "http://yetanotherns1");
+ ns.enterScope();
+
+ assertEquals("http://yetanotherns1", ns.getUri("ns1"));
+ assertEquals(0, ns.getPrefixes("http://ns1").length);
+
+ ns.leaveScope(true);
+ ns.leaveScope(true);
+
+ assertEquals("http://ns1", ns.getUri("ns1"));
+ assertEquals(1, ns.getPrefixes("http://ns1").length);
+
+ ns.leaveScope(true);
+ assertNull(ns.getUri("ns1"));
+ }
+
+ public void testMultiDeclaration() {
+ NamespacesTable ns = new NamespacesTable();
+ ns.addDeclaration("ns1", "http://ns1");
+ ns.enterScope();
+ // two in the same scope
+ ns.addDeclaration("ns2", "http://ns1");
+ ns.addDeclaration("ns3", "http://ns1");
+ ns.enterScope();
+
+ String[] prefixes = ns.getPrefixes("http://ns1");
+ assertEquals(3, prefixes.length);
+ assertEquals("ns3", prefixes[0]);
+ assertEquals("ns2", prefixes[1]);
+ assertEquals("ns1", prefixes[2]);
+ }
+
+ public void testStreamDeclarations() throws Exception {
+ NamespacesTable ns = new NamespacesTable();
+ ns.addDeclaration("ns1", "http://ns1");
+ ns.enterScope();
+ ns.addDeclaration("ns2", "http://ns2");
+ ns.enterScope(new DefaultHandler() {
+ public void startPrefixMapping(String prefix, String uri) throws org.xml.sax.SAXException {
+ assertEquals("ns2", prefix);
+ assertEquals("http://ns2", uri);
+ };
+ });
+
+ // Enter and leave a nested scope
+ ns.addDeclaration("ns3", "http://ns3");
+ ns.enterScope();
+ ns.leaveScope(true);
+
+ ns.leaveScope(new DefaultHandler() {
+ public void endPrefixMapping(String prefix) throws org.xml.sax.SAXException {
+ assertEquals("ns2", prefix);
+ };
+ });
+ }
+}
Propchange: cocoon/trunk/src/test/org/apache/cocoon/xml/NamespacesTableTestCase.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cocoon/trunk/src/test/org/apache/cocoon/xml/NamespacesTableTestCase.java
------------------------------------------------------------------------------
svn:keywords = Id
Modified: cocoon/trunk/status.xml
URL: http://svn.apache.org/viewcvs/cocoon/trunk/status.xml?rev=231269&r1=231268&r2=231269&view=diff
==============================================================================
--- cocoon/trunk/status.xml (original)
+++ cocoon/trunk/status.xml Wed Aug 10 08:43:57 2005
@@ -518,6 +518,9 @@
</action>
</release>
<release version="2.1.8" date="TBD">
+ <action dev="SW" type="fix">
+ JXTemplate: ensure JXPath expressions can use namespace prefix mappings declared in the template document.
+ </action>
<action dev="CZ" type="update">
Updated Axis to 1.2 and wsdl4j to 1.5.1.
</action>