Return-Path: X-Original-To: apmail-cocoon-dev-archive@www.apache.org Delivered-To: apmail-cocoon-dev-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 2F8C09BBE for ; Mon, 26 Mar 2012 08:56:21 +0000 (UTC) Received: (qmail 4353 invoked by uid 500); 26 Mar 2012 08:56:20 -0000 Delivered-To: apmail-cocoon-dev-archive@cocoon.apache.org Received: (qmail 4207 invoked by uid 500); 26 Mar 2012 08:56:18 -0000 Mailing-List: contact dev-help@cocoon.apache.org; run by ezmlm Precedence: bulk list-help: list-unsubscribe: List-Post: Reply-To: dev@cocoon.apache.org List-Id: Delivered-To: mailing list dev@cocoon.apache.org Received: (qmail 4196 invoked by uid 99); 26 Mar 2012 08:56:18 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 26 Mar 2012 08:56:18 +0000 X-ASF-Spam-Status: No, hits=2.9 required=5.0 tests=HTML_MESSAGE,SPF_NEUTRAL X-Spam-Check-By: apache.org Received-SPF: neutral (athena.apache.org: local policy) Received: from [78.134.5.44] (HELO rovere.tirasa.net) (78.134.5.44) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 26 Mar 2012 08:56:11 +0000 Received: from localhost (localhost [127.0.0.1]) by rovere.tirasa.net (Postfix) with ESMTP id 2E755183BBB for ; Mon, 26 Mar 2012 10:55:48 +0200 (CEST) X-Virus-Scanned: amavisd-new at tirasa.net Received: from rovere.tirasa.net ([127.0.0.1]) by localhost (rovere.tirasa.net [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 9e6KLNWtREHL for ; Mon, 26 Mar 2012 10:55:41 +0200 (CEST) Received: from [192.168.0.2] (mogano.tirasa.net [192.168.0.2]) by rovere.tirasa.net (Postfix) with ESMTPSA id 238A8183AE5 for ; Mon, 26 Mar 2012 10:55:41 +0200 (CEST) Message-ID: <4F702F0C.1050606@apache.org> Date: Mon, 26 Mar 2012 10:55:40 +0200 From: =?UTF-8?B?RnJhbmNlc2NvIENoaWNjaGlyaWNjw7I=?= User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:10.0.1) Gecko/20120304 Thunderbird/10.0.1 MIME-Version: 1.0 To: dev@cocoon.apache.org Subject: Re: svn commit: r1305128 - /cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/component/I18nTransformer.java References: <20120325205851.4DB8F2388860@eris.apache.org> In-Reply-To: <20120325205851.4DB8F2388860@eris.apache.org> X-Enigmail-Version: 1.3.5 Content-Type: multipart/alternative; boundary="------------050501070807080608030407" X-Virus-Checked: Checked by ClamAV on apache.org This is a multi-part message in MIME format. --------------050501070807080608030407 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Hi Andreas, very cool that you fixed this on I18NTransformer: it was in my TODO list, so I am glad twice ;-) Could you please add a specific unit test [1] for the feature you've added? Actually, a couple of tests would be better: one for default namespace and one for a custom namespace. A nice thing would also be to add something to samples [2]. I was waiting to have some time to move ParamSAXBuffer to proper subproject (cocoon-xml), instead of keeping it in cocoon-sax, as reported in [4], point 5; hence my proposal is: why don't you merge FragmentBuffer in ParamSAXBuffer? Later on I will move this class to cocoon-xml, as planned. Thanks! Regards. [1] https://svn.apache.org/repos/asf/cocoon/cocoon3/trunk/cocoon-sax/src/test/java/org/apache/cocoon/sax/component/I18NTransformerTest.java [2] https://svn.apache.org/repos/asf/cocoon/cocoon3/trunk/cocoon-sample/src/main/resources/COB-INF/sitemap.xmap [3] https://issues.apache.org/jira/browse/COCOON3-64 [4] https://issues.apache.org/jira/browse/COCOON3-64?focusedCommentId=13083164&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-13083164 On 25/03/2012 22:58, andreas@apache.org wrote: > Author: andreas > Date: Sun Mar 25 20:58:50 2012 > New Revision: 1305128 > > URL: http://svn.apache.org/viewvc?rev=1305128&view=rev > Log: > Add parameters parse-xml and parse-namespace to the I18nTransformer. Allows to include XML elements in I18n messages. > > Modified: > cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/component/I18nTransformer.java > > Modified: cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/component/I18nTransformer.java > URL: http://svn.apache.org/viewvc/cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/component/I18nTransformer.java?rev=1305128&r1=1305127&r2=1305128&view=diff > ============================================================================== > --- cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/component/I18nTransformer.java (original) > +++ cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/component/I18nTransformer.java Sun Mar 25 20:58:50 2012 > @@ -33,9 +33,9 @@ import java.util.Map; > import java.util.MissingResourceException; > import java.util.PropertyResourceBundle; > import java.util.ResourceBundle; > +import java.util.ResourceBundle.Control; > import java.util.Set; > import java.util.StringTokenizer; > -import java.util.ResourceBundle.Control; > > import org.apache.cocoon.pipeline.SetupException; > import org.apache.cocoon.pipeline.caching.CacheKey; > @@ -44,6 +44,7 @@ import org.apache.cocoon.pipeline.compon > import org.apache.cocoon.sax.AbstractSAXTransformer; > import org.apache.cocoon.sax.util.VariableExpressionTokenizer; > import org.apache.cocoon.sax.util.VariableExpressionTokenizer.TokenReceiver; > +import org.apache.cocoon.sax.util.XMLUtils; > import org.apache.cocoon.xml.sax.ParamSAXBuffer; > import org.apache.cocoon.xml.sax.SAXBuffer; > import org.slf4j.Logger; > @@ -577,6 +578,16 @@ public class I18nTransformer extends Abs > public static final String DEFAULT_ENCODING = "ISO-8859-1"; > > /** > + * If XML inside i18n messages shall be parsed. > + */ > + public static final String PARAM_PARSE_XML = "parse-xml"; > + > + /** > + * The default namespace for XML elements inside messages. Defaults to http://www.w3.org/1999/xhtml. > + */ > + public static final String PARAM_PARSE_NAMESPACE = "parse-namespace"; > + > + /** > * States of the transformer. > */ > private enum TransformerState { > @@ -717,6 +728,12 @@ public class I18nTransformer extends Abs > > // Date and number elements and params formatting attributes with values. > private Map formattingParams; > + > + // parse XML inside messages? > + private boolean parseXml; > + > + // default namespace for XML inside messages > + private String parseNamespace; > > /** > * Empty constructor, for usage with sitemap. > @@ -806,6 +823,16 @@ public class I18nTransformer extends Abs > > final String encoding = (String) (parameters.containsKey(PARAM_ENCODING) > ? parameters.get(PARAM_ENCODING) : DEFAULT_ENCODING); > + > + this.parseXml = parameters.containsKey(PARAM_PARSE_XML) > + ? Boolean.parseBoolean((String) parameters.get(PARAM_PARSE_XML)) > + : false; > + > + if (this.parseXml) { > + this.parseNamespace = parameters.containsKey(PARAM_PARSE_NAMESPACE) > + ? (String) parameters.get(PARAM_PARSE_NAMESPACE) > + : "http://www.w3.org/1999/xhtml"; > + } > > this.init(parseLocale((String) parameters.get(PARAM_LOCALE)), > (String) parameters.get(PARAM_BUNDLE), > @@ -966,7 +993,7 @@ public class I18nTransformer extends Abs > > if (currentKey != null) { > final ParamSAXBuffer message = > - getMessage(currentKey, ParamSAXBuffer.class); > + getMessage(currentKey, FragmentBuffer.class); > translatedTextRecorder = message; > } > } else if (ELEM_TRANSLATE.equals(name)) { > @@ -1898,7 +1925,19 @@ public class I18nTransformer extends Abs > if (message != null && message.length() > 0) { > try { > buffer = reference.newInstance(); > - buffer.characters(message.toCharArray(), 0, message.length()); > + if (this.parseXml) { > + try { > + final String xml = "" + message + ""; > + XMLUtils.toSax(xml, buffer); > + } catch (Exception e) { > + LOG.error("Could not parse XML '{}'", message, e); > + buffer.recycle(); > + buffer.characters(message.toCharArray(), 0, message.length()); > + } > + } > + else { > + buffer.characters(message.toCharArray(), 0, message.length()); > + } > } catch (InstantiationException e) { > LOG.error("Could not instantiate {}", reference, e); > } catch (IllegalAccessException e) { > @@ -1908,6 +1947,42 @@ public class I18nTransformer extends Abs > > return buffer; > } > + > + /** > + * SAX buffer which passes only the content of the document element to the content handler. > + * An element with an arbitrary local name can be used the wrapper element. > + */ > + protected static final class FragmentBuffer extends ParamSAXBuffer { > + > + private static final long serialVersionUID = -9153292487513611344L; > + > + private int depth = 0; > + > + @Override > + public void startDocument() throws SAXException {} > + > + @Override > + public void endDocument() throws SAXException {} > + > + @Override > + public void startElement(String namespaceURI, String localName, String qName, > + Attributes atts) throws SAXException { > + if (this.depth > 0) { > + super.startElement(namespaceURI, localName, qName, atts); > + } > + this.depth++; > + } > + > + @Override > + public void endElement(String namespaceURI, String localName, String qName) > + throws SAXException { > + this.depth--; > + if (this.depth > 0) { > + super.endElement(namespaceURI, localName, qName); > + } > + } > + > + } > > /** > * Helper method to retrieve a message from the current dictionary. > @@ -1922,7 +1997,7 @@ public class I18nTransformer extends Abs > final ParamSAXBuffer defaultValue) > throws SAXException { > > - ParamSAXBuffer result = getMessage(key, ParamSAXBuffer.class); > + ParamSAXBuffer result = getMessage(key, FragmentBuffer.class); > if (result == null) { > result = defaultValue; > } -- Francesco Chicchiriccò Apache Cocoon PMC and Apache Syncope PPMC Member http://people.apache.org/~ilgrosso/ --------------050501070807080608030407 Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: 8bit Hi Andreas,
very cool that you fixed this on I18NTransformer: it was in my TODO list, so I am glad twice ;-)

