You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by hl...@apache.org on 2011/10/25 21:18:48 UTC

svn commit: r1188867 - in /tapestry/tapestry5/trunk/tapestry-core/src: main/java/org/apache/tapestry5/internal/dynamic/ main/java/org/apache/tapestry5/internal/services/ test/java/org/apache/tapestry5/internal/services/ test/resources/org/apache/tapest...

Author: hlship
Date: Tue Oct 25 19:18:47 2011
New Revision: 1188867

URL: http://svn.apache.org/viewvc?rev=1188867&view=rev
Log:
TAP5-1720: Supply a "<!DOCTYPE html>" for any component template that doesn't have a specific <!DOCTYPE>

Added:
    tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/internal/services/html_entities.tml
Modified:
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/dynamic/DynamicTemplateParserImpl.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/dynamic/DynamicTemplateSaxParser.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DTDData.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/SaxTemplateParser.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/TemplateParser.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/TemplateParserImpl.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/XMLTokenStream.java
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/TemplateParserImplTest.java

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/dynamic/DynamicTemplateParserImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/dynamic/DynamicTemplateParserImpl.java?rev=1188867&r1=1188866&r2=1188867&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/dynamic/DynamicTemplateParserImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/dynamic/DynamicTemplateParserImpl.java Tue Oct 25 19:18:47 2011
@@ -14,9 +14,8 @@
 
 package org.apache.tapestry5.internal.dynamic;
 
-import java.util.Map;
-
 import org.apache.tapestry5.internal.services.PageSource;
+import org.apache.tapestry5.internal.services.TemplateParser;
 import org.apache.tapestry5.ioc.Resource;
 import org.apache.tapestry5.ioc.annotations.PostInjection;
 import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
@@ -28,6 +27,8 @@ import org.apache.tapestry5.services.Upd
 import org.apache.tapestry5.services.dynamic.DynamicTemplate;
 import org.apache.tapestry5.services.dynamic.DynamicTemplateParser;
 
+import java.util.Map;
+
 public class DynamicTemplateParserImpl implements DynamicTemplateParser, UpdateListener
 {
     private final Map<Resource, DynamicTemplate> cache = CollectionFactory.newConcurrentMap();
@@ -38,10 +39,13 @@ public class DynamicTemplateParserImpl i
 
     private final URLChangeTracker tracker;
 
-    public DynamicTemplateParserImpl(ClasspathURLConverter converter, BindingSource bindingSource, PageSource pageSource)
+    private final TemplateParser componentTemplateParser;
+
+    public DynamicTemplateParserImpl(ClasspathURLConverter converter, BindingSource bindingSource, PageSource pageSource, TemplateParser componentTemplateParser)
     {
         this.bindingSource = bindingSource;
         this.pageSource = pageSource;
+        this.componentTemplateParser = componentTemplateParser;
 
         tracker = new URLChangeTracker(converter);
     }
@@ -69,7 +73,7 @@ public class DynamicTemplateParserImpl i
 
     private DynamicTemplate doParse(Resource resource)
     {
-        return new DynamicTemplateSaxParser(resource, bindingSource).parse();
+        return new DynamicTemplateSaxParser(resource, bindingSource, componentTemplateParser.getDTDURLMappings()).parse();
     }
 
     public void checkForUpdates()

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/dynamic/DynamicTemplateSaxParser.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/dynamic/DynamicTemplateSaxParser.java?rev=1188867&r1=1188866&r2=1188867&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/dynamic/DynamicTemplateSaxParser.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/dynamic/DynamicTemplateSaxParser.java Tue Oct 25 19:18:47 2011
@@ -14,15 +14,6 @@
 
 package org.apache.tapestry5.internal.dynamic;
 
-import java.net.URL;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import javax.xml.namespace.QName;
-
 import org.apache.tapestry5.Binding;
 import org.apache.tapestry5.BindingConstants;
 import org.apache.tapestry5.Block;
@@ -44,7 +35,16 @@ import org.apache.tapestry5.services.Bin
 import org.apache.tapestry5.services.dynamic.DynamicDelegate;
 import org.apache.tapestry5.services.dynamic.DynamicTemplate;
 
-/** Does the heavy lifting for {@link DynamicTemplateParserImpl}. */
+import javax.xml.namespace.QName;
+import java.net.URL;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Does the heavy lifting for {@link DynamicTemplateParserImpl}.
+ */
 public class DynamicTemplateSaxParser
 {
     private final Resource resource;
@@ -53,8 +53,6 @@ public class DynamicTemplateSaxParser
 
     private final XMLTokenStream tokenStream;
 
-    private final Map<String, URL> publicIdToURL = Collections.emptyMap();
-
     private static final Pattern PARAM_ID_PATTERN = Pattern.compile("^param:(\\p{Alpha}\\w*)$",
             Pattern.CASE_INSENSITIVE);
 
@@ -69,7 +67,7 @@ public class DynamicTemplateSaxParser
         }
     };
 
-    public DynamicTemplateSaxParser(Resource resource, BindingSource bindingSource)
+    public DynamicTemplateSaxParser(Resource resource, BindingSource bindingSource, Map<String, URL> publicIdToURL)
     {
         this.resource = resource;
         this.bindingSource = bindingSource;
@@ -84,8 +82,7 @@ public class DynamicTemplateSaxParser
             tokenStream.parse();
 
             return toDynamicTemplate(root());
-        }
-        catch (Exception ex)
+        } catch (Exception ex)
         {
             throw new TapestryException(String.format("Failure parsing dynamic template %s: %s", resource,
                     InternalUtils.toMessage(ex)), tokenStream.getLocation(), ex);
@@ -219,7 +216,7 @@ public class DynamicTemplateSaxParser
     }
 
     private static DynamicTemplateElement createElementWriterElement(final String elementURI, final String elementName,
-            final List<DynamicTemplateAttribute> attributes, List<DynamicTemplateElement> body)
+                                                                     final List<DynamicTemplateAttribute> attributes, List<DynamicTemplateElement> body)
     {
         final Flow<DynamicTemplateElement> bodyFlow = F.flow(body).reverse();
 
@@ -269,8 +266,7 @@ public class DynamicTemplateSaxParser
                     Block block = delegate.getBlock(blockId);
 
                     queue.push((RenderCommand) block);
-                }
-                catch (Exception ex)
+                } catch (Exception ex)
                 {
                     throw new TapestryException(String.format(
                             "Exception rendering block '%s' as part of dynamic template: %s", blockId,
@@ -443,7 +439,7 @@ public class DynamicTemplateSaxParser
     }
 
     private static Mapper<DynamicDelegate, String> createExpansionExtractor(final String expression,
-            final Location location, final BindingSource bindingSource)
+                                                                            final Location location, final BindingSource bindingSource)
     {
         return new Mapper<DynamicDelegate, String>()
         {
@@ -458,8 +454,7 @@ public class DynamicTemplateSaxParser
                     Object boundValue = binding.get();
 
                     return boundValue == null ? null : boundValue.toString();
-                }
-                catch (Throwable t)
+                } catch (Throwable t)
                 {
                     throw new TapestryException(InternalUtils.toMessage(t), location, t);
                 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DTDData.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DTDData.java?rev=1188867&r1=1188866&r2=1188867&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DTDData.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DTDData.java Tue Oct 25 19:18:47 2011
@@ -1,4 +1,4 @@
-// Copyright 2009 The Apache Software Foundation
+// Copyright 2009, 2011 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.
@@ -19,14 +19,17 @@ import org.xml.sax.ext.LexicalHandler;
 /**
  * A capturing of the data from
  * {@link LexicalHandler#startDTD(String, String, String)}.
- * 
+ *
  * @since 5.2.0
  */
-public interface DTDData
+public class DTDData
 {
-    String getRootName();
+    public final String rootName, publicId, systemId;
 
-    String getPublicId();
-
-    String getSystemId();
+    public DTDData(String rootName, String publicId, String systemId)
+    {
+        this.rootName = rootName;
+        this.publicId = publicId;
+        this.systemId = systemId;
+    }
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/SaxTemplateParser.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/SaxTemplateParser.java?rev=1188867&r1=1188866&r2=1188867&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/SaxTemplateParser.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/SaxTemplateParser.java Tue Oct 25 19:18:47 2011
@@ -1,4 +1,4 @@
-// Copyright 2009 The Apache Software Foundation
+// Copyright 2009, 2011 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.
@@ -293,8 +293,8 @@ public class SaxTemplateParser
     {
         DTDData dtdInfo = tokenStream.getDTDInfo();
 
-        tokenAccumulator.add(new DTDToken(dtdInfo.getRootName(), dtdInfo.getPublicId(), dtdInfo
-                .getSystemId(), getLocation()));
+        tokenAccumulator.add(new DTDToken(dtdInfo.rootName, dtdInfo.publicId, dtdInfo
+                .systemId, getLocation()));
     }
 
     private Location getLocation()

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/TemplateParser.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/TemplateParser.java?rev=1188867&r1=1188866&r2=1188867&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/TemplateParser.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/TemplateParser.java Tue Oct 25 19:18:47 2011
@@ -1,4 +1,4 @@
-// Copyright 2006, 2008 The Apache Software Foundation
+// Copyright 2006, 2008, 2011 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.
@@ -19,6 +19,7 @@ import org.apache.tapestry5.ioc.Resource
 import org.apache.tapestry5.ioc.annotations.UsesMappedConfiguration;
 
 import java.net.URL;
+import java.util.Map;
 
 /**
  * Parses a resource into a {@link org.apache.tapestry5.internal.parser.ComponentTemplate}. The service's configuration
@@ -37,4 +38,13 @@ public interface TemplateParser
      * @throws RuntimeException if the resource does not exist, or if there is any kind of parse error
      */
     ComponentTemplate parseTemplate(Resource templateResource);
+
+    /**
+     * Returns a mapping from URL string to a local equivalent URL, used to avoid attempting to pull
+     * well-known DTDs down over the wire while parsing XML.
+     *
+     * @since 5.3
+     */
+    Map<String, URL> getDTDURLMappings();
 }
+

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/TemplateParserImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/TemplateParserImpl.java?rev=1188867&r1=1188866&r2=1188867&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/TemplateParserImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/TemplateParserImpl.java Tue Oct 25 19:18:47 2011
@@ -1,4 +1,4 @@
-// Copyright 2006, 2007, 2008, 2009, 2010 The Apache Software Foundation
+// Copyright 2006, 2007, 2008, 2009, 2010, 2011 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.
@@ -14,9 +14,6 @@
 
 package org.apache.tapestry5.internal.services;
 
-import java.net.URL;
-import java.util.Map;
-
 import org.apache.tapestry5.SymbolConstants;
 import org.apache.tapestry5.internal.parser.ComponentTemplate;
 import org.apache.tapestry5.ioc.Invokable;
@@ -24,11 +21,14 @@ import org.apache.tapestry5.ioc.Operatio
 import org.apache.tapestry5.ioc.Resource;
 import org.apache.tapestry5.ioc.annotations.Symbol;
 
+import java.net.URL;
+import java.util.Map;
+
 /**
  * Parses Tapestry XML template files into {@link ComponentTemplate} instances.
  * A new instance of {@link SaxTemplateParser} is created for each document
  * parsed.
- * 
+ *
  * @since 5.1.0.0
  */
 public class TemplateParserImpl implements TemplateParser
@@ -41,8 +41,8 @@ public class TemplateParserImpl implemen
 
     public TemplateParserImpl(Map<String, URL> configuration,
 
-    @Symbol(SymbolConstants.COMPRESS_WHITESPACE)
-    boolean defaultCompressWhitespace, OperationTracker tracker)
+                              @Symbol(SymbolConstants.COMPRESS_WHITESPACE)
+                              boolean defaultCompressWhitespace, OperationTracker tracker)
     {
         this.configuration = configuration;
         this.defaultCompressWhitespace = defaultCompressWhitespace;
@@ -62,4 +62,9 @@ public class TemplateParserImpl implemen
             }
         });
     }
+
+    public Map<String, URL> getDTDURLMappings()
+    {
+        return configuration;
+    }
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/XMLTokenStream.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/XMLTokenStream.java?rev=1188867&r1=1188866&r2=1188867&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/XMLTokenStream.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/XMLTokenStream.java Tue Oct 25 19:18:47 2011
@@ -37,6 +37,11 @@ import java.util.Map;
  */
 public class XMLTokenStream
 {
+
+    public static final String TRANSITIONAL_DOCTYPE = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">";
+
+    private static final DTDData HTML5_DTD_DATA = new DTDData("html", null, null);
+
     private final class SaxHandler implements LexicalHandler, EntityResolver, ContentHandler
     {
         private Locator locator;
@@ -62,7 +67,10 @@ public class XMLTokenStream
 
             if (cachedLocation == null)
             {
-                cachedLocation = new LocationImpl(resource, line);
+                // lineOffset accounts for the extra line when a doctype is injected. The line number reported
+                // from the XML parser inlcudes the phantom doctype line, the lineOffset is used to subtract one
+                // to get the real line number.
+                cachedLocation = new LocationImpl(resource, line + lineOffset);
             }
 
             return cachedLocation;
@@ -138,6 +146,7 @@ public class XMLTokenStream
 
         public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException
         {
+            characters(ch, start, length);
         }
 
         public void startDTD(final String name, final String publicId, final String systemId)
@@ -145,26 +154,12 @@ public class XMLTokenStream
         {
             insideDTD = true;
 
-            DTDData data = new DTDData()
+            if (!ignoreDTD)
             {
+                DTDData data = html5DTD ? HTML5_DTD_DATA : new DTDData(name, publicId, systemId);
 
-                public String getSystemId()
-                {
-                    return html5DTD ? null : systemId;
-                }
-
-                public String getRootName()
-                {
-                    return name;
-                }
-
-                public String getPublicId()
-                {
-                    return html5DTD ? null : publicId;
-                }
-            };
-
-            add(XMLTokenType.DTD).dtdData = data;
+                add(XMLTokenType.DTD).dtdData = data;
+            }
         }
 
         public void endDocument() throws SAXException
@@ -182,12 +177,21 @@ public class XMLTokenStream
             this.locator = locator;
         }
 
+        /**
+         * Checks for the extra namespace injected when the transitional doctype is injected (which
+         * occurs when the template contains no doctype).
+         */
+        private boolean ignoreURI(String uri)
+        {
+            return ignoreDTD && uri.equals("http://www.w3.org/1999/xhtml");
+        }
+
         public void startElement(String uri, String localName, String qName, Attributes attributes)
                 throws SAXException
         {
             XMLToken token = add(XMLTokenType.START_ELEMENT);
 
-            token.uri = uri;
+            token.uri = ignoreURI(uri) ? "" : uri;
             token.localName = localName;
             token.qName = qName;
 
@@ -227,6 +231,11 @@ public class XMLTokenStream
 
         public void startPrefixMapping(String prefix, String uri) throws SAXException
         {
+            if (ignoreDTD && prefix.equals("") && uri.equals("http://www.w3.org/1999/xhtml"))
+            {
+                return;
+            }
+
             namespaceMappings.add(new NamespaceMapping(prefix, uri));
         }
 
@@ -270,7 +279,9 @@ public class XMLTokenStream
 
     private Location exceptionLocation;
 
-    private boolean html5DTD;
+    private boolean html5DTD, ignoreDTD;
+
+    private int lineOffset;
 
     public XMLTokenStream(Resource resource, Map<String, URL> publicIdToURL)
     {
@@ -314,60 +325,95 @@ public class XMLTokenStream
         }
     }
 
-    private InputStream openStream() throws IOException
+    enum State
     {
+        MAYBE_XML, MAYBE_DOCTYPE, JUST_COPY
+    }
 
+    private InputStream openStream() throws IOException
+    {
         InputStream rawStream = resource.openStream();
 
         InputStreamReader rawReader = new InputStreamReader(rawStream);
         LineNumberReader reader = new LineNumberReader(rawReader);
 
+        ByteArrayOutputStream bos = new ByteArrayOutputStream(5000);
+        PrintWriter writer = new PrintWriter(bos);
+
+        State state = State.MAYBE_XML;
+
         try
         {
-            String firstLine = reader.readLine();
-
-            if ("<!DOCTYPE html>".equalsIgnoreCase(firstLine))
+            while (true)
             {
-                // When we hit the doctype later, ignore the transitional PUBLIC and SYSTEM ids and
-                // treat it like a proper HTML5 doctype.
-                html5DTD = true;
-                return substituteTransitionalDoctype(reader);
-            }
+                String line = reader.readLine();
 
-            // Open a fresh stream for the parser to operate on.
+                if (line == null)
+                {
+                    break;
+                }
 
-            return resource.openStream();
+                switch (state)
+                {
 
-        } finally
-        {
-            reader.close();
-        }
-    }
+                    case MAYBE_XML:
 
-    private InputStream substituteTransitionalDoctype(LineNumberReader reader) throws IOException
-    {
-        ByteArrayOutputStream bos = new ByteArrayOutputStream(5000);
-        PrintWriter writer = new PrintWriter(bos);
+                        if (line.toLowerCase().startsWith("<?xml"))
+                        {
+                            writer.println(line);
+                            state = State.MAYBE_DOCTYPE;
+                            continue;
+                        }
 
-        writer.println("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">");
+                    case MAYBE_DOCTYPE:
 
-        while (true)
-        {
-            String line = reader.readLine();
-            if (line == null)
-            {
-                break;
-            }
+                        if (line.trim().length() == 0)
+                        {
+                            writer.println(line);
+                            continue;
+                        }
 
-            writer.println(line);
-        }
+                        String lineLower = line.toLowerCase();
+
+                        if (lineLower.equals("<!doctype html>"))
+                        {
+                            html5DTD = true;
+                            writer.println(TRANSITIONAL_DOCTYPE);
+                            state = State.JUST_COPY;
+                            continue;
+                        }
+
+
+                        if (lineLower.startsWith("<!doctype"))
+                        {
+                            writer.println(line);
+                            state = State.JUST_COPY;
+                            continue;
+                        }
 
-        writer.close();
+                        // No doctype, let's provide one.
+
+                        ignoreDTD = true;
+                        lineOffset = -1;
+                        writer.println(TRANSITIONAL_DOCTYPE);
+
+                        state = State.JUST_COPY;
+
+                        // And drop down to writing out the actual line, and all following lines.
+
+                    case JUST_COPY:
+                        writer.println(line);
+                }
+            }
+        } finally
+        {
+            writer.close();
+            reader.close();
+        }
 
         return new ByteArrayInputStream(bos.toByteArray());
     }
 
-
     private XMLToken token()
     {
         return tokens.get(cursor);

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/TemplateParserImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/TemplateParserImplTest.java?rev=1188867&r1=1188866&r2=1188867&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/TemplateParserImplTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/TemplateParserImplTest.java Tue Oct 25 19:18:47 2011
@@ -985,4 +985,22 @@ public class TemplateParserImplTest exte
             assertMessageContains(ex, "Extension point 'batman' is already defined for this template.");
         }
     }
+
+    @Test
+    public void html_entities_inside_template_without_doctype_are_allowed() throws Exception
+    {
+
+        List<TemplateToken> tokens = tokens("html_entities.tml");
+
+        assertEquals(tokens.size(), 3);
+
+        StartElementToken token0 = get(tokens, 0);
+
+        assertEquals(token0.name, "html");
+
+        TextToken token1 = get(tokens, 1);
+
+        assertEquals(token1.text, "\n[\u00A0]\n");
+
+    }
 }

Added: tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/internal/services/html_entities.tml
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/internal/services/html_entities.tml?rev=1188867&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/internal/services/html_entities.tml (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/internal/services/html_entities.tml Tue Oct 25 19:18:47 2011
@@ -0,0 +1,3 @@
+<html>
+    [&nbsp;]
+</html>
\ No newline at end of file