You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by po...@apache.org on 2005/07/19 19:34:02 UTC

svn commit: r219726 - in /jakarta/commons/proper/jelly/trunk: jelly-tags/xml/ jelly-tags/xml/src/java/org/apache/commons/jelly/tags/xml/ jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/ src/java/org/apache/commons/jelly/ src/java/org/apache/c...

Author: polx
Date: Tue Jul 19 10:34:00 2005
New Revision: 219726

URL: http://svn.apache.org/viewcvs?rev=219726&view=rev
Log:
Fixing treatment of namespaced-qualified attributes in XML taglib and
in the xml-output.
This fixes JELLY-213 and JELLY-214.
paul

Added:
    jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/java/org/apache/commons/jelly/tags/xml/ReplaceNamespaceTag.java
    jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/attributeNameSpace.jelly
    jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/attributeNameSpaceDefaultNS.jelly
    jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/attributeNameSpaceDuplicatedNS.jelly
    jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/attributeNameSpaceWithInnerElements.jelly
    jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/elementWithNameSpace.jelly
    jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/elementWithNameSpaceError.jelly
    jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/namespaceReplace.jelly
    jakarta/commons/proper/jelly/trunk/src/test/org/apache/commons/jelly/testStaticNamespacedAttributes.jelly
Modified:
    jakarta/commons/proper/jelly/trunk/jelly-tags/xml/project.xml
    jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/java/org/apache/commons/jelly/tags/xml/AttributeTag.java
    jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/java/org/apache/commons/jelly/tags/xml/ElementTag.java
    jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/java/org/apache/commons/jelly/tags/xml/XMLTagLibrary.java
    jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/TestXMLTags.java
    jakarta/commons/proper/jelly/trunk/src/java/org/apache/commons/jelly/XMLOutput.java
    jakarta/commons/proper/jelly/trunk/src/java/org/apache/commons/jelly/impl/StaticTag.java
    jakarta/commons/proper/jelly/trunk/src/java/org/apache/commons/jelly/impl/StaticTagScript.java
    jakarta/commons/proper/jelly/trunk/src/java/org/apache/commons/jelly/impl/TagScript.java
    jakarta/commons/proper/jelly/trunk/src/java/org/apache/commons/jelly/parser/XMLParser.java
    jakarta/commons/proper/jelly/trunk/src/test/org/apache/commons/jelly/TestCoreTags.java
    jakarta/commons/proper/jelly/trunk/src/test/org/apache/commons/jelly/core/TestFileTag.java

Modified: jakarta/commons/proper/jelly/trunk/jelly-tags/xml/project.xml
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/jelly/trunk/jelly-tags/xml/project.xml?rev=219726&r1=219725&r2=219726&view=diff
==============================================================================
--- jakarta/commons/proper/jelly/trunk/jelly-tags/xml/project.xml (original)
+++ jakarta/commons/proper/jelly/trunk/jelly-tags/xml/project.xml Tue Jul 19 10:34:00 2005
@@ -20,7 +20,7 @@
   <extend>${basedir}/../tag-project.xml</extend>
   <id>commons-jelly-tags-xml</id>
   <name>commons-jelly-tags-xml</name>
-  <currentVersion>1.1</currentVersion>
+  <currentVersion>1.2-dev</currentVersion>
   <package>org.apache.commons.jelly.tags.xml</package>
   <description>The Jelly XML Tag Library</description>
   <shortDescription>Commons Jelly XML Tag Library</shortDescription>
@@ -37,6 +37,11 @@
     </version>
   </versions>
   <dependencies>
+    <dependency>
+      <id>commons-jelly</id>
+      <version>SNAPSHOT</version>
+    </dependency>
+    
     <!-- run time / in testing-->
 
     <dependency>

Modified: jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/java/org/apache/commons/jelly/tags/xml/AttributeTag.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/java/org/apache/commons/jelly/tags/xml/AttributeTag.java?rev=219726&r1=219725&r2=219726&view=diff
==============================================================================
--- jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/java/org/apache/commons/jelly/tags/xml/AttributeTag.java (original)
+++ jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/java/org/apache/commons/jelly/tags/xml/AttributeTag.java Tue Jul 19 10:34:00 2005
@@ -26,6 +26,8 @@
   * @version $Revision$
   */
 public class AttributeTag extends TagSupport {
+     /** The namespace URI. */
+    private String namespace;
 
     /** the name of the attribute. */
     private String name;
@@ -38,10 +40,11 @@
     //-------------------------------------------------------------------------
     public void doTag(XMLOutput output) throws JellyTagException {
         ElementTag tag = (ElementTag) findAncestorWithClass( ElementTag.class );
-        if ( tag == null ) {
-            throw new JellyTagException( "<attribute> tag must be enclosed inside an <element> tag" );
+        if (tag == null) {
+            throw new JellyTagException(
+                    "<attribute> tag must be enclosed inside an <element> tag" );
         }
-        tag.setAttributeValue( getName(), getBodyText( false ) );
+        tag.setAttributeValue(getName(), getBodyText(false), getURI());
     }
 
     // Properties
@@ -53,10 +56,25 @@
     public String getName() {
         return name;
     }
+
     /**
-     * Sets the name of the attribute
+     * Sets the name of the attribute.
      */
     public void setName(String name) {
         this.name = name;
+    }
+
+    /**
+     * @return the namespace URI of the element
+     */
+    public String getURI() {
+        return namespace;
+    }
+
+    /**
+     * Sets the namespace URI of the element
+     */
+    public void setURI(String namespace) {
+        this.namespace = namespace;
     }
 }

Modified: jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/java/org/apache/commons/jelly/tags/xml/ElementTag.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/java/org/apache/commons/jelly/tags/xml/ElementTag.java?rev=219726&r1=219725&r2=219726&view=diff
==============================================================================
--- jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/java/org/apache/commons/jelly/tags/xml/ElementTag.java (original)
+++ jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/java/org/apache/commons/jelly/tags/xml/ElementTag.java Tue Jul 19 10:34:00 2005
@@ -15,6 +15,7 @@
  */
 package org.apache.commons.jelly.tags.xml;
 
+import org.apache.commons.jelly.JellyException;
 import org.apache.commons.jelly.JellyTagException;
 import org.apache.commons.jelly.TagSupport;
 import org.apache.commons.jelly.XMLOutput;
@@ -22,8 +23,6 @@
 import org.xml.sax.SAXException;
 import org.xml.sax.helpers.AttributesImpl;
 
-import java.io.IOException;
-
 /** A tag to produce an XML element which can contain other attributes
   * or elements like the <code>&lt;xsl:element&gt;</code> tag.
   *
@@ -32,16 +31,16 @@
   */
 public class ElementTag extends TagSupport {
 
-    /** The namespace URI */
+    /** The namespace URI. */
     private String namespace;
 
-    /** The qualified name */
+    /** The qualified name. */
     private String name;
 
-    /** The XML Attributes */
+    /** The XML Attributes. */
     private AttributesImpl attributes = new AttributesImpl();
 
-    /** flag set if attributes are output */
+    /** flag set if attributes are output. */
     private boolean outputAttributes;
 
     public ElementTag() {
@@ -52,11 +51,12 @@
      *
      * @param name of the attribute
      * @param value of the attribute
-     * @throws JellyException if the start element has already been output.
+     * @param uri namespace of the attribute
+     * @throws JellyTagException if the start element has already been output.
      *   Attributes must be set on the outer element before any content
      *   (child elements or text) is output
      */
-    public void setAttributeValue( String name, String value ) throws JellyTagException {
+    public void setAttributeValue(String name, String value, String uri) throws JellyTagException {
         if (outputAttributes) {
             throw new JellyTagException(
                 "Cannot set the value of attribute: "
@@ -67,13 +67,22 @@
         // ### we'll assume that all attributes are in no namespace!
         // ### this is severely limiting!
         // ### we should be namespace aware
-        int index = attributes.getIndex("", name);
+        // NAMESPACE FIXED:
+        int idx = name.indexOf(':');
+        final String localName = (idx >= 0)
+            ? name.substring(idx + 1)
+            : name;
+        final String nsUri = (uri != null)
+            ? uri
+            : "";
+
+        int index = attributes.getIndex(nsUri, localName);
         if (index >= 0) {
             attributes.removeAttribute(index);
         }
         // treat null values as no attribute
         if (value != null) {
-            attributes.addAttribute("", name, name, "CDATA", value);
+            attributes.addAttribute(nsUri, localName, name, "CDATA", value);
         }
     }
 
@@ -107,22 +116,21 @@
                 super.endElement(uri, localName, qName);
             }
 
-            public void characters(char ch[], int start, int length) throws SAXException {
+            public void characters(char[] ch, int start, int length) throws SAXException {
                 initialize();
                 super.characters(ch, start, length);
             }
 
-            public void ignorableWhitespace(char ch[], int start, int length)
+            public void ignorableWhitespace(char[] ch, int start, int length)
                 throws SAXException {
                 initialize();
                 super.ignorableWhitespace(ch, start, length);
             }
 
             public void objectData(Object object)
-                throws SAXException
-            {
+                throws SAXException {
                 initialize();
-                super.objectData( object );
+                super.objectData(object);
             }
 
             public void processingInstruction(String target, String data)
@@ -133,7 +141,7 @@
 
             /**
              * Ensure that the outer start element is generated
-             * before any content is output
+             * before any content is output.
              */
             protected void initialize() throws SAXException {
                 if (!outputAttributes) {

Added: jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/java/org/apache/commons/jelly/tags/xml/ReplaceNamespaceTag.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/java/org/apache/commons/jelly/tags/xml/ReplaceNamespaceTag.java?rev=219726&view=auto
==============================================================================
--- jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/java/org/apache/commons/jelly/tags/xml/ReplaceNamespaceTag.java (added)
+++ jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/java/org/apache/commons/jelly/tags/xml/ReplaceNamespaceTag.java Tue Jul 19 10:34:00 2005
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2002,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.commons.jelly.tags.xml;
+
+import org.apache.commons.jelly.JellyTagException;
+import org.apache.commons.jelly.MissingAttributeException;
+import org.apache.commons.jelly.TagSupport;
+import org.apache.commons.jelly.XMLOutput;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.AttributesImpl;
+
+/**
+ * Replace namespace is a filter to change the namespace of any
+ * elemement attribute passing through it.
+ * 
+ * @author Diogo Quintela <dq...@gmail.com>
+ */
+public class ReplaceNamespaceTag extends TagSupport {
+    private String fromNamespace;
+    private String toNamespace;
+
+    public ReplaceNamespaceTag() {
+    }
+
+    //  Tag interface
+    //-------------------------------------------------------------------------
+    public void doTag(XMLOutput output) throws MissingAttributeException, JellyTagException {
+        final String fromURI = (fromNamespace != null) ? fromNamespace : "";
+        final String toURI = (toNamespace != null) ? toNamespace : "";
+        XMLOutput newOutput = output;
+
+        if (!toURI.equals(fromURI)) {
+            newOutput = new XMLOutput(output) {
+                public void startElement(String uri, String localName, String qName, Attributes atts)
+                    throws SAXException {
+                    super.startElement(replaceURI(uri), localName, qName, replaceURI(atts));
+                }
+
+                public void endElement(String uri, String localName, String qName)
+                    throws SAXException {
+                    super.endElement(replaceURI(uri), localName, qName);
+                }
+
+                public void startPrefixMapping(String prefix, String uri)
+                    throws SAXException {
+                    super.startPrefixMapping(prefix, replaceURI(uri));
+                }
+
+                private String replaceURI(String uri) {
+                    String newUri = uri;
+
+                    if (fromURI.equals((uri != null) ? uri : "")) {
+                        newUri = toURI;
+                    }
+
+                    return newUri;
+                }
+
+                private Attributes replaceURI(Attributes atts) {
+                    AttributesImpl newAttsImpl = new AttributesImpl();
+
+                    for (int i = 0; i < atts.getLength(); i++) {
+                        // Normally attributes don't have namespaces
+                        // But may have (only if on form prefix:attr) ?
+                        // So, we'll only replace if needed
+                        String QName = atts.getQName(i);
+                        String newUri = atts.getURI(i);
+                        int idx = QName.indexOf(':');
+
+                        if (idx >= 0) {
+                            newUri = replaceURI(newUri);
+                        }
+
+                        newAttsImpl.addAttribute(newUri, atts.getLocalName(i), atts.getQName(i),
+                            atts.getType(i), atts.getValue(i));
+                    }
+
+                    return newAttsImpl;
+                }
+            };
+        }
+
+        invokeBody(newOutput);
+    }
+
+    /**
+     * @return the source namespace URI to replace
+     */
+    public String getFromURI() {
+        return fromNamespace;
+    }
+
+    /**
+     * Sets the source namespace URI to replace.
+     */
+    public void setFromURI(String namespace) {
+        this.fromNamespace = namespace;
+    }
+
+    /**
+     * @return the destination namespace URI to replace
+     */
+    public String getToURI() {
+        return toNamespace;
+    }
+
+    /**
+     * Sets the destination namespace URI to replace.
+     */
+    public void setToURI(String namespace) {
+        this.toNamespace = namespace;
+    }
+}
\ No newline at end of file

Modified: jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/java/org/apache/commons/jelly/tags/xml/XMLTagLibrary.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/java/org/apache/commons/jelly/tags/xml/XMLTagLibrary.java?rev=219726&r1=219725&r2=219726&view=diff
==============================================================================
--- jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/java/org/apache/commons/jelly/tags/xml/XMLTagLibrary.java (original)
+++ jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/java/org/apache/commons/jelly/tags/xml/XMLTagLibrary.java Tue Jul 19 10:34:00 2005
@@ -53,6 +53,7 @@
         registerTag("expr", ExprTag.class);
         registerTag("element", ElementTag.class);
         registerTag("attribute", AttributeTag.class);
+        registerTag("replaceNamespace", ReplaceNamespaceTag.class);
         registerTag("copy", CopyTag.class);
         registerTag("copyOf", CopyOfTag.class);
         registerTag("comment", CommentTag.class);

Modified: jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/TestXMLTags.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/TestXMLTags.java?rev=219726&r1=219725&r2=219726&view=diff
==============================================================================
--- jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/TestXMLTags.java (original)
+++ jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/TestXMLTags.java Tue Jul 19 10:34:00 2005
@@ -19,15 +19,20 @@
 import java.io.FileInputStream;
 import java.io.InputStream;
 import java.io.StringWriter;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
 
+import junit.framework.Assert;
 import junit.framework.Test;
 import junit.framework.TestCase;
 import junit.framework.TestSuite;
 import junit.textui.TestRunner;
 
 import org.apache.commons.jelly.JellyContext;
+import org.apache.commons.jelly.JellyException;
 import org.apache.commons.jelly.Script;
 import org.apache.commons.jelly.XMLOutput;
 import org.apache.commons.jelly.parser.XMLParser;
@@ -36,6 +41,8 @@
 import org.dom4j.Document;
 import org.dom4j.DocumentHelper;
 import org.dom4j.Node;
+import org.dom4j.io.SAXContentHandler;
+import org.dom4j.io.XMLWriter;
 
 /** Tests the parser, the engine and the XML tags
   *
@@ -84,57 +91,158 @@
             log.debug("Evaluated script as...");
             log.debug(text);
         }
-        assertEquals("Produces the correct output", "It works!", text);
+        assertEquals("Should produce the correct output", "It works!", text);
+    }
+
+    public void testElementWithNameSpace() throws Exception {
+        String text = evaluteScriptAsText(testBaseDir + "/elementWithNameSpace.jelly");
+        assertEquals("Should produce the correct output",
+                "<env:Envelope "+
+                "xmlns:env=\"http://schemas.xmlsoap.org/soap/envelope/\" "+
+                "env:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"+
+                "</env:Envelope>", text);
+    }
+
+    public void testElementWithNameSpaceError() throws Exception {
+        try {
+            evaluteScriptAsText(testBaseDir + "/elementWithNameSpaceError.jelly");
+            Assert.fail("We should have bailed out with an JellyException");
+        } catch (JellyException jex) {
+            assertTrue(jex.getReason().startsWith("Cannot set same prefix to diferent URI in same node"));
+        }
+    }
+
+    public void testNamespaceReplace() throws Exception {
+        // For this test when we not set "ns" var with expected namespace, it
+        // is expected to repeat the same two times
+        String text = evaluteScriptAsText(testBaseDir + "/namespaceReplace.jelly");
+        String repeatingText = "<test-subnode attr=\"test\"><test-anotherSubNode></test-anotherSubNode><test-anotherSubNodeAgain xmlns:other=\"\" other:abc=\"testValue\"></test-anotherSubNodeAgain></test-subnode>";
+        assertEquals("Should produce the correct output",
+                "<test-node xmlns:test=\"http://apache/testNS\" test:abc=\"testValue\">"+
+                repeatingText + repeatingText +
+                "</test-node>", text);
+
+        Map ctxVars = new HashMap();
+        ctxVars.put("ns", "http://java/ns");
+
+        text = evaluteScriptAsText(testBaseDir + "/namespaceReplace.jelly", ctxVars);
+
+        String firstTrunk =
+        "<test-subnode xmlns=\"\" attr=\"test\">" +
+        "<test-anotherSubNode>" +
+        "</test-anotherSubNode>" +
+        "<test-anotherSubNodeAgain xmlns:other=\"http://java/ns\" xmlns=\"http://java/ns\" other:abc=\"testValue\">" +
+        "</test-anotherSubNodeAgain>" +
+        "</test-subnode>";
+
+        String secondTrunk =
+            "<test-subnode attr=\"test\">" +
+            "<test-anotherSubNode>" +
+            "</test-anotherSubNode>" +
+            "<test-anotherSubNodeAgain xmlns:other=\"http://java/ns\" other:abc=\"testValue\">" +
+            "</test-anotherSubNodeAgain>" +
+            "</test-subnode>";
+
+        System.out.println("TestXMLTags.testNamespaceReplace() text="+text);
+        assertEquals("Should produce the correct output",
+                "<test-node xmlns:test=\"http://apache/testNS\" xmlns=\"http://java/ns\" test:abc=\"testValue\">"+
+                firstTrunk + secondTrunk +
+                "</test-node>", text);
+    }
+
+    public void testAttributeNameSpaceDuplicatedNS() throws Exception {
+        try {
+            evaluteScriptAsText(testBaseDir + "/attributeNameSpaceDuplicatedNS.jelly");
+            Assert.fail("We should have bailed out with an JellyException");
+        } catch (JellyException jex) {
+            assertTrue(jex.getReason().startsWith("Cannot set same prefix to diferent URI in same node"));
+        }
+    }
+
+    public void testAttributeNameSpace() throws Exception {
+        String text = evaluteScriptAsText(testBaseDir + "/attributeNameSpace.jelly");
+        System.out.println(text);
+        assertEquals("Should produce the correct output",
+                "<top-node xmlns=\"abc\">"+
+                "<test-node xmlns:test=\"http://apache/testNS\" xmlns=\"http://apache/trueNS\" test:abc=\"testValue\" abc2=\"testValue\" abc3=\"testValue\">"+
+                "<test:test-subnode><node-at-same-ns-as-top xmlns=\"abc\">"+
+                "</node-at-same-ns-as-top>"+
+                "</test:test-subnode>"+
+                "</test-node>"+
+                "</top-node>", text);
+    }
+
+    public void testAttributeNameSpaceDefaultNS() throws Exception {
+        String text = evaluteScriptAsText(testBaseDir + "/attributeNameSpaceDefaultNS.jelly");
+        System.out.println(text);
+        assertEquals("Should produce the correct output",
+                "<top-node>"+
+                "<test-node xmlns:test=\"http://apache/testNS\" xmlns=\"http://apache/trueNS\" test:abc=\"testValue\" abc2=\"testValue\" abc3=\"testValue\">"+
+                "<test:test-subnode><node-at-same-ns-as-top xmlns=\"\">"+
+                "</node-at-same-ns-as-top>"+
+                "</test:test-subnode>"+
+                "</test-node>"+
+                "</top-node>", text);
+    }
+
+    public void testAttributeNameSpaceWithInnerElements() throws Exception {
+        String text = evaluteScriptAsText(testBaseDir + "/attributeNameSpaceWithInnerElements.jelly");
+        assertEquals("Should produce the correct output",
+                "<test-node xmlns:test=\"http://apache/testNS\" test:abc=\"testValue\" abc2=\"testValue\" abc3=\"testValue\">"+
+                "<test-sub-node xmlns:test2=\"http://apache/testNS\" xmlns:test3=\"http://apache/anotherNS\" test:abc=\"testValue\" test2:abc2=\"testValue\" test3:abc3=\"testValue\">"+
+                "</test-sub-node>"+
+                "</test-node>"
+                , text);
     }
 
     public void testTransform() throws Exception {
         String text = evaluteScriptAsText(testBaseDir + "/transformExample.jelly");
-        assertEquals("Produces the correct output", "It works!", text);
+        assertEquals("Should produce the correct output", "It works!", text);
     }
 
     public void testTransformAllInLine() throws Exception {
         String text = evaluteScriptAsText(testBaseDir + "/transformExampleAllInLine.jelly");
-        assertEquals("Produces the correct output", "It works!", text);
+        assertEquals("Should produce the correct output", "It works!", text);
     }
 
     public void testTransformParams() throws Exception {
         String text = evaluteScriptAsText(testBaseDir + "/transformParamExample.jelly");
-        assertEquals("Produces the correct output", "It works!", text);
+        assertEquals("Should produce the correct output", "It works!", text);
     }
 
     public void testTransformParamsInLine() throws Exception {
 
         String text = evaluteScriptAsText(testBaseDir + "/transformParamExample2.jelly");
-        assertEquals("Produces the correct output", "It works!", text);
+        assertEquals("Should produce the correct output", "It works!", text);
     }
 
     public void testTransformSAXOutput() throws Exception {
         String text = evaluteScriptAsText(testBaseDir + "/transformExampleSAXOutput.jelly");
-        assertEquals("Produces the correct output", "It works!", text);
+        assertEquals("Should produce the correct output", "It works!", text);
     }
 
     public void testTransformSAXOutputNestedTransforms() throws Exception {
         String text = evaluteScriptAsText(testBaseDir +
             "/transformExampleSAXOutputNestedTransforms.jelly");
-        assertEquals("Produces the correct output", "It works!", text);
+        assertEquals("Should produce the correct output", "It works!", text);
     }
 
     public void testTransformSchematron() throws Exception {
         String text = evaluteScriptAsText(testBaseDir +
             "/schematron/transformSchematronExample.jelly");
-        assertEquals("Produces the correct output", "Report count=1:assert count=2", text);
+        assertEquals("Should produce the correct output", "Report count=1:assert count=2", text);
     }
 
     public void testTransformXmlVar() throws Exception {
         String text = evaluteScriptAsText(testBaseDir +
             "/transformExampleXmlVar.jelly");
-        assertEquals("Produces the correct output", "It works!", text);
+        assertEquals("Should produce the correct output", "It works!", text);
     }
 
     public void testDoctype() throws Exception {
         String text = evaluteScriptAsText(testBaseDir +
             "/testDoctype.jelly");
-        assertEquals("Produces the correct output", "<!DOCTYPE foo PUBLIC \"publicID\" \"foo.dtd\">\n<foo></foo>", text);
+        assertEquals("Should produce the correct output", "<!DOCTYPE foo PUBLIC \"publicID\" \"foo.dtd\">\n<foo></foo>", text);
     }
 
     public void runUnitTest(String name) throws Exception {
@@ -172,7 +280,23 @@
      * returns the whitespace trimmed output as text
      */
     protected String evaluteScriptAsText(String fileName) throws Exception {
+        return evaluteScriptAsText(fileName, null);
+    }
+
+    /**
+     * Evaluates the script by the given file name and
+     * returns the whitespace trimmed output as text
+     */
+    protected String evaluteScriptAsText(String fileName, Map ctxVars) throws Exception {
         JellyContext context = new JellyContext();
+        if (ctxVars != null) {
+            Set keys = ctxVars.keySet();
+            for (Iterator iterator = keys.iterator(); iterator.hasNext();) {
+                String key = (String) iterator.next();
+                Object value = ctxVars.get(key);
+                context.setVariable(key, value);
+            }
+        }
 
         // allow scripts to refer to any resource inside this project
         // using an absolute URI like /src/test/org/apache/foo.xml
@@ -190,4 +314,49 @@
         }
         return text;
     }
+
+    protected String evaluteScriptAsTextUsingSaxContentHandler(String fileName, Map ctxVars) throws Exception {
+        org.dom4j.io.OutputFormat outputFormat = new org.dom4j.io.OutputFormat();
+        outputFormat.setSuppressDeclaration(true);
+        outputFormat.setNewlines(false);
+        outputFormat.setIndent(false);
+        outputFormat.setExpandEmptyElements(true);
+        //outputFormat.setIndentSize(4);
+
+        StringWriter buffer = new StringWriter();
+        XMLWriter xmlWriter = new XMLWriter(buffer, outputFormat);
+        // xmlWriter.setEscapeText(false);
+
+        SAXContentHandler saxHandler = new SAXContentHandler();
+        XMLOutput output = new XMLOutput(saxHandler);
+
+        // now run a script using a URL
+        JellyContext context = new JellyContext();
+        if (ctxVars != null) {
+            Set keys = ctxVars.keySet();
+            for (Iterator iterator = keys.iterator(); iterator.hasNext();) {
+                String key = (String) iterator.next();
+                Object value = ctxVars.get(key);
+                context.setVariable(key, value);
+            }
+        }
+
+        // allow scripts to refer to any resource inside this project
+        // using an absolute URI like /src/test/org/apache/foo.xml
+        context.setRootURL(new File(".").toURL());
+
+        output.startDocument();
+        context.runScript(new File(fileName), output);
+        output.endDocument();
+        xmlWriter.write(saxHandler.getDocument());
+        xmlWriter.flush();
+
+        String text = buffer.toString().trim();
+        if (log.isDebugEnabled()) {
+            log.debug("Evaluated script as...");
+            log.debug(text);
+        }
+        return text;
+    }
+
 }

Added: jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/attributeNameSpace.jelly
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/attributeNameSpace.jelly?rev=219726&view=auto
==============================================================================
--- jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/attributeNameSpace.jelly (added)
+++ jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/attributeNameSpace.jelly Tue Jul 19 10:34:00 2005
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<j:jelly xmlns:j="jelly:core" xmlns:x="jelly:xml" xmlns="abc">
+    <top-node>
+        <x:element URI="http://apache/trueNS" name="test-node">
+            <x:attribute URI="http://apache/testNS" name="test:abc" trim="true">testValue</x:attribute>
+            <!-- attributes without ':' should not have namespace -->
+            <x:attribute URI="http://apache/testNS" name="abc2" trim="true">testValue</x:attribute>
+            <x:attribute name="abc3" trim="true">testValue</x:attribute>
+            <x:element URI="http://apache/testNS" name="test:test-subnode">
+                <node-at-same-ns-as-top/>
+            </x:element>
+        </x:element>
+    </top-node>
+</j:jelly>
+

Added: jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/attributeNameSpaceDefaultNS.jelly
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/attributeNameSpaceDefaultNS.jelly?rev=219726&view=auto
==============================================================================
--- jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/attributeNameSpaceDefaultNS.jelly (added)
+++ jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/attributeNameSpaceDefaultNS.jelly Tue Jul 19 10:34:00 2005
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<j:jelly xmlns:j="jelly:core" xmlns:x="jelly:xml">
+    <top-node>
+        <x:element URI="http://apache/trueNS" name="test-node">
+            <x:attribute URI="http://apache/testNS" name="test:abc" trim="true">testValue</x:attribute>
+            <!-- attributes without ':' should not have namespace -->
+            <x:attribute URI="http://apache/testNS" name="abc2" trim="true">testValue</x:attribute>
+            <x:attribute name="abc3" trim="true">testValue</x:attribute>
+            <x:element URI="http://apache/testNS" name="test:test-subnode">
+                <node-at-same-ns-as-top/>
+            </x:element>
+        </x:element>
+    </top-node>
+</j:jelly>
+

Added: jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/attributeNameSpaceDuplicatedNS.jelly
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/attributeNameSpaceDuplicatedNS.jelly?rev=219726&view=auto
==============================================================================
--- jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/attributeNameSpaceDuplicatedNS.jelly (added)
+++ jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/attributeNameSpaceDuplicatedNS.jelly Tue Jul 19 10:34:00 2005
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<j:jelly xmlns:j="jelly:core" xmlns:x="jelly:xml">
+    <x:element name="test-node">
+        <x:attribute URI="http://apache/testNS" name="test:abc" trim="true">testValue</x:attribute>
+        <x:attribute URI="http://apache/anotherNS" name="test:abc2" trim="true">testValue</x:attribute>
+    </x:element>
+</j:jelly>
+

Added: jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/attributeNameSpaceWithInnerElements.jelly
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/attributeNameSpaceWithInnerElements.jelly?rev=219726&view=auto
==============================================================================
--- jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/attributeNameSpaceWithInnerElements.jelly (added)
+++ jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/attributeNameSpaceWithInnerElements.jelly Tue Jul 19 10:34:00 2005
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<j:jelly xmlns:j="jelly:core" xmlns:x="jelly:xml">
+    <x:element name="test-node">
+        <x:attribute URI="http://apache/testNS" name="test:abc" trim="true">testValue</x:attribute>
+        <!-- attributes without ':' should not have namespace -->
+        <x:attribute URI="http://apache/testNS" name="abc2" trim="true">testValue</x:attribute>
+        <x:attribute name="abc3" trim="true">testValue</x:attribute>
+
+        <x:element name="test-sub-node">
+            <x:attribute URI="http://apache/testNS" name="test:abc" trim="true">testValue</x:attribute>
+            <x:attribute URI="http://apache/testNS" name="test2:abc2" trim="true">testValue</x:attribute>
+            <x:attribute URI="http://apache/anotherNS" name="test3:abc3" trim="true">testValue</x:attribute>
+        </x:element>
+    </x:element>
+</j:jelly>
+

Added: jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/elementWithNameSpace.jelly
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/elementWithNameSpace.jelly?rev=219726&view=auto
==============================================================================
--- jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/elementWithNameSpace.jelly (added)
+++ jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/elementWithNameSpace.jelly Tue Jul 19 10:34:00 2005
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<j:jelly xmlns:j="jelly:core" xmlns:x="jelly:xml">
+    <x:element URI="http://schemas.xmlsoap.org/soap/envelope/" name="env:Envelope">
+        <x:attribute URI="http://schemas.xmlsoap.org/soap/envelope/" 
+                     name="env:encodingStyle" trim="true">
+            http://schemas.xmlsoap.org/soap/encoding/
+        </x:attribute>
+    </x:element>
+</j:jelly>
+

Added: jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/elementWithNameSpaceError.jelly
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/elementWithNameSpaceError.jelly?rev=219726&view=auto
==============================================================================
--- jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/elementWithNameSpaceError.jelly (added)
+++ jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/elementWithNameSpaceError.jelly Tue Jul 19 10:34:00 2005
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<j:jelly xmlns:j="jelly:core" xmlns:x="jelly:xml">
+    <x:element URI="http://schemas.xmlsoap.org/soap/envelope/" name="env:Envelope">
+        <x:attribute name="env:encodingStyle" trim="true">
+            http://schemas.xmlsoap.org/soap/encoding/
+        </x:attribute>
+    </x:element>
+</j:jelly>
+

Added: jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/namespaceReplace.jelly
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/namespaceReplace.jelly?rev=219726&view=auto
==============================================================================
--- jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/namespaceReplace.jelly (added)
+++ jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/namespaceReplace.jelly Tue Jul 19 10:34:00 2005
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<j:jelly xmlns:j="jelly:core" xmlns:x="jelly:xml">
+    <x:element URI="${ns}" name="test-node">
+        <x:attribute URI="http://apache/testNS" name="test:abc" trim="true">testValue</x:attribute>
+
+        <test-subnode attr="test">
+            <test-anotherSubNode />
+            <x:element URI="${ns}" name="test-anotherSubNodeAgain">
+                <x:attribute URI="${ns}" name="other:abc" trim="true">testValue</x:attribute>
+            </x:element>
+        </test-subnode>
+
+        <x:replaceNamespace toURI="${ns}">
+            <test-subnode attr="test">
+                <test-anotherSubNode />
+                <x:element URI="${ns}" name="test-anotherSubNodeAgain">
+                    <x:attribute URI="${ns}" name="other:abc" trim="true">testValue</x:attribute>
+                </x:element>
+            </test-subnode>
+        </x:replaceNamespace>
+    </x:element>
+</j:jelly>
+

Modified: jakarta/commons/proper/jelly/trunk/src/java/org/apache/commons/jelly/XMLOutput.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/jelly/trunk/src/java/org/apache/commons/jelly/XMLOutput.java?rev=219726&r1=219725&r2=219726&view=diff
==============================================================================
--- jakarta/commons/proper/jelly/trunk/src/java/org/apache/commons/jelly/XMLOutput.java (original)
+++ jakarta/commons/proper/jelly/trunk/src/java/org/apache/commons/jelly/XMLOutput.java Tue Jul 19 10:34:00 2005
@@ -20,6 +20,11 @@
 import java.io.OutputStream;
 import java.io.UnsupportedEncodingException;
 import java.io.Writer;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -44,29 +49,35 @@
 public class XMLOutput implements ContentHandler, LexicalHandler {
 
     protected static final String[] LEXICAL_HANDLER_NAMES =
-        {
-            "http://xml.org/sax/properties/lexical-handler",
-            "http://xml.org/sax/handlers/LexicalHandler" };
+     {
+        "http://xml.org/sax/properties/lexical-handler",
+        "http://xml.org/sax/handlers/LexicalHandler" };
 
-    /** empty attributes */
+    /** Empty attributes. */
     private static final Attributes EMPTY_ATTRIBUTES = new AttributesImpl();
 
     /** The Log to which logging calls will be made. */
     private static final Log log = LogFactory.getLog(XMLOutput.class);
 
-    /** the default for escaping of text */
+    /** the default for escaping of text. */
     private static final boolean DEFAULT_ESCAPE_TEXT = false;
 
-    /** The SAX ContentHandler that output goes to */
+    /** The SAX ContentHandler that output goes to. */
     private ContentHandler contentHandler;
 
-    /** The SAX LexicalHandler that output goes to */
+    /** The SAX LexicalHandler that output goes to. */
     private LexicalHandler lexicalHandler;
 
+    /** Stack of kown namespaces. */
+    private NamespaceStack namespaceStack = new NamespaceStack();
 
     public XMLOutput() {
     }
 
+    /** The XML-output will relay the SAX events to the indicated
+     * contentHandler.
+     * @param contentHandler
+     */
     public XMLOutput(ContentHandler contentHandler) {
         this.contentHandler = contentHandler;
         // often classes will implement LexicalHandler as well
@@ -75,6 +86,11 @@
         }
     }
 
+    /** The XML-output will relay the SAX events to the indicated
+     * content-handler lexical-handler.
+     * @param contentHandler
+     * @param lexicalHandler
+     */
     public XMLOutput(
         ContentHandler contentHandler,
         LexicalHandler lexicalHandler) {
@@ -92,16 +108,25 @@
     }
 
     /**
-     * Provides a useful hook that implementations can use to close the
-     * underlying OutputStream or Writer
+     * Provides a useful hook that implementations
+     * can use to close the
+     * underlying OutputStream or Writer.
+     *
+     * @throws IOException
      */
     public void close() throws IOException {
     }
 
+    /** Flushes the underlying stream if {@link XMLWriter}
+     * or {@link XMLOutput}.
+     *
+     * @throws IOException
+     */
     public void flush() throws IOException {
-        if( contentHandler instanceof XMLWriter )
-        {
+        if (contentHandler instanceof XMLWriter) {
             ((XMLWriter)contentHandler).flush();
+        } else if (contentHandler instanceof XMLOutput) {
+            ((XMLOutput)contentHandler).flush();
         }
     }
 
@@ -109,7 +134,7 @@
     //-------------------------------------------------------------------------
 
     /**
-     * Creates an XMLOutput from an existing SAX XMLReader
+     * Creates an XMLOutput from an existing SAX XMLReader.
      */
     public static XMLOutput createXMLOutput(XMLReader xmlReader) {
         XMLOutput output = new XMLOutput(xmlReader.getContentHandler());
@@ -122,10 +147,11 @@
                     output.setLexicalHandler((LexicalHandler) value);
                     break;
                 }
-            }
-            catch (Exception e) {
+            } catch (Exception e) {
                 // ignore any unsupported-operation exceptions
-                if (log.isDebugEnabled()) log.debug("error setting lexical handler properties", e);
+                if (log.isDebugEnabled()) {
+                    log.debug("error setting lexical handler properties", e);
+                }
             }
         }
         return output;
@@ -145,10 +171,9 @@
      *
      * @param writer is the writer to output to
      * @param escapeText is whether or not text output will be escaped. This must be true
-     * if the underlying output is XML or could be false if the underlying output is textual.
+     *   if the underlying output is XML or could be false if the underlying output is textual.
      */
-    public static XMLOutput createXMLOutput(Writer writer, boolean escapeText)
-    {
+    public static XMLOutput createXMLOutput(Writer writer, boolean escapeText) {
         XMLWriter xmlWriter = new XMLWriter(writer);
         xmlWriter.setEscapeText(escapeText);
         return createXMLOutput(xmlWriter);
@@ -169,8 +194,11 @@
      * @param out is the output stream to write
      * @param escapeText is whether or not text output will be escaped. This must be true
      * if the underlying output is XML or could be false if the underlying output is textual.
+     * @throws UnsupportedEncodingException if the underlying write could not
+     *   be created.
      */
-    public static XMLOutput createXMLOutput(OutputStream out, boolean escapeText) throws UnsupportedEncodingException {
+    public static XMLOutput createXMLOutput(OutputStream out, boolean escapeText)
+            throws UnsupportedEncodingException {
         XMLWriter xmlWriter = new XMLWriter(out);
         xmlWriter.setEscapeText(escapeText);
         return createXMLOutput(xmlWriter);
@@ -193,7 +221,7 @@
     /**
      * Outputs the given String as a piece of valid text in the
      * XML event stream.
-     * Any special XML characters should be properly escaped.
+     * Any special XML characters should come out properly escaped.
      */
     public void write(String text) throws SAXException {
         char[] ch = text.toCharArray();
@@ -212,7 +240,7 @@
     }
 
     /**
-     * Outputs a comment to the XML stream
+     * Outputs a comment to the XML stream.
      */
     public void writeComment(String text) throws SAXException {
         char[] ch = text.toCharArray();
@@ -220,21 +248,24 @@
     }
 
     /**
-     * Helper method for outputting a start element event for an element in no namespace
+     * Helper method for outputting a start element event
+     * for an element in no namespace.
      */
     public void startElement(String localName) throws SAXException {
         startElement("", localName, localName, EMPTY_ATTRIBUTES);
     }
 
     /**
-     * Helper method for outputting a start element event for an element in no namespace
+     * Helper method for outputting a start element event
+     * for an element in no namespace.
      */
     public void startElement(String localName, Attributes attributes) throws SAXException {
         startElement("", localName, localName, attributes);
     }
 
     /**
-     * Helper method for outputting an end element event for an element in no namespace
+     * Helper method for outputting an end element event
+     * for an element in no namespace.
      */
     public void endElement(String localName) throws SAXException {
         endElement("", localName, localName);
@@ -344,7 +375,9 @@
      * @see #startElement
      */
     public void startPrefixMapping(String prefix, String uri) throws SAXException {
-        contentHandler.startPrefixMapping(prefix, uri);
+        namespaceStack.pushNamespace(prefix, uri);
+        // contentHandler.startPrefixMapping(prefix, uri) will be called if needed
+        // in pushNamespace
     }
 
     /**
@@ -364,7 +397,9 @@
      * @see #endElement
      */
     public void endPrefixMapping(String prefix) throws SAXException {
-        contentHandler.endPrefixMapping(prefix);
+        namespaceStack.popNamespace(prefix);
+        // End prefix mapping was already called after endElement
+        // contentHandler.endPrefixMapping(prefix);
     }
 
     /**
@@ -435,7 +470,28 @@
         String qName,
         Attributes atts)
         throws SAXException {
+
+        int idx = qName.indexOf(':');
+        String attNsPrefix = "";
+        if (idx >= 0) {
+            attNsPrefix = qName.substring(0, idx);
+        }
+        namespaceStack.pushNamespace(attNsPrefix, uri);
+        for (int i = 0; i < atts.getLength(); i++) {
+            String attQName = atts.getQName(i);
+            // An attribute only has an namespace if has a prefix
+            // If not, stays in namespace of containing node
+            idx = attQName.indexOf(':');
+            if (idx >= 0) {
+                attNsPrefix = attQName.substring(0, idx);
+                String attUri = atts.getURI(i);
+                namespaceStack.pushNamespace(attNsPrefix, attUri);
+            }
+        }
+
         contentHandler.startElement(uri, localName, qName, atts);
+        // Inform namespaceStack of a new depth
+        namespaceStack.increaseLevel();
     }
 
     /**
@@ -462,6 +518,9 @@
     public void endElement(String uri, String localName, String qName)
         throws SAXException {
         contentHandler.endElement(uri, localName, qName);
+        // Inform namespaceStack to return to previous depth
+        namespaceStack.decreaseLevel();
+        namespaceStack.popNamespaces();
     }
 
     /**
@@ -507,7 +566,7 @@
      * @see #ignorableWhitespace
      * @see org.xml.sax.Locator
      */
-    public void characters(char ch[], int start, int length) throws SAXException {
+    public void characters(char[] ch, int start, int length) throws SAXException {
         contentHandler.characters(ch, start, length);
     }
 
@@ -535,7 +594,7 @@
      *            wrapping another exception.
      * @see #characters
      */
-    public void ignorableWhitespace(char ch[], int start, int length)
+    public void ignorableWhitespace(char[] ch, int start, int length)
         throws SAXException {
         contentHandler.ignorableWhitespace(ch, start, length);
     }
@@ -855,4 +914,127 @@
         return answer;
     }
 
+    private final class NamespaceStack {
+        /** A list of maps: Each map contains prefix->uri mapping */
+        private List nsStack;
+
+        private NamespaceStack() {
+            this.nsStack = new ArrayList();
+            this.nsStack.add(new HashMap());
+        }
+
+        private boolean isRootNodeDefaultNs(String prefix, String uri) {
+            return ("".equals(prefix) && "".equals(uri) && nsStack.size() == 1);
+        }
+
+        public void pushNamespace(String prefix, String uri) throws SAXException {
+            Map prefixUriMap;
+
+            if (prefix == null) {
+                prefix = "";
+            }
+            if (uri == null) {
+                uri = "";
+            }
+
+            if ("xml".equals(prefix)) {
+                // We should ignore setting 'xml' prefix
+                // As declared in java of ContentHandler#startPrefixMapping
+                return;
+            }
+
+
+            // Lets find out if we already declared this same prefix,
+            // if not declare in current depth map (the first of list)
+            // and call contentHandler.startPrefixMapping(prefix, uri);
+            boolean isNew = true;
+            for (Iterator iter = nsStack.iterator(); iter.hasNext();) {
+                prefixUriMap = (Map) iter.next();
+                if (prefixUriMap.containsKey(prefix)) {
+                    if (uri.equals(prefixUriMap.get(prefix))) {
+                        // Its an active namespace already
+                        // System.out.println(">>>"+XMLOutput.this.hashCode()+">NamespaceStack.pushNamespace() IS NOT NEW prefix="+prefix+",uri="+uri);
+                        isNew = false;
+                    }
+                    // We found it in stack
+                    // If it was exacly the same, we won't bother
+                    break;
+                }
+            }
+
+            if (isNew) {
+                // not declared sometime before
+                prefixUriMap = (Map) nsStack.get(0); // Current depth map
+                // Sanity check: Don't let two prefixes for diferent uris in
+                // same depth
+                if (prefixUriMap.containsKey(prefix)) {
+                    if (!uri.equals(prefixUriMap.get(prefix))) {
+                        throw new SAXException("Cannot set same prefix to diferent URI in same node: trying to add prefix \""
+                                + prefix + "\" for uri \""+uri+"\" whereas the declared ones are " + prefixUriMap);
+                    }
+                } else {
+                    prefixUriMap.put(prefix, uri);
+
+                    // To avoid setting xmlns="" for top node (not very nice :D)
+                    // We need to especificaly check this condition
+                    if (!isRootNodeDefaultNs(prefix, uri)) {
+//                        System.out.println(">>>"+XMLOutput.this.hashCode()+">NamespaceStack.pushNamespace() prefix="+prefix+",uri="+uri);
+                        contentHandler.startPrefixMapping(prefix, uri);
+                    }
+                }
+            }
+        }
+
+        public void popNamespaces() throws SAXException {
+            Map prefixUriMap = (Map)nsStack.get(0);
+            for (Iterator iter = prefixUriMap.keySet().iterator();iter.hasNext();) {
+                String prefix = (String)iter.next();
+                String uri = (String) prefixUriMap.get(prefix);
+                iter.remove();
+
+                // If we havent called startPrefixMapping for root node if we wanted to avoid xmlns=""
+                // We aren't going to call endPrefixMapping neither
+                if (!isRootNodeDefaultNs(prefix, uri)) {
+//                    System.out.println(">>>"+XMLOutput.this.hashCode()+">NamespaceStack.popNamespaces() prefix="+prefix);
+                    contentHandler.endPrefixMapping(prefix);
+                }
+            }
+        }
+
+        public void popNamespace(String prefix) throws SAXException {
+            Map prefixUriMap = (Map)nsStack.get(0);
+
+            if (prefix == null) {
+                prefix = "";
+            }
+
+            if ("xml".equals(prefix)) {
+                // We should ignore setting 'xml' prefix
+                // As declared in java of ContentHandler#startPrefixMapping
+                return;
+            }
+
+            if (prefixUriMap.containsKey(prefix)) {
+                String uri = (String) prefixUriMap.get(prefix);
+                prefixUriMap.remove(prefix);
+                // If we havent called startPrefixMapping for root node if we wanted to avoid xmlns=""
+                // We aren't going to call endPrefixMapping neither
+                if (!isRootNodeDefaultNs(prefix, uri)) {
+//                    System.out.println(">>>"+XMLOutput.this.hashCode()+">NamespaceStack.popNamespace() prefix="+prefix);
+                    contentHandler.endPrefixMapping(prefix);
+                }
+            }/* else {
+                improper nesting ? or already removed in popNamespaces
+            }
+            */
+        }
+
+        public void decreaseLevel() {
+            nsStack.remove(0);
+        }
+
+        public void increaseLevel() {
+            nsStack.add(0, new HashMap());
+        }
+    }
 }

Modified: jakarta/commons/proper/jelly/trunk/src/java/org/apache/commons/jelly/impl/StaticTag.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/jelly/trunk/src/java/org/apache/commons/jelly/impl/StaticTag.java?rev=219726&r1=219725&r2=219726&view=diff
==============================================================================
--- jakarta/commons/proper/jelly/trunk/src/java/org/apache/commons/jelly/impl/StaticTag.java (original)
+++ jakarta/commons/proper/jelly/trunk/src/java/org/apache/commons/jelly/impl/StaticTag.java Tue Jul 19 10:34:00 2005
@@ -69,6 +69,15 @@
         }
     }
 
+    public void setAttribute(String name, String prefix, String nsURI, Object value) {
+        if(value==null)
+            return;
+        if(prefix!=null && prefix.length()>0)
+            attributes.addAttribute(nsURI,name,prefix+":"+name,"CDATA",value.toString());
+        else
+            attributes.addAttribute("",name,name,"CDATA",value.toString());
+    }
+
     // DynaTag interface
     //-------------------------------------------------------------------------
     public void setAttribute(String name, Object value) throws JellyTagException {

Modified: jakarta/commons/proper/jelly/trunk/src/java/org/apache/commons/jelly/impl/StaticTagScript.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/jelly/trunk/src/java/org/apache/commons/jelly/impl/StaticTagScript.java?rev=219726&r1=219725&r2=219726&view=diff
==============================================================================
--- jakarta/commons/proper/jelly/trunk/src/java/org/apache/commons/jelly/impl/StaticTagScript.java (original)
+++ jakarta/commons/proper/jelly/trunk/src/java/org/apache/commons/jelly/impl/StaticTagScript.java Tue Jul 19 10:34:00 2005
@@ -86,7 +86,10 @@
             for (Iterator iter = attributes.entrySet().iterator(); iter.hasNext();) {
                 Map.Entry entry = (Map.Entry) iter.next();
                 String name = (String) entry.getKey();
-                Expression expression = (Expression) entry.getValue();
+                if(name.indexOf(':')!=-1)
+                    name = name.substring(name.indexOf(':')+1);
+                ExpressionAttribute expat = (ExpressionAttribute) entry.getValue();
+                Expression expression = expat.exp;
 
                 Object value = null;
 
@@ -96,7 +99,10 @@
                     value = expression.evaluate(context);
                 }
 
-                dynaTag.setAttribute(name, value);
+                if(expat.prefix!=null || expat.prefix.length()>0 && tag instanceof StaticTag)
+                    ((StaticTag) dynaTag).setAttribute(name,expat.prefix, expat.nsURI,value);
+                else
+                    dynaTag.setAttribute(name, value);
             }
 
             tag.doTag(output);

Modified: jakarta/commons/proper/jelly/trunk/src/java/org/apache/commons/jelly/impl/TagScript.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/jelly/trunk/src/java/org/apache/commons/jelly/impl/TagScript.java?rev=219726&r1=219725&r2=219726&view=diff
==============================================================================
--- jakarta/commons/proper/jelly/trunk/src/java/org/apache/commons/jelly/impl/TagScript.java (original)
+++ jakarta/commons/proper/jelly/trunk/src/java/org/apache/commons/jelly/impl/TagScript.java Tue Jul 19 10:34:00 2005
@@ -170,7 +170,19 @@
         if (log.isDebugEnabled()) {
             log.debug("adding attribute name: " + name + " expression: " + expression);
         }
-        attributes.put(name, expression);
+        attributes.put(name, new ExpressionAttribute(name,expression));
+    }
+
+    /** Add an initialization attribute for the tag.
+     * This method must be called after the setTag() method
+     */
+    public void addAttribute(String name, String prefix, String nsURI, Expression expression) {
+        if (log.isDebugEnabled()) {
+            log.debug("adding attribute name: " + name + " expression: " + expression);
+        }
+        if(name.indexOf(':')==-1)
+            name = prefix + ':' + name;
+        attributes.put(name, new ExpressionAttribute(name,prefix,nsURI,expression));
     }
 
     /**
@@ -206,7 +218,7 @@
                 for (Iterator iter = attributes.entrySet().iterator(); iter.hasNext();) {
                     Map.Entry entry = (Map.Entry) iter.next();
                     String name = (String) entry.getKey();
-                    Expression expression = (Expression) entry.getValue();
+                    Expression expression = ((ExpressionAttribute) entry.getValue()).exp;
 
                     Class type = dynaTag.getAttributeType(name);
                     Object value = null;
@@ -225,7 +237,7 @@
                 for (Iterator iter = attributes.entrySet().iterator(); iter.hasNext();) {
                     Map.Entry entry = (Map.Entry) iter.next();
                     String name = (String) entry.getKey();
-                    Expression expression = (Expression) entry.getValue();
+                    Expression expression = ((ExpressionAttribute) entry.getValue()).exp;
 
                     DynaProperty property = dynaBean.getDynaClass().getDynaProperty(name);
                     if (property == null) {
@@ -690,3 +702,21 @@
         throw new JellyTagException(e, fileName, elementName, columnNumber, lineNumber);
     }
 }
+
+
+class ExpressionAttribute {
+    public ExpressionAttribute(String name, Expression exp) {
+        this(name,"","",exp);
+    }
+    public ExpressionAttribute(String name, String prefix, String nsURI, Expression exp) {
+        this.name = name;
+        this.prefix = prefix;
+        this.nsURI = nsURI;
+        this.exp = exp;
+    }
+
+    String name;
+    String prefix;
+    String nsURI;
+    Expression exp;
+}
\ No newline at end of file

Modified: jakarta/commons/proper/jelly/trunk/src/java/org/apache/commons/jelly/parser/XMLParser.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/jelly/trunk/src/java/org/apache/commons/jelly/parser/XMLParser.java?rev=219726&r1=219725&r2=219726&view=diff
==============================================================================
--- jakarta/commons/proper/jelly/trunk/src/java/org/apache/commons/jelly/parser/XMLParser.java (original)
+++ jakarta/commons/proper/jelly/trunk/src/java/org/apache/commons/jelly/parser/XMLParser.java Tue Jul 19 10:34:00 2005
@@ -1066,7 +1066,12 @@
                         attributeValue, getExpressionFactory()
                     );
                 String attrQName = list.getQName(i);
-                script.addAttribute(attrQName, expression);
+                int p = attrQName.indexOf(':');
+                String prefix = p>=0 ?
+                        attrQName.substring(0,p):
+                        "";
+                script.addAttribute(list.getLocalName(i),
+                        prefix, list.getURI(i), expression);
             }
             return script;
         }

Modified: jakarta/commons/proper/jelly/trunk/src/test/org/apache/commons/jelly/TestCoreTags.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/jelly/trunk/src/test/org/apache/commons/jelly/TestCoreTags.java?rev=219726&r1=219725&r2=219726&view=diff
==============================================================================
--- jakarta/commons/proper/jelly/trunk/src/test/org/apache/commons/jelly/TestCoreTags.java (original)
+++ jakarta/commons/proper/jelly/trunk/src/test/org/apache/commons/jelly/TestCoreTags.java Tue Jul 19 10:34:00 2005
@@ -105,4 +105,24 @@
         textScript.trimStartWhitespace();
         assertEquals("foo", textScript.getText());
     }
+
+
+    public void testStaticNamespacedAttributes() throws Exception {
+        InputStream in = new FileInputStream("src/test/org/apache/commons/jelly/testStaticNamespacedAttributes.jelly");
+        XMLParser parser = new XMLParser();
+        Script script = parser.parse(in);
+        script = script.compile();
+        log.debug("Found: " + script);
+        JellyContext context = new JellyContext();
+        StringWriter buffer = new StringWriter();
+        script.run(context, XMLOutput.createXMLOutput(buffer));
+        String text = buffer.toString().trim();
+        if (log.isDebugEnabled()) {
+            log.debug("Evaluated script as...");
+            log.debug(text);
+        }
+        assertEquals("Should produces the correct output",
+                "<blip xmlns:blop=\"blop\" blop:x=\"blip\"></blip>",
+                text);
+    }
 }

Modified: jakarta/commons/proper/jelly/trunk/src/test/org/apache/commons/jelly/core/TestFileTag.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/jelly/trunk/src/test/org/apache/commons/jelly/core/TestFileTag.java?rev=219726&r1=219725&r2=219726&view=diff
==============================================================================
--- jakarta/commons/proper/jelly/trunk/src/test/org/apache/commons/jelly/core/TestFileTag.java (original)
+++ jakarta/commons/proper/jelly/trunk/src/test/org/apache/commons/jelly/core/TestFileTag.java Tue Jul 19 10:34:00 2005
@@ -55,7 +55,7 @@
 
         //FIXME This doesn't take into account attribute ordering
         assertEquals("fully qualified attributes not passed",
-                "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\"></html>",
+                "<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"en\" xml:lang=\"en\"></html>",
                 data);
     }
 

Added: jakarta/commons/proper/jelly/trunk/src/test/org/apache/commons/jelly/testStaticNamespacedAttributes.jelly
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/jelly/trunk/src/test/org/apache/commons/jelly/testStaticNamespacedAttributes.jelly?rev=219726&view=auto
==============================================================================
--- jakarta/commons/proper/jelly/trunk/src/test/org/apache/commons/jelly/testStaticNamespacedAttributes.jelly (added)
+++ jakarta/commons/proper/jelly/trunk/src/test/org/apache/commons/jelly/testStaticNamespacedAttributes.jelly Tue Jul 19 10:34:00 2005
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<j:jelly xmlns:j="jelly:core">
+	<blip xmlns:blop="blop" blop:x="blip"/>
+</j:jelly>



---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org


Re: svn commit: r219726 - in /jakarta/commons/proper/jelly/trunk: jelly-tags/xml/ jelly-tags/xml/src/java/org/apache/commons/jelly/tags/xml/ jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/ src/java/org/apache/commons/jelly/ src/java/org/ap

Posted by Paul Libbrecht <pa...@activemath.org>.
Le 20 juil. 05, à 01:08, Dion Gillard a écrit :
> could you make the <version> tag 1.2-SNAPSHOT instead of -dev? That 
> keeps it all consistent.

I wanted to ask about this.
Actually, I've also made 1.1-dev into jelly's project.xml.
Isn't SNAPSHOT supposed to be a (fake but complete) version number? 
What we want is something else, or ?

> And how about an update to the changes.xml file?

Sure, that soon.

Also, how could I upload the snapshot at some point?

thanks

paul


---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org


Re: svn commit: r219726 - in /jakarta/commons/proper/jelly/trunk: jelly-tags/xml/ jelly-tags/xml/src/java/org/apache/commons/jelly/tags/xml/ jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/ src/java/org/apache/commons/jelly/ src/java/org/ap

Posted by Dion Gillard <di...@gmail.com>.
Hi Paul,

could you make the <version> tag 1.2-SNAPSHOT instead of -dev? That
keeps it all consistent.

And how about an update to the changes.xml file?

On 7/20/05, polx@apache.org <po...@apache.org> wrote:
> Author: polx
> Date: Tue Jul 19 10:34:00 2005
> New Revision: 219726
> 
> URL: http://svn.apache.org/viewcvs?rev=219726&view=rev
> Log:
> Fixing treatment of namespaced-qualified attributes in XML taglib and
> in the xml-output.
> This fixes JELLY-213 and JELLY-214.
> paul
> 
> Added:
>     jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/java/org/apache/commons/jelly/tags/xml/ReplaceNamespaceTag.java
>     jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/attributeNameSpace.jelly
>     jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/attributeNameSpaceDefaultNS.jelly
>     jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/attributeNameSpaceDuplicatedNS.jelly
>     jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/attributeNameSpaceWithInnerElements.jelly
>     jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/elementWithNameSpace.jelly
>     jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/elementWithNameSpaceError.jelly
>     jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/namespaceReplace.jelly
>     jakarta/commons/proper/jelly/trunk/src/test/org/apache/commons/jelly/testStaticNamespacedAttributes.jelly
> Modified:
>     jakarta/commons/proper/jelly/trunk/jelly-tags/xml/project.xml
>     jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/java/org/apache/commons/jelly/tags/xml/AttributeTag.java
>     jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/java/org/apache/commons/jelly/tags/xml/ElementTag.java
>     jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/java/org/apache/commons/jelly/tags/xml/XMLTagLibrary.java
>     jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/TestXMLTags.java
>     jakarta/commons/proper/jelly/trunk/src/java/org/apache/commons/jelly/XMLOutput.java
>     jakarta/commons/proper/jelly/trunk/src/java/org/apache/commons/jelly/impl/StaticTag.java
>     jakarta/commons/proper/jelly/trunk/src/java/org/apache/commons/jelly/impl/StaticTagScript.java
>     jakarta/commons/proper/jelly/trunk/src/java/org/apache/commons/jelly/impl/TagScript.java
>     jakarta/commons/proper/jelly/trunk/src/java/org/apache/commons/jelly/parser/XMLParser.java
>     jakarta/commons/proper/jelly/trunk/src/test/org/apache/commons/jelly/TestCoreTags.java
>     jakarta/commons/proper/jelly/trunk/src/test/org/apache/commons/jelly/core/TestFileTag.java
> 
> Modified: jakarta/commons/proper/jelly/trunk/jelly-tags/xml/project.xml
> URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/jelly/trunk/jelly-tags/xml/project.xml?rev=219726&r1=219725&r2=219726&view=diff
> ==============================================================================
> --- jakarta/commons/proper/jelly/trunk/jelly-tags/xml/project.xml (original)
> +++ jakarta/commons/proper/jelly/trunk/jelly-tags/xml/project.xml Tue Jul 19 10:34:00 2005
> @@ -20,7 +20,7 @@
>    <extend>${basedir}/../tag-project.xml</extend>
>    <id>commons-jelly-tags-xml</id>
>    <name>commons-jelly-tags-xml</name>
> -  <currentVersion>1.1</currentVersion>
> +  <currentVersion>1.2-dev</currentVersion>
>    <package>org.apache.commons.jelly.tags.xml</package>
>    <description>The Jelly XML Tag Library</description>
>    <shortDescription>Commons Jelly XML Tag Library</shortDescription>
> @@ -37,6 +37,11 @@
>      </version>
>    </versions>
>    <dependencies>
> +    <dependency>
> +      <id>commons-jelly</id>
> +      <version>SNAPSHOT</version>
> +    </dependency>
> +
>      <!-- run time / in testing-->
> 
>      <dependency>
> 
> Modified: jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/java/org/apache/commons/jelly/tags/xml/AttributeTag.java
> URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/java/org/apache/commons/jelly/tags/xml/AttributeTag.java?rev=219726&r1=219725&r2=219726&view=diff
> ==============================================================================
> --- jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/java/org/apache/commons/jelly/tags/xml/AttributeTag.java (original)
> +++ jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/java/org/apache/commons/jelly/tags/xml/AttributeTag.java Tue Jul 19 10:34:00 2005
> @@ -26,6 +26,8 @@
>    * @version $Revision$
>    */
>  public class AttributeTag extends TagSupport {
> +     /** The namespace URI. */
> +    private String namespace;
> 
>      /** the name of the attribute. */
>      private String name;
> @@ -38,10 +40,11 @@
>      //-------------------------------------------------------------------------
>      public void doTag(XMLOutput output) throws JellyTagException {
>          ElementTag tag = (ElementTag) findAncestorWithClass( ElementTag.class );
> -        if ( tag == null ) {
> -            throw new JellyTagException( "<attribute> tag must be enclosed inside an <element> tag" );
> +        if (tag == null) {
> +            throw new JellyTagException(
> +                    "<attribute> tag must be enclosed inside an <element> tag" );
>          }
> -        tag.setAttributeValue( getName(), getBodyText( false ) );
> +        tag.setAttributeValue(getName(), getBodyText(false), getURI());
>      }
> 
>      // Properties
> @@ -53,10 +56,25 @@
>      public String getName() {
>          return name;
>      }
> +
>      /**
> -     * Sets the name of the attribute
> +     * Sets the name of the attribute.
>       */
>      public void setName(String name) {
>          this.name = name;
> +    }
> +
> +    /**
> +     * @return the namespace URI of the element
> +     */
> +    public String getURI() {
> +        return namespace;
> +    }
> +
> +    /**
> +     * Sets the namespace URI of the element
> +     */
> +    public void setURI(String namespace) {
> +        this.namespace = namespace;
>      }
>  }
> 
> Modified: jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/java/org/apache/commons/jelly/tags/xml/ElementTag.java
> URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/java/org/apache/commons/jelly/tags/xml/ElementTag.java?rev=219726&r1=219725&r2=219726&view=diff
> ==============================================================================
> --- jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/java/org/apache/commons/jelly/tags/xml/ElementTag.java (original)
> +++ jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/java/org/apache/commons/jelly/tags/xml/ElementTag.java Tue Jul 19 10:34:00 2005
> @@ -15,6 +15,7 @@
>   */
>  package org.apache.commons.jelly.tags.xml;
> 
> +import org.apache.commons.jelly.JellyException;
>  import org.apache.commons.jelly.JellyTagException;
>  import org.apache.commons.jelly.TagSupport;
>  import org.apache.commons.jelly.XMLOutput;
> @@ -22,8 +23,6 @@
>  import org.xml.sax.SAXException;
>  import org.xml.sax.helpers.AttributesImpl;
> 
> -import java.io.IOException;
> -
>  /** A tag to produce an XML element which can contain other attributes
>    * or elements like the <code>&lt;xsl:element&gt;</code> tag.
>    *
> @@ -32,16 +31,16 @@
>    */
>  public class ElementTag extends TagSupport {
> 
> -    /** The namespace URI */
> +    /** The namespace URI. */
>      private String namespace;
> 
> -    /** The qualified name */
> +    /** The qualified name. */
>      private String name;
> 
> -    /** The XML Attributes */
> +    /** The XML Attributes. */
>      private AttributesImpl attributes = new AttributesImpl();
> 
> -    /** flag set if attributes are output */
> +    /** flag set if attributes are output. */
>      private boolean outputAttributes;
> 
>      public ElementTag() {
> @@ -52,11 +51,12 @@
>       *
>       * @param name of the attribute
>       * @param value of the attribute
> -     * @throws JellyException if the start element has already been output.
> +     * @param uri namespace of the attribute
> +     * @throws JellyTagException if the start element has already been output.
>       *   Attributes must be set on the outer element before any content
>       *   (child elements or text) is output
>       */
> -    public void setAttributeValue( String name, String value ) throws JellyTagException {
> +    public void setAttributeValue(String name, String value, String uri) throws JellyTagException {
>          if (outputAttributes) {
>              throw new JellyTagException(
>                  "Cannot set the value of attribute: "
> @@ -67,13 +67,22 @@
>          // ### we'll assume that all attributes are in no namespace!
>          // ### this is severely limiting!
>          // ### we should be namespace aware
> -        int index = attributes.getIndex("", name);
> +        // NAMESPACE FIXED:
> +        int idx = name.indexOf(':');
> +        final String localName = (idx >= 0)
> +            ? name.substring(idx + 1)
> +            : name;
> +        final String nsUri = (uri != null)
> +            ? uri
> +            : "";
> +
> +        int index = attributes.getIndex(nsUri, localName);
>          if (index >= 0) {
>              attributes.removeAttribute(index);
>          }
>          // treat null values as no attribute
>          if (value != null) {
> -            attributes.addAttribute("", name, name, "CDATA", value);
> +            attributes.addAttribute(nsUri, localName, name, "CDATA", value);
>          }
>      }
> 
> @@ -107,22 +116,21 @@
>                  super.endElement(uri, localName, qName);
>              }
> 
> -            public void characters(char ch[], int start, int length) throws SAXException {
> +            public void characters(char[] ch, int start, int length) throws SAXException {
>                  initialize();
>                  super.characters(ch, start, length);
>              }
> 
> -            public void ignorableWhitespace(char ch[], int start, int length)
> +            public void ignorableWhitespace(char[] ch, int start, int length)
>                  throws SAXException {
>                  initialize();
>                  super.ignorableWhitespace(ch, start, length);
>              }
> 
>              public void objectData(Object object)
> -                throws SAXException
> -            {
> +                throws SAXException {
>                  initialize();
> -                super.objectData( object );
> +                super.objectData(object);
>              }
> 
>              public void processingInstruction(String target, String data)
> @@ -133,7 +141,7 @@
> 
>              /**
>               * Ensure that the outer start element is generated
> -             * before any content is output
> +             * before any content is output.
>               */
>              protected void initialize() throws SAXException {
>                  if (!outputAttributes) {
> 
> Added: jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/java/org/apache/commons/jelly/tags/xml/ReplaceNamespaceTag.java
> URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/java/org/apache/commons/jelly/tags/xml/ReplaceNamespaceTag.java?rev=219726&view=auto
> ==============================================================================
> --- jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/java/org/apache/commons/jelly/tags/xml/ReplaceNamespaceTag.java (added)
> +++ jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/java/org/apache/commons/jelly/tags/xml/ReplaceNamespaceTag.java Tue Jul 19 10:34:00 2005
> @@ -0,0 +1,128 @@
> +/*
> + * Copyright 2002,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.commons.jelly.tags.xml;
> +
> +import org.apache.commons.jelly.JellyTagException;
> +import org.apache.commons.jelly.MissingAttributeException;
> +import org.apache.commons.jelly.TagSupport;
> +import org.apache.commons.jelly.XMLOutput;
> +
> +import org.xml.sax.Attributes;
> +import org.xml.sax.SAXException;
> +import org.xml.sax.helpers.AttributesImpl;
> +
> +/**
> + * Replace namespace is a filter to change the namespace of any
> + * elemement attribute passing through it.
> + *
> + * @author Diogo Quintela <dq...@gmail.com>
> + */
> +public class ReplaceNamespaceTag extends TagSupport {
> +    private String fromNamespace;
> +    private String toNamespace;
> +
> +    public ReplaceNamespaceTag() {
> +    }
> +
> +    //  Tag interface
> +    //-------------------------------------------------------------------------
> +    public void doTag(XMLOutput output) throws MissingAttributeException, JellyTagException {
> +        final String fromURI = (fromNamespace != null) ? fromNamespace : "";
> +        final String toURI = (toNamespace != null) ? toNamespace : "";
> +        XMLOutput newOutput = output;
> +
> +        if (!toURI.equals(fromURI)) {
> +            newOutput = new XMLOutput(output) {
> +                public void startElement(String uri, String localName, String qName, Attributes atts)
> +                    throws SAXException {
> +                    super.startElement(replaceURI(uri), localName, qName, replaceURI(atts));
> +                }
> +
> +                public void endElement(String uri, String localName, String qName)
> +                    throws SAXException {
> +                    super.endElement(replaceURI(uri), localName, qName);
> +                }
> +
> +                public void startPrefixMapping(String prefix, String uri)
> +                    throws SAXException {
> +                    super.startPrefixMapping(prefix, replaceURI(uri));
> +                }
> +
> +                private String replaceURI(String uri) {
> +                    String newUri = uri;
> +
> +                    if (fromURI.equals((uri != null) ? uri : "")) {
> +                        newUri = toURI;
> +                    }
> +
> +                    return newUri;
> +                }
> +
> +                private Attributes replaceURI(Attributes atts) {
> +                    AttributesImpl newAttsImpl = new AttributesImpl();
> +
> +                    for (int i = 0; i < atts.getLength(); i++) {
> +                        // Normally attributes don't have namespaces
> +                        // But may have (only if on form prefix:attr) ?
> +                        // So, we'll only replace if needed
> +                        String QName = atts.getQName(i);
> +                        String newUri = atts.getURI(i);
> +                        int idx = QName.indexOf(':');
> +
> +                        if (idx >= 0) {
> +                            newUri = replaceURI(newUri);
> +                        }
> +
> +                        newAttsImpl.addAttribute(newUri, atts.getLocalName(i), atts.getQName(i),
> +                            atts.getType(i), atts.getValue(i));
> +                    }
> +
> +                    return newAttsImpl;
> +                }
> +            };
> +        }
> +
> +        invokeBody(newOutput);
> +    }
> +
> +    /**
> +     * @return the source namespace URI to replace
> +     */
> +    public String getFromURI() {
> +        return fromNamespace;
> +    }
> +
> +    /**
> +     * Sets the source namespace URI to replace.
> +     */
> +    public void setFromURI(String namespace) {
> +        this.fromNamespace = namespace;
> +    }
> +
> +    /**
> +     * @return the destination namespace URI to replace
> +     */
> +    public String getToURI() {
> +        return toNamespace;
> +    }
> +
> +    /**
> +     * Sets the destination namespace URI to replace.
> +     */
> +    public void setToURI(String namespace) {
> +        this.toNamespace = namespace;
> +    }
> +}
> \ No newline at end of file
> 
> Modified: jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/java/org/apache/commons/jelly/tags/xml/XMLTagLibrary.java
> URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/java/org/apache/commons/jelly/tags/xml/XMLTagLibrary.java?rev=219726&r1=219725&r2=219726&view=diff
> ==============================================================================
> --- jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/java/org/apache/commons/jelly/tags/xml/XMLTagLibrary.java (original)
> +++ jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/java/org/apache/commons/jelly/tags/xml/XMLTagLibrary.java Tue Jul 19 10:34:00 2005
> @@ -53,6 +53,7 @@
>          registerTag("expr", ExprTag.class);
>          registerTag("element", ElementTag.class);
>          registerTag("attribute", AttributeTag.class);
> +        registerTag("replaceNamespace", ReplaceNamespaceTag.class);
>          registerTag("copy", CopyTag.class);
>          registerTag("copyOf", CopyOfTag.class);
>          registerTag("comment", CommentTag.class);
> 
> Modified: jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/TestXMLTags.java
> URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/TestXMLTags.java?rev=219726&r1=219725&r2=219726&view=diff
> ==============================================================================
> --- jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/TestXMLTags.java (original)
> +++ jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/TestXMLTags.java Tue Jul 19 10:34:00 2005
> @@ -19,15 +19,20 @@
>  import java.io.FileInputStream;
>  import java.io.InputStream;
>  import java.io.StringWriter;
> +import java.util.HashMap;
>  import java.util.Iterator;
>  import java.util.List;
> +import java.util.Map;
> +import java.util.Set;
> 
> +import junit.framework.Assert;
>  import junit.framework.Test;
>  import junit.framework.TestCase;
>  import junit.framework.TestSuite;
>  import junit.textui.TestRunner;
> 
>  import org.apache.commons.jelly.JellyContext;
> +import org.apache.commons.jelly.JellyException;
>  import org.apache.commons.jelly.Script;
>  import org.apache.commons.jelly.XMLOutput;
>  import org.apache.commons.jelly.parser.XMLParser;
> @@ -36,6 +41,8 @@
>  import org.dom4j.Document;
>  import org.dom4j.DocumentHelper;
>  import org.dom4j.Node;
> +import org.dom4j.io.SAXContentHandler;
> +import org.dom4j.io.XMLWriter;
> 
>  /** Tests the parser, the engine and the XML tags
>    *
> @@ -84,57 +91,158 @@
>              log.debug("Evaluated script as...");
>              log.debug(text);
>          }
> -        assertEquals("Produces the correct output", "It works!", text);
> +        assertEquals("Should produce the correct output", "It works!", text);
> +    }
> +
> +    public void testElementWithNameSpace() throws Exception {
> +        String text = evaluteScriptAsText(testBaseDir + "/elementWithNameSpace.jelly");
> +        assertEquals("Should produce the correct output",
> +                "<env:Envelope "+
> +                "xmlns:env=\"http://schemas.xmlsoap.org/soap/envelope/\" "+
> +                "env:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"+
> +                "</env:Envelope>", text);
> +    }
> +
> +    public void testElementWithNameSpaceError() throws Exception {
> +        try {
> +            evaluteScriptAsText(testBaseDir + "/elementWithNameSpaceError.jelly");
> +            Assert.fail("We should have bailed out with an JellyException");
> +        } catch (JellyException jex) {
> +            assertTrue(jex.getReason().startsWith("Cannot set same prefix to diferent URI in same node"));
> +        }
> +    }
> +
> +    public void testNamespaceReplace() throws Exception {
> +        // For this test when we not set "ns" var with expected namespace, it
> +        // is expected to repeat the same two times
> +        String text = evaluteScriptAsText(testBaseDir + "/namespaceReplace.jelly");
> +        String repeatingText = "<test-subnode attr=\"test\"><test-anotherSubNode></test-anotherSubNode><test-anotherSubNodeAgain xmlns:other=\"\" other:abc=\"testValue\"></test-anotherSubNodeAgain></test-subnode>";
> +        assertEquals("Should produce the correct output",
> +                "<test-node xmlns:test=\"http://apache/testNS\" test:abc=\"testValue\">"+
> +                repeatingText + repeatingText +
> +                "</test-node>", text);
> +
> +        Map ctxVars = new HashMap();
> +        ctxVars.put("ns", "http://java/ns");
> +
> +        text = evaluteScriptAsText(testBaseDir + "/namespaceReplace.jelly", ctxVars);
> +
> +        String firstTrunk =
> +        "<test-subnode xmlns=\"\" attr=\"test\">" +
> +        "<test-anotherSubNode>" +
> +        "</test-anotherSubNode>" +
> +        "<test-anotherSubNodeAgain xmlns:other=\"http://java/ns\" xmlns=\"http://java/ns\" other:abc=\"testValue\">" +
> +        "</test-anotherSubNodeAgain>" +
> +        "</test-subnode>";
> +
> +        String secondTrunk =
> +            "<test-subnode attr=\"test\">" +
> +            "<test-anotherSubNode>" +
> +            "</test-anotherSubNode>" +
> +            "<test-anotherSubNodeAgain xmlns:other=\"http://java/ns\" other:abc=\"testValue\">" +
> +            "</test-anotherSubNodeAgain>" +
> +            "</test-subnode>";
> +
> +        System.out.println("TestXMLTags.testNamespaceReplace() text="+text);
> +        assertEquals("Should produce the correct output",
> +                "<test-node xmlns:test=\"http://apache/testNS\" xmlns=\"http://java/ns\" test:abc=\"testValue\">"+
> +                firstTrunk + secondTrunk +
> +                "</test-node>", text);
> +    }
> +
> +    public void testAttributeNameSpaceDuplicatedNS() throws Exception {
> +        try {
> +            evaluteScriptAsText(testBaseDir + "/attributeNameSpaceDuplicatedNS.jelly");
> +            Assert.fail("We should have bailed out with an JellyException");
> +        } catch (JellyException jex) {
> +            assertTrue(jex.getReason().startsWith("Cannot set same prefix to diferent URI in same node"));
> +        }
> +    }
> +
> +    public void testAttributeNameSpace() throws Exception {
> +        String text = evaluteScriptAsText(testBaseDir + "/attributeNameSpace.jelly");
> +        System.out.println(text);
> +        assertEquals("Should produce the correct output",
> +                "<top-node xmlns=\"abc\">"+
> +                "<test-node xmlns:test=\"http://apache/testNS\" xmlns=\"http://apache/trueNS\" test:abc=\"testValue\" abc2=\"testValue\" abc3=\"testValue\">"+
> +                "<test:test-subnode><node-at-same-ns-as-top xmlns=\"abc\">"+
> +                "</node-at-same-ns-as-top>"+
> +                "</test:test-subnode>"+
> +                "</test-node>"+
> +                "</top-node>", text);
> +    }
> +
> +    public void testAttributeNameSpaceDefaultNS() throws Exception {
> +        String text = evaluteScriptAsText(testBaseDir + "/attributeNameSpaceDefaultNS.jelly");
> +        System.out.println(text);
> +        assertEquals("Should produce the correct output",
> +                "<top-node>"+
> +                "<test-node xmlns:test=\"http://apache/testNS\" xmlns=\"http://apache/trueNS\" test:abc=\"testValue\" abc2=\"testValue\" abc3=\"testValue\">"+
> +                "<test:test-subnode><node-at-same-ns-as-top xmlns=\"\">"+
> +                "</node-at-same-ns-as-top>"+
> +                "</test:test-subnode>"+
> +                "</test-node>"+
> +                "</top-node>", text);
> +    }
> +
> +    public void testAttributeNameSpaceWithInnerElements() throws Exception {
> +        String text = evaluteScriptAsText(testBaseDir + "/attributeNameSpaceWithInnerElements.jelly");
> +        assertEquals("Should produce the correct output",
> +                "<test-node xmlns:test=\"http://apache/testNS\" test:abc=\"testValue\" abc2=\"testValue\" abc3=\"testValue\">"+
> +                "<test-sub-node xmlns:test2=\"http://apache/testNS\" xmlns:test3=\"http://apache/anotherNS\" test:abc=\"testValue\" test2:abc2=\"testValue\" test3:abc3=\"testValue\">"+
> +                "</test-sub-node>"+
> +                "</test-node>"
> +                , text);
>      }
> 
>      public void testTransform() throws Exception {
>          String text = evaluteScriptAsText(testBaseDir + "/transformExample.jelly");
> -        assertEquals("Produces the correct output", "It works!", text);
> +        assertEquals("Should produce the correct output", "It works!", text);
>      }
> 
>      public void testTransformAllInLine() throws Exception {
>          String text = evaluteScriptAsText(testBaseDir + "/transformExampleAllInLine.jelly");
> -        assertEquals("Produces the correct output", "It works!", text);
> +        assertEquals("Should produce the correct output", "It works!", text);
>      }
> 
>      public void testTransformParams() throws Exception {
>          String text = evaluteScriptAsText(testBaseDir + "/transformParamExample.jelly");
> -        assertEquals("Produces the correct output", "It works!", text);
> +        assertEquals("Should produce the correct output", "It works!", text);
>      }
> 
>      public void testTransformParamsInLine() throws Exception {
> 
>          String text = evaluteScriptAsText(testBaseDir + "/transformParamExample2.jelly");
> -        assertEquals("Produces the correct output", "It works!", text);
> +        assertEquals("Should produce the correct output", "It works!", text);
>      }
> 
>      public void testTransformSAXOutput() throws Exception {
>          String text = evaluteScriptAsText(testBaseDir + "/transformExampleSAXOutput.jelly");
> -        assertEquals("Produces the correct output", "It works!", text);
> +        assertEquals("Should produce the correct output", "It works!", text);
>      }
> 
>      public void testTransformSAXOutputNestedTransforms() throws Exception {
>          String text = evaluteScriptAsText(testBaseDir +
>              "/transformExampleSAXOutputNestedTransforms.jelly");
> -        assertEquals("Produces the correct output", "It works!", text);
> +        assertEquals("Should produce the correct output", "It works!", text);
>      }
> 
>      public void testTransformSchematron() throws Exception {
>          String text = evaluteScriptAsText(testBaseDir +
>              "/schematron/transformSchematronExample.jelly");
> -        assertEquals("Produces the correct output", "Report count=1:assert count=2", text);
> +        assertEquals("Should produce the correct output", "Report count=1:assert count=2", text);
>      }
> 
>      public void testTransformXmlVar() throws Exception {
>          String text = evaluteScriptAsText(testBaseDir +
>              "/transformExampleXmlVar.jelly");
> -        assertEquals("Produces the correct output", "It works!", text);
> +        assertEquals("Should produce the correct output", "It works!", text);
>      }
> 
>      public void testDoctype() throws Exception {
>          String text = evaluteScriptAsText(testBaseDir +
>              "/testDoctype.jelly");
> -        assertEquals("Produces the correct output", "<!DOCTYPE foo PUBLIC \"publicID\" \"foo.dtd\">\n<foo></foo>", text);
> +        assertEquals("Should produce the correct output", "<!DOCTYPE foo PUBLIC \"publicID\" \"foo.dtd\">\n<foo></foo>", text);
>      }
> 
>      public void runUnitTest(String name) throws Exception {
> @@ -172,7 +280,23 @@
>       * returns the whitespace trimmed output as text
>       */
>      protected String evaluteScriptAsText(String fileName) throws Exception {
> +        return evaluteScriptAsText(fileName, null);
> +    }
> +
> +    /**
> +     * Evaluates the script by the given file name and
> +     * returns the whitespace trimmed output as text
> +     */
> +    protected String evaluteScriptAsText(String fileName, Map ctxVars) throws Exception {
>          JellyContext context = new JellyContext();
> +        if (ctxVars != null) {
> +            Set keys = ctxVars.keySet();
> +            for (Iterator iterator = keys.iterator(); iterator.hasNext();) {
> +                String key = (String) iterator.next();
> +                Object value = ctxVars.get(key);
> +                context.setVariable(key, value);
> +            }
> +        }
> 
>          // allow scripts to refer to any resource inside this project
>          // using an absolute URI like /src/test/org/apache/foo.xml
> @@ -190,4 +314,49 @@
>          }
>          return text;
>      }
> +
> +    protected String evaluteScriptAsTextUsingSaxContentHandler(String fileName, Map ctxVars) throws Exception {
> +        org.dom4j.io.OutputFormat outputFormat = new org.dom4j.io.OutputFormat();
> +        outputFormat.setSuppressDeclaration(true);
> +        outputFormat.setNewlines(false);
> +        outputFormat.setIndent(false);
> +        outputFormat.setExpandEmptyElements(true);
> +        //outputFormat.setIndentSize(4);
> +
> +        StringWriter buffer = new StringWriter();
> +        XMLWriter xmlWriter = new XMLWriter(buffer, outputFormat);
> +        // xmlWriter.setEscapeText(false);
> +
> +        SAXContentHandler saxHandler = new SAXContentHandler();
> +        XMLOutput output = new XMLOutput(saxHandler);
> +
> +        // now run a script using a URL
> +        JellyContext context = new JellyContext();
> +        if (ctxVars != null) {
> +            Set keys = ctxVars.keySet();
> +            for (Iterator iterator = keys.iterator(); iterator.hasNext();) {
> +                String key = (String) iterator.next();
> +                Object value = ctxVars.get(key);
> +                context.setVariable(key, value);
> +            }
> +        }
> +
> +        // allow scripts to refer to any resource inside this project
> +        // using an absolute URI like /src/test/org/apache/foo.xml
> +        context.setRootURL(new File(".").toURL());
> +
> +        output.startDocument();
> +        context.runScript(new File(fileName), output);
> +        output.endDocument();
> +        xmlWriter.write(saxHandler.getDocument());
> +        xmlWriter.flush();
> +
> +        String text = buffer.toString().trim();
> +        if (log.isDebugEnabled()) {
> +            log.debug("Evaluated script as...");
> +            log.debug(text);
> +        }
> +        return text;
> +    }
> +
>  }
> 
> Added: jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/attributeNameSpace.jelly
> URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/attributeNameSpace.jelly?rev=219726&view=auto
> ==============================================================================
> --- jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/attributeNameSpace.jelly (added)
> +++ jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/attributeNameSpace.jelly Tue Jul 19 10:34:00 2005
> @@ -0,0 +1,15 @@
> +<?xml version="1.0" encoding="UTF-8"?>
> +<j:jelly xmlns:j="jelly:core" xmlns:x="jelly:xml" xmlns="abc">
> +    <top-node>
> +        <x:element URI="http://apache/trueNS" name="test-node">
> +            <x:attribute URI="http://apache/testNS" name="test:abc" trim="true">testValue</x:attribute>
> +            <!-- attributes without ':' should not have namespace -->
> +            <x:attribute URI="http://apache/testNS" name="abc2" trim="true">testValue</x:attribute>
> +            <x:attribute name="abc3" trim="true">testValue</x:attribute>
> +            <x:element URI="http://apache/testNS" name="test:test-subnode">
> +                <node-at-same-ns-as-top/>
> +            </x:element>
> +        </x:element>
> +    </top-node>
> +</j:jelly>
> +
> 
> Added: jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/attributeNameSpaceDefaultNS.jelly
> URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/attributeNameSpaceDefaultNS.jelly?rev=219726&view=auto
> ==============================================================================
> --- jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/attributeNameSpaceDefaultNS.jelly (added)
> +++ jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/attributeNameSpaceDefaultNS.jelly Tue Jul 19 10:34:00 2005
> @@ -0,0 +1,15 @@
> +<?xml version="1.0" encoding="UTF-8"?>
> +<j:jelly xmlns:j="jelly:core" xmlns:x="jelly:xml">
> +    <top-node>
> +        <x:element URI="http://apache/trueNS" name="test-node">
> +            <x:attribute URI="http://apache/testNS" name="test:abc" trim="true">testValue</x:attribute>
> +            <!-- attributes without ':' should not have namespace -->
> +            <x:attribute URI="http://apache/testNS" name="abc2" trim="true">testValue</x:attribute>
> +            <x:attribute name="abc3" trim="true">testValue</x:attribute>
> +            <x:element URI="http://apache/testNS" name="test:test-subnode">
> +                <node-at-same-ns-as-top/>
> +            </x:element>
> +        </x:element>
> +    </top-node>
> +</j:jelly>
> +
> 
> Added: jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/attributeNameSpaceDuplicatedNS.jelly
> URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/attributeNameSpaceDuplicatedNS.jelly?rev=219726&view=auto
> ==============================================================================
> --- jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/attributeNameSpaceDuplicatedNS.jelly (added)
> +++ jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/attributeNameSpaceDuplicatedNS.jelly Tue Jul 19 10:34:00 2005
> @@ -0,0 +1,8 @@
> +<?xml version="1.0" encoding="UTF-8"?>
> +<j:jelly xmlns:j="jelly:core" xmlns:x="jelly:xml">
> +    <x:element name="test-node">
> +        <x:attribute URI="http://apache/testNS" name="test:abc" trim="true">testValue</x:attribute>
> +        <x:attribute URI="http://apache/anotherNS" name="test:abc2" trim="true">testValue</x:attribute>
> +    </x:element>
> +</j:jelly>
> +
> 
> Added: jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/attributeNameSpaceWithInnerElements.jelly
> URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/attributeNameSpaceWithInnerElements.jelly?rev=219726&view=auto
> ==============================================================================
> --- jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/attributeNameSpaceWithInnerElements.jelly (added)
> +++ jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/attributeNameSpaceWithInnerElements.jelly Tue Jul 19 10:34:00 2005
> @@ -0,0 +1,16 @@
> +<?xml version="1.0" encoding="UTF-8"?>
> +<j:jelly xmlns:j="jelly:core" xmlns:x="jelly:xml">
> +    <x:element name="test-node">
> +        <x:attribute URI="http://apache/testNS" name="test:abc" trim="true">testValue</x:attribute>
> +        <!-- attributes without ':' should not have namespace -->
> +        <x:attribute URI="http://apache/testNS" name="abc2" trim="true">testValue</x:attribute>
> +        <x:attribute name="abc3" trim="true">testValue</x:attribute>
> +
> +        <x:element name="test-sub-node">
> +            <x:attribute URI="http://apache/testNS" name="test:abc" trim="true">testValue</x:attribute>
> +            <x:attribute URI="http://apache/testNS" name="test2:abc2" trim="true">testValue</x:attribute>
> +            <x:attribute URI="http://apache/anotherNS" name="test3:abc3" trim="true">testValue</x:attribute>
> +        </x:element>
> +    </x:element>
> +</j:jelly>
> +
> 
> Added: jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/elementWithNameSpace.jelly
> URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/elementWithNameSpace.jelly?rev=219726&view=auto
> ==============================================================================
> --- jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/elementWithNameSpace.jelly (added)
> +++ jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/elementWithNameSpace.jelly Tue Jul 19 10:34:00 2005
> @@ -0,0 +1,10 @@
> +<?xml version="1.0" encoding="UTF-8"?>
> +<j:jelly xmlns:j="jelly:core" xmlns:x="jelly:xml">
> +    <x:element URI="http://schemas.xmlsoap.org/soap/envelope/" name="env:Envelope">
> +        <x:attribute URI="http://schemas.xmlsoap.org/soap/envelope/"
> +                     name="env:encodingStyle" trim="true">
> +            http://schemas.xmlsoap.org/soap/encoding/
> +        </x:attribute>
> +    </x:element>
> +</j:jelly>
> +
> 
> Added: jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/elementWithNameSpaceError.jelly
> URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/elementWithNameSpaceError.jelly?rev=219726&view=auto
> ==============================================================================
> --- jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/elementWithNameSpaceError.jelly (added)
> +++ jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/elementWithNameSpaceError.jelly Tue Jul 19 10:34:00 2005
> @@ -0,0 +1,9 @@
> +<?xml version="1.0" encoding="UTF-8"?>
> +<j:jelly xmlns:j="jelly:core" xmlns:x="jelly:xml">
> +    <x:element URI="http://schemas.xmlsoap.org/soap/envelope/" name="env:Envelope">
> +        <x:attribute name="env:encodingStyle" trim="true">
> +            http://schemas.xmlsoap.org/soap/encoding/
> +        </x:attribute>
> +    </x:element>
> +</j:jelly>
> +
> 
> Added: jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/namespaceReplace.jelly
> URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/namespaceReplace.jelly?rev=219726&view=auto
> ==============================================================================
> --- jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/namespaceReplace.jelly (added)
> +++ jakarta/commons/proper/jelly/trunk/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/namespaceReplace.jelly Tue Jul 19 10:34:00 2005
> @@ -0,0 +1,23 @@
> +<?xml version="1.0" encoding="UTF-8"?>
> +<j:jelly xmlns:j="jelly:core" xmlns:x="jelly:xml">
> +    <x:element URI="${ns}" name="test-node">
> +        <x:attribute URI="http://apache/testNS" name="test:abc" trim="true">testValue</x:attribute>
> +
> +        <test-subnode attr="test">
> +            <test-anotherSubNode />
> +            <x:element URI="${ns}" name="test-anotherSubNodeAgain">
> +                <x:attribute URI="${ns}" name="other:abc" trim="true">testValue</x:attribute>
> +            </x:element>
> +        </test-subnode>
> +
> +        <x:replaceNamespace toURI="${ns}">
> +            <test-subnode attr="test">
> +                <test-anotherSubNode />
> +                <x:element URI="${ns}" name="test-anotherSubNodeAgain">
> +                    <x:attribute URI="${ns}" name="other:abc" trim="true">testValue</x:attribute>
> +                </x:element>
> +            </test-subnode>
> +        </x:replaceNamespace>
> +    </x:element>
> +</j:jelly>
> +
> 
> Modified: jakarta/commons/proper/jelly/trunk/src/java/org/apache/commons/jelly/XMLOutput.java
> URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/jelly/trunk/src/java/org/apache/commons/jelly/XMLOutput.java?rev=219726&r1=219725&r2=219726&view=diff
> ==============================================================================
> --- jakarta/commons/proper/jelly/trunk/src/java/org/apache/commons/jelly/XMLOutput.java (original)
> +++ jakarta/commons/proper/jelly/trunk/src/java/org/apache/commons/jelly/XMLOutput.java Tue Jul 19 10:34:00 2005
> @@ -20,6 +20,11 @@
>  import java.io.OutputStream;
>  import java.io.UnsupportedEncodingException;
>  import java.io.Writer;
> +import java.util.ArrayList;
> +import java.util.HashMap;
> +import java.util.Iterator;
> +import java.util.List;
> +import java.util.Map;
> 
>  import org.apache.commons.logging.Log;
>  import org.apache.commons.logging.LogFactory;
> @@ -44,29 +49,35 @@
>  public class XMLOutput implements ContentHandler, LexicalHandler {
> 
>      protected static final String[] LEXICAL_HANDLER_NAMES =
> -        {
> -            "http://xml.org/sax/properties/lexical-handler",
> -            "http://xml.org/sax/handlers/LexicalHandler" };
> +     {
> +        "http://xml.org/sax/properties/lexical-handler",
> +        "http://xml.org/sax/handlers/LexicalHandler" };
> 
> -    /** empty attributes */
> +    /** Empty attributes. */
>      private static final Attributes EMPTY_ATTRIBUTES = new AttributesImpl();
> 
>      /** The Log to which logging calls will be made. */
>      private static final Log log = LogFactory.getLog(XMLOutput.class);
> 
> -    /** the default for escaping of text */
> +    /** the default for escaping of text. */
>      private static final boolean DEFAULT_ESCAPE_TEXT = false;
> 
> -    /** The SAX ContentHandler that output goes to */
> +    /** The SAX ContentHandler that output goes to. */
>      private ContentHandler contentHandler;
> 
> -    /** The SAX LexicalHandler that output goes to */
> +    /** The SAX LexicalHandler that output goes to. */
>      private LexicalHandler lexicalHandler;
> 
> +    /** Stack of kown namespaces. */
> +    private NamespaceStack namespaceStack = new NamespaceStack();
> 
>      public XMLOutput() {
>      }
> 
> +    /** The XML-output will relay the SAX events to the indicated
> +     * contentHandler.
> +     * @param contentHandler
> +     */
>      public XMLOutput(ContentHandler contentHandler) {
>          this.contentHandler = contentHandler;
>          // often classes will implement LexicalHandler as well
> @@ -75,6 +86,11 @@
>          }
>      }
> 
> +    /** The XML-output will relay the SAX events to the indicated
> +     * content-handler lexical-handler.
> +     * @param contentHandler
> +     * @param lexicalHandler
> +     */
>      public XMLOutput(
>          ContentHandler contentHandler,
>          LexicalHandler lexicalHandler) {
> @@ -92,16 +108,25 @@
>      }
> 
>      /**
> -     * Provides a useful hook that implementations can use to close the
> -     * underlying OutputStream or Writer
> +     * Provides a useful hook that implementations
> +     * can use to close the
> +     * underlying OutputStream or Writer.
> +     *
> +     * @throws IOException
>       */
>      public void close() throws IOException {
>      }
> 
> +    /** Flushes the underlying stream if {@link XMLWriter}
> +     * or {@link XMLOutput}.
> +     *
> +     * @throws IOException
> +     */
>      public void flush() throws IOException {
> -        if( contentHandler instanceof XMLWriter )
> -        {
> +        if (contentHandler instanceof XMLWriter) {
>              ((XMLWriter)contentHandler).flush();
> +        } else if (contentHandler instanceof XMLOutput) {
> +            ((XMLOutput)contentHandler).flush();
>          }
>      }
> 
> @@ -109,7 +134,7 @@
>      //-------------------------------------------------------------------------
> 
>      /**
> -     * Creates an XMLOutput from an existing SAX XMLReader
> +     * Creates an XMLOutput from an existing SAX XMLReader.
>       */
>      public static XMLOutput createXMLOutput(XMLReader xmlReader) {
>          XMLOutput output = new XMLOutput(xmlReader.getContentHandler());
> @@ -122,10 +147,11 @@
>                      output.setLexicalHandler((LexicalHandler) value);
>                      break;
>                  }
> -            }
> -            catch (Exception e) {
> +            } catch (Exception e) {
>                  // ignore any unsupported-operation exceptions
> -                if (log.isDebugEnabled()) log.debug("error setting lexical handler properties", e);
> +                if (log.isDebugEnabled()) {
> +                    log.debug("error setting lexical handler properties", e);
> +                }
>              }
>          }
>          return output;
> @@ -145,10 +171,9 @@
>       *
>       * @param writer is the writer to output to
>       * @param escapeText is whether or not text output will be escaped. This must be true
> -     * if the underlying output is XML or could be false if the underlying output is textual.
> +     *   if the underlying output is XML or could be false if the underlying output is textual.
>       */
> -    public static XMLOutput createXMLOutput(Writer writer, boolean escapeText)
> -    {
> +    public static XMLOutput createXMLOutput(Writer writer, boolean escapeText) {
>          XMLWriter xmlWriter = new XMLWriter(writer);
>          xmlWriter.setEscapeText(escapeText);
>          return createXMLOutput(xmlWriter);
> @@ -169,8 +194,11 @@
>       * @param out is the output stream to write
>       * @param escapeText is whether or not text output will be escaped. This must be true
>       * if the underlying output is XML or could be false if the underlying output is textual.
> +     * @throws UnsupportedEncodingException if the underlying write could not
> +     *   be created.
>       */
> -    public static XMLOutput createXMLOutput(OutputStream out, boolean escapeText) throws UnsupportedEncodingException {
> +    public static XMLOutput createXMLOutput(OutputStream out, boolean escapeText)
> +            throws UnsupportedEncodingException {
>          XMLWriter xmlWriter = new XMLWriter(out);
>          xmlWriter.setEscapeText(escapeText);
>          return createXMLOutput(xmlWriter);
> @@ -193,7 +221,7 @@
>      /**
>       * Outputs the given String as a piece of valid text in the
>       * XML event stream.
> -     * Any special XML characters should be properly escaped.
> +     * Any special XML characters should come out properly escaped.
>       */
>      public void write(String text) throws SAXException {
>          char[] ch = text.toCharArray();
> @@ -212,7 +240,7 @@
>      }
> 
>      /**
> -     * Outputs a comment to the XML stream
> +     * Outputs a comment to the XML stream.
>       */
>      public void writeComment(String text) throws SAXException {
>          char[] ch = text.toCharArray();
> @@ -220,21 +248,24 @@
>      }
> 
>      /**
> -     * Helper method for outputting a start element event for an element in no namespace
> +     * Helper method for outputting a start element event
> +     * for an element in no namespace.
>       */
>      public void startElement(String localName) throws SAXException {
>          startElement("", localName, localName, EMPTY_ATTRIBUTES);
>      }
> 
>      /**
> -     * Helper method for outputting a start element event for an element in no namespace
> +     * Helper method for outputting a start element event
> +     * for an element in no namespace.
>       */
>      public void startElement(String localName, Attributes attributes) throws SAXException {
>          startElement("", localName, localName, attributes);
>      }
> 
>      /**
> -     * Helper method for outputting an end element event for an element in no namespace
> +     * Helper method for outputting an end element event
> +     * for an element in no namespace.
>       */
>      public void endElement(String localName) throws SAXException {
>          endElement("", localName, localName);
> @@ -344,7 +375,9 @@
>       * @see #startElement
>       */
>      public void startPrefixMapping(String prefix, String uri) throws SAXException {
> -        contentHandler.startPrefixMapping(prefix, uri);
> +        namespaceStack.pushNamespace(prefix, uri);
> +        // contentHandler.startPrefixMapping(prefix, uri) will be called if needed
> +        // in pushNamespace
>      }
> 
>      /**
> @@ -364,7 +397,9 @@
>       * @see #endElement
>       */
>      public void endPrefixMapping(String prefix) throws SAXException {
> -        contentHandler.endPrefixMapping(prefix);
> +        namespaceStack.popNamespace(prefix);
> +        // End prefix mapping was already called after endElement
> +        // contentHandler.endPrefixMapping(prefix);
>      }
> 
>      /**
> @@ -435,7 +470,28 @@
>          String qName,
>          Attributes atts)
>          throws SAXException {
> +
> +        int idx = qName.indexOf(':');
> +        String attNsPrefix = "";
> +        if (idx >= 0) {
> +            attNsPrefix = qName.substring(0, idx);
> +        }
> +        namespaceStack.pushNamespace(attNsPrefix, uri);
> +        for (int i = 0; i < atts.getLength(); i++) {
> +            String attQName = atts.getQName(i);
> +            // An attribute only has an namespace if has a prefix
> +            // If not, stays in namespace of containing node
> +            idx = attQName.indexOf(':');
> +            if (idx >= 0) {
> +                attNsPrefix = attQName.substring(0, idx);
> +                String attUri = atts.getURI(i);
> +                namespaceStack.pushNamespace(attNsPrefix, attUri);
> +            }
> +        }
> +
>          contentHandler.startElement(uri, localName, qName, atts);
> +        // Inform namespaceStack of a new depth
> +        namespaceStack.increaseLevel();
>      }
> 
>      /**
> @@ -462,6 +518,9 @@
>      public void endElement(String uri, String localName, String qName)
>          throws SAXException {
>          contentHandler.endElement(uri, localName, qName);
> +        // Inform namespaceStack to return to previous depth
> +        namespaceStack.decreaseLevel();
> +        namespaceStack.popNamespaces();
>      }
> 
>      /**
> @@ -507,7 +566,7 @@
>       * @see #ignorableWhitespace
>       * @see org.xml.sax.Locator
>       */
> -    public void characters(char ch[], int start, int length) throws SAXException {
> +    public void characters(char[] ch, int start, int length) throws SAXException {
>          contentHandler.characters(ch, start, length);
>      }
> 
> @@ -535,7 +594,7 @@
>       *            wrapping another exception.
>       * @see #characters
>       */
> -    public void ignorableWhitespace(char ch[], int start, int length)
> +    public void ignorableWhitespace(char[] ch, int start, int length)
>          throws SAXException {
>          contentHandler.ignorableWhitespace(ch, start, length);
>      }
> @@ -855,4 +914,127 @@
>          return answer;
>      }
> 
> +    private final class NamespaceStack {
> +        /** A list of maps: Each map contains prefix->uri mapping */
> +        private List nsStack;
> +
> +        private NamespaceStack() {
> +            this.nsStack = new ArrayList();
> +            this.nsStack.add(new HashMap());
> +        }
> +
> +        private boolean isRootNodeDefaultNs(String prefix, String uri) {
> +            return ("".equals(prefix) && "".equals(uri) && nsStack.size() == 1);
> +        }
> +
> +        public void pushNamespace(String prefix, String uri) throws SAXException {
> +            Map prefixUriMap;
> +
> +            if (prefix == null) {
> +                prefix = "";
> +            }
> +            if (uri == null) {
> +                uri = "";
> +            }
> +
> +            if ("xml".equals(prefix)) {
> +                // We should ignore setting 'xml' prefix
> +                // As declared in java of ContentHandler#startPrefixMapping
> +                return;
> +            }
> +
> +
> +            // Lets find out if we already declared this same prefix,
> +            // if not declare in current depth map (the first of list)
> +            // and call contentHandler.startPrefixMapping(prefix, uri);
> +            boolean isNew = true;
> +            for (Iterator iter = nsStack.iterator(); iter.hasNext();) {
> +                prefixUriMap = (Map) iter.next();
> +                if (prefixUriMap.containsKey(prefix)) {
> +                    if (uri.equals(prefixUriMap.get(prefix))) {
> +                        // Its an active namespace already
> +                        // System.out.println(">>>"+XMLOutput.this.hashCode()+">NamespaceStack.pushNamespace() IS NOT NEW prefix="+prefix+",uri="+uri);
> +                        isNew = false;
> +                    }
> +                    // We found it in stack
> +                    // If it was exacly the same, we won't bother
> +                    break;
> +                }
> +            }
> +
> +            if (isNew) {
> +                // not declared sometime before
> +                prefixUriMap = (Map) nsStack.get(0); // Current depth map
> +                // Sanity check: Don't let two prefixes for diferent uris in
> +                // same depth
> +                if (prefixUriMap.containsKey(prefix)) {
> +                    if (!uri.equals(prefixUriMap.get(prefix))) {
> +                        throw new SAXException("Cannot set same prefix to diferent URI in same node: trying to add prefix \""
> +                                + prefix + "\" for uri \""+uri+"\" whereas the declared ones are " + prefixUriMap);
> +                    }
> +                } else {
> +                    prefixUriMap.put(prefix, uri);
> +
> +                    // To avoid setting xmlns="" for top node (not very nice :D)
> +                    // We need to especificaly check this condition
> +                    if (!isRootNodeDefaultNs(prefix, uri)) {
> +//                        System.out.println(">>>"+XMLOutput.this.hashCode()+">NamespaceStack.pushNamespace() prefix="+prefix+",uri="+uri);
> +                        contentHandler.startPrefixMapping(prefix, uri);
> +                    }
> +                }
> +            }
> +        }
> +
> +        public void popNamespaces() throws SAXException {
> +            Map prefixUriMap = (Map)nsStack.get(0);
> +            for (Iterator iter = prefixUriMap.keySet().iterator();iter.hasNext();) {
> +                String prefix = (String)iter.next();
> +                String uri = (String) prefixUriMap.get(prefix);
> +                iter.remove();
> +
> +                // If we havent called startPrefixMapping for root node if we wanted to avoid xmlns=""
> +                // We aren't going to call endPrefixMapping neither
> +                if (!isRootNodeDefaultNs(prefix, uri)) {
> +//                    System.out.println(">>>"+XMLOutput.this.hashCode()+">NamespaceStack.popNamespaces() prefix="+prefix);
> +                    contentHandler.endPrefixMapping(prefix);
> +                }
> +            }
> +        }
> +
> +        public void popNamespace(String prefix) throws SAXException {
> +            Map prefixUriMap = (Map)nsStack.get(0);
> +
> +            if (prefix == null) {
> +                prefix = "";
> +            }
> +
> +            if ("xml".equals(prefix)) {
> +                // We should ignore setting 'xml' prefix
> +                // As declared in java of ContentHandler#startPrefixMapping
> +                return;
> +            }
> +
> +            if (prefixUriMap.containsKey(prefix)) {
> +                String uri = (String) prefixUriMap.get(prefix);
> +                prefixUriMap.remove(prefix);
> +                // If we havent called startPrefixMapping for root node if we wanted to avoid xmlns=""
> +                // We aren't going to call endPrefixMapping neither
> +                if (!isRootNodeDefaultNs(prefix, uri)) {
> +//                    System.out.println(">>>"+XMLOutput.this.hashCode()+">NamespaceStack.popNamespace() prefix="+prefix);
> +                    contentHandler.endPrefixMapping(prefix);
> +                }
> +            }/* else {
> +                improper nesting ? or already removed in popNamespaces
> +            }
> +            */
> +        }
> +
> +        public void decreaseLevel() {
> +            nsStack.remove(0);
> +        }
> +
> +        public void increaseLevel() {
> +            nsStack.add(0, new HashMap());
> +        }
> +    }
>  }
> 
> Modified: jakarta/commons/proper/jelly/trunk/src/java/org/apache/commons/jelly/impl/StaticTag.java
> URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/jelly/trunk/src/java/org/apache/commons/jelly/impl/StaticTag.java?rev=219726&r1=219725&r2=219726&view=diff
> ==============================================================================
> --- jakarta/commons/proper/jelly/trunk/src/java/org/apache/commons/jelly/impl/StaticTag.java (original)
> +++ jakarta/commons/proper/jelly/trunk/src/java/org/apache/commons/jelly/impl/StaticTag.java Tue Jul 19 10:34:00 2005
> @@ -69,6 +69,15 @@
>          }
>      }
> 
> +    public void setAttribute(String name, String prefix, String nsURI, Object value) {
> +        if(value==null)
> +            return;
> +        if(prefix!=null && prefix.length()>0)
> +            attributes.addAttribute(nsURI,name,prefix+":"+name,"CDATA",value.toString());
> +        else
> +            attributes.addAttribute("",name,name,"CDATA",value.toString());
> +    }
> +
>      // DynaTag interface
>      //-------------------------------------------------------------------------
>      public void setAttribute(String name, Object value) throws JellyTagException {
> 
> Modified: jakarta/commons/proper/jelly/trunk/src/java/org/apache/commons/jelly/impl/StaticTagScript.java
> URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/jelly/trunk/src/java/org/apache/commons/jelly/impl/StaticTagScript.java?rev=219726&r1=219725&r2=219726&view=diff
> ==============================================================================
> --- jakarta/commons/proper/jelly/trunk/src/java/org/apache/commons/jelly/impl/StaticTagScript.java (original)
> +++ jakarta/commons/proper/jelly/trunk/src/java/org/apache/commons/jelly/impl/StaticTagScript.java Tue Jul 19 10:34:00 2005
> @@ -86,7 +86,10 @@
>              for (Iterator iter = attributes.entrySet().iterator(); iter.hasNext();) {
>                  Map.Entry entry = (Map.Entry) iter.next();
>                  String name = (String) entry.getKey();
> -                Expression expression = (Expression) entry.getValue();
> +                if(name.indexOf(':')!=-1)
> +                    name = name.substring(name.indexOf(':')+1);
> +                ExpressionAttribute expat = (ExpressionAttribute) entry.getValue();
> +                Expression expression = expat.exp;
> 
>                  Object value = null;
> 
> @@ -96,7 +99,10 @@
>                      value = expression.evaluate(context);
>                  }
> 
> -                dynaTag.setAttribute(name, value);
> +                if(expat.prefix!=null || expat.prefix.length()>0 && tag instanceof StaticTag)
> +                    ((StaticTag) dynaTag).setAttribute(name,expat.prefix, expat.nsURI,value);
> +                else
> +                    dynaTag.setAttribute(name, value);
>              }
> 
>              tag.doTag(output);
> 
> Modified: jakarta/commons/proper/jelly/trunk/src/java/org/apache/commons/jelly/impl/TagScript.java
> URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/jelly/trunk/src/java/org/apache/commons/jelly/impl/TagScript.java?rev=219726&r1=219725&r2=219726&view=diff
> ==============================================================================
> --- jakarta/commons/proper/jelly/trunk/src/java/org/apache/commons/jelly/impl/TagScript.java (original)
> +++ jakarta/commons/proper/jelly/trunk/src/java/org/apache/commons/jelly/impl/TagScript.java Tue Jul 19 10:34:00 2005
> @@ -170,7 +170,19 @@
>          if (log.isDebugEnabled()) {
>              log.debug("adding attribute name: " + name + " expression: " + expression);
>          }
> -        attributes.put(name, expression);
> +        attributes.put(name, new ExpressionAttribute(name,expression));
> +    }
> +
> +    /** Add an initialization attribute for the tag.
> +     * This method must be called after the setTag() method
> +     */
> +    public void addAttribute(String name, String prefix, String nsURI, Expression expression) {
> +        if (log.isDebugEnabled()) {
> +            log.debug("adding attribute name: " + name + " expression: " + expression);
> +        }
> +        if(name.indexOf(':')==-1)
> +            name = prefix + ':' + name;
> +        attributes.put(name, new ExpressionAttribute(name,prefix,nsURI,expression));
>      }
> 
>      /**
> @@ -206,7 +218,7 @@
>                  for (Iterator iter = attributes.entrySet().iterator(); iter.hasNext();) {
>                      Map.Entry entry = (Map.Entry) iter.next();
>                      String name = (String) entry.getKey();
> -                    Expression expression = (Expression) entry.getValue();
> +                    Expression expression = ((ExpressionAttribute) entry.getValue()).exp;
> 
>                      Class type = dynaTag.getAttributeType(name);
>                      Object value = null;
> @@ -225,7 +237,7 @@
>                  for (Iterator iter = attributes.entrySet().iterator(); iter.hasNext();) {
>                      Map.Entry entry = (Map.Entry) iter.next();
>                      String name = (String) entry.getKey();
> -                    Expression expression = (Expression) entry.getValue();
> +                    Expression expression = ((ExpressionAttribute) entry.getValue()).exp;
> 
>                      DynaProperty property = dynaBean.getDynaClass().getDynaProperty(name);
>                      if (property == null) {
> @@ -690,3 +702,21 @@
>          throw new JellyTagException(e, fileName, elementName, columnNumber, lineNumber);
>      }
>  }
> +
> +
> +class ExpressionAttribute {
> +    public ExpressionAttribute(String name, Expression exp) {
> +        this(name,"","",exp);
> +    }
> +    public ExpressionAttribute(String name, String prefix, String nsURI, Expression exp) {
> +        this.name = name;
> +        this.prefix = prefix;
> +        this.nsURI = nsURI;
> +        this.exp = exp;
> +    }
> +
> +    String name;
> +    String prefix;
> +    String nsURI;
> +    Expression exp;
> +}
> \ No newline at end of file
> 
> Modified: jakarta/commons/proper/jelly/trunk/src/java/org/apache/commons/jelly/parser/XMLParser.java
> URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/jelly/trunk/src/java/org/apache/commons/jelly/parser/XMLParser.java?rev=219726&r1=219725&r2=219726&view=diff
> ==============================================================================
> --- jakarta/commons/proper/jelly/trunk/src/java/org/apache/commons/jelly/parser/XMLParser.java (original)
> +++ jakarta/commons/proper/jelly/trunk/src/java/org/apache/commons/jelly/parser/XMLParser.java Tue Jul 19 10:34:00 2005
> @@ -1066,7 +1066,12 @@
>                          attributeValue, getExpressionFactory()
>                      );
>                  String attrQName = list.getQName(i);
> -                script.addAttribute(attrQName, expression);
> +                int p = attrQName.indexOf(':');
> +                String prefix = p>=0 ?
> +                        attrQName.substring(0,p):
> +                        "";
> +                script.addAttribute(list.getLocalName(i),
> +                        prefix, list.getURI(i), expression);
>              }
>              return script;
>          }
> 
> Modified: jakarta/commons/proper/jelly/trunk/src/test/org/apache/commons/jelly/TestCoreTags.java
> URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/jelly/trunk/src/test/org/apache/commons/jelly/TestCoreTags.java?rev=219726&r1=219725&r2=219726&view=diff
> ==============================================================================
> --- jakarta/commons/proper/jelly/trunk/src/test/org/apache/commons/jelly/TestCoreTags.java (original)
> +++ jakarta/commons/proper/jelly/trunk/src/test/org/apache/commons/jelly/TestCoreTags.java Tue Jul 19 10:34:00 2005
> @@ -105,4 +105,24 @@
>          textScript.trimStartWhitespace();
>          assertEquals("foo", textScript.getText());
>      }
> +
> +
> +    public void testStaticNamespacedAttributes() throws Exception {
> +        InputStream in = new FileInputStream("src/test/org/apache/commons/jelly/testStaticNamespacedAttributes.jelly");
> +        XMLParser parser = new XMLParser();
> +        Script script = parser.parse(in);
> +        script = script.compile();
> +        log.debug("Found: " + script);
> +        JellyContext context = new JellyContext();
> +        StringWriter buffer = new StringWriter();
> +        script.run(context, XMLOutput.createXMLOutput(buffer));
> +        String text = buffer.toString().trim();
> +        if (log.isDebugEnabled()) {
> +            log.debug("Evaluated script as...");
> +            log.debug(text);
> +        }
> +        assertEquals("Should produces the correct output",
> +                "<blip xmlns:blop=\"blop\" blop:x=\"blip\"></blip>",
> +                text);
> +    }
>  }
> 
> Modified: jakarta/commons/proper/jelly/trunk/src/test/org/apache/commons/jelly/core/TestFileTag.java
> URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/jelly/trunk/src/test/org/apache/commons/jelly/core/TestFileTag.java?rev=219726&r1=219725&r2=219726&view=diff
> ==============================================================================
> --- jakarta/commons/proper/jelly/trunk/src/test/org/apache/commons/jelly/core/TestFileTag.java (original)
> +++ jakarta/commons/proper/jelly/trunk/src/test/org/apache/commons/jelly/core/TestFileTag.java Tue Jul 19 10:34:00 2005
> @@ -55,7 +55,7 @@
> 
>          //FIXME This doesn't take into account attribute ordering
>          assertEquals("fully qualified attributes not passed",
> -                "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\"></html>",
> +                "<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"en\" xml:lang=\"en\"></html>",
>                  data);
>      }
> 
> 
> Added: jakarta/commons/proper/jelly/trunk/src/test/org/apache/commons/jelly/testStaticNamespacedAttributes.jelly
> URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/jelly/trunk/src/test/org/apache/commons/jelly/testStaticNamespacedAttributes.jelly?rev=219726&view=auto
> ==============================================================================
> --- jakarta/commons/proper/jelly/trunk/src/test/org/apache/commons/jelly/testStaticNamespacedAttributes.jelly (added)
> +++ jakarta/commons/proper/jelly/trunk/src/test/org/apache/commons/jelly/testStaticNamespacedAttributes.jelly Tue Jul 19 10:34:00 2005
> @@ -0,0 +1,4 @@
> +<?xml version="1.0" encoding="utf-8" ?>
> +<j:jelly xmlns:j="jelly:core">
> +       <blip xmlns:blop="blop" blop:x="blip"/>
> +</j:jelly>
> 
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: commons-dev-help@jakarta.apache.org
> 
> 


-- 
http://www.multitask.com.au/people/dion/
"You are going to let the fear of poverty govern your life and your
reward will be that you will eat, but you will not live." - George
Bernard Shaw

---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org