Could you please add a specific unit test [1] for the feature you've added? Actually, a couple of tests would be better: one for default namespace and one for a custom namespace.

A nice thing would also be to add something to samples [2].

I was waiting to have some time to move ParamSAXBuffer to proper subproject (cocoon-xml), instead of keeping it in cocoon-sax, as reported in [4], point 5; hence my proposal is: why don't you merge FragmentBuffer in ParamSAXBuffer? Later on I will move this class to cocoon-xml, as planned.

Thanks!
Regards.

[1] https://svn.apache.org/repos/asf/cocoon/cocoon3/trunk/cocoon-sax/src/test/java/org/apache/cocoon/sax/component/I18NTransformerTest.java
[2] https://svn.apache.org/repos/asf/cocoon/cocoon3/trunk/cocoon-sample/src/main/resources/COB-INF/sitemap.xmap
[3] https://issues.apache.org/jira/browse/COCOON3-64
[4] https://issues.apache.org/jira/browse/COCOON3-64?focusedCommentId=13083164&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-13083164

On 25/03/2012 22:58, andreas@apache.org wrote:
Author: andreas
Date: Sun Mar 25 20:58:50 2012
New Revision: 1305128

URL: http://svn.apache.org/viewvc?rev=1305128&view=rev
Log:
Add parameters parse-xml and parse-namespace to the I18nTransformer. Allows to include XML elements in I18n messages.

Modified:
    cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/component/I18nTransformer.java

Modified: cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/component/I18nTransformer.java
URL: http://svn.apache.org/viewvc/cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/component/I18nTransformer.java?rev=1305128&r1=1305127&r2=1305128&view=diff
==============================================================================
--- cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/component/I18nTransformer.java (original)
+++ cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/component/I18nTransformer.java Sun Mar 25 20:58:50 2012
@@ -33,9 +33,9 @@ import java.util.Map;
 import java.util.MissingResourceException;
 import java.util.PropertyResourceBundle;
 import java.util.ResourceBundle;
+import java.util.ResourceBundle.Control;
 import java.util.Set;
 import java.util.StringTokenizer;
-import java.util.ResourceBundle.Control;
 
 import org.apache.cocoon.pipeline.SetupException;
 import org.apache.cocoon.pipeline.caching.CacheKey;
@@ -44,6 +44,7 @@ import org.apache.cocoon.pipeline.compon
 import org.apache.cocoon.sax.AbstractSAXTransformer;
 import org.apache.cocoon.sax.util.VariableExpressionTokenizer;
 import org.apache.cocoon.sax.util.VariableExpressionTokenizer.TokenReceiver;
+import org.apache.cocoon.sax.util.XMLUtils;
 import org.apache.cocoon.xml.sax.ParamSAXBuffer;
 import org.apache.cocoon.xml.sax.SAXBuffer;
 import org.slf4j.Logger;
@@ -577,6 +578,16 @@ public class I18nTransformer extends Abs
     public static final String DEFAULT_ENCODING = "ISO-8859-1";
 
     /**
+     * If XML inside i18n messages shall be parsed.
+     */
+    public static final String PARAM_PARSE_XML = "parse-xml";
+
+    /**
+     * The default namespace for XML elements inside messages. Defaults to http://www.w3.org/1999/xhtml.
+     */
+    public static final String PARAM_PARSE_NAMESPACE = "parse-namespace";
+
+    /**
      * States of the transformer.
      */
     private enum TransformerState {
@@ -717,6 +728,12 @@ public class I18nTransformer extends Abs
 
     // Date and number elements and params formatting attributes with values.
     private Map<String, String> formattingParams;
+    
+    // parse XML inside messages?
+    private boolean parseXml;
+
+    // default namespace for XML inside messages
+    private String parseNamespace;
 
     /**
      * Empty constructor, for usage with sitemap.
@@ -806,6 +823,16 @@ public class I18nTransformer extends Abs
         
         final String encoding = (String) (parameters.containsKey(PARAM_ENCODING)
                 ? parameters.get(PARAM_ENCODING) : DEFAULT_ENCODING);
+        
+        this.parseXml = parameters.containsKey(PARAM_PARSE_XML)
+                ? Boolean.parseBoolean((String) parameters.get(PARAM_PARSE_XML))
+                : false;
+
+        if (this.parseXml) {
+            this.parseNamespace = parameters.containsKey(PARAM_PARSE_NAMESPACE)
+                    ? (String) parameters.get(PARAM_PARSE_NAMESPACE)
+                    : "http://www.w3.org/1999/xhtml";
+        }
 
         this.init(parseLocale((String) parameters.get(PARAM_LOCALE)),
                 (String) parameters.get(PARAM_BUNDLE),
@@ -966,7 +993,7 @@ public class I18nTransformer extends Abs
 
             if (currentKey != null) {
                 final ParamSAXBuffer message =
-                        getMessage(currentKey, ParamSAXBuffer.class);
+                        getMessage(currentKey, FragmentBuffer.class);
                 translatedTextRecorder = message;
             }
         } else if (ELEM_TRANSLATE.equals(name)) {
@@ -1898,7 +1925,19 @@ public class I18nTransformer extends Abs
         if (message != null && message.length() > 0) {
             try {
                 buffer = reference.newInstance();
-                buffer.characters(message.toCharArray(), 0, message.length());
+                if (this.parseXml) {
+                    try {
+                        final String xml = "<?xml version='1.0'?><dummy xmlns='" + this.parseNamespace + "'>" + message + "</dummy>";
+                        XMLUtils.toSax(xml, buffer);
+                    } catch (Exception e) {
+                        LOG.error("Could not parse XML '{}'", message, e);
+                        buffer.recycle();
+                        buffer.characters(message.toCharArray(), 0, message.length());
+                    }
+                }
+                else {
+                    buffer.characters(message.toCharArray(), 0, message.length());
+                }
             } catch (InstantiationException e) {
                 LOG.error("Could not instantiate {}", reference, e);
             } catch (IllegalAccessException e) {
@@ -1908,6 +1947,42 @@ public class I18nTransformer extends Abs
 
         return buffer;
     }
+    
+    /**
+     * SAX buffer which passes only the content of the document element to the content handler.
+     * An element with an arbitrary local name can be used the wrapper element.
+     */
+    protected static final class FragmentBuffer extends ParamSAXBuffer {
+
+        private static final long serialVersionUID = -9153292487513611344L;
+        
+        private int depth = 0;
+
+        @Override
+        public void startDocument() throws SAXException {}
+
+        @Override
+        public void endDocument() throws SAXException {}
+
+        @Override
+        public void startElement(String namespaceURI, String localName, String qName,
+                Attributes atts) throws SAXException {
+            if (this.depth > 0) {
+                super.startElement(namespaceURI, localName, qName, atts);
+            }
+            this.depth++;
+        }
+
+        @Override
+        public void endElement(String namespaceURI, String localName, String qName)
+                throws SAXException {
+            this.depth--;
+            if (this.depth > 0) {
+                super.endElement(namespaceURI, localName, qName);
+            }
+        }
+        
+    }
 
     /**
      * Helper method to retrieve a message from the current dictionary.
@@ -1922,7 +1997,7 @@ public class I18nTransformer extends Abs
             final ParamSAXBuffer defaultValue)
             throws SAXException {
 
-        ParamSAXBuffer result = getMessage(key, ParamSAXBuffer.class);
+        ParamSAXBuffer result = getMessage(key, FragmentBuffer.class);
         if (result == null) {
             result = defaultValue;
         }
-- 
Francesco Chicchiriccò

Apache Cocoon PMC and Apache Syncope PPMC Member
http://people.apache.org/~ilgrosso/
--------------050501070807080608030407--