You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by hl...@apache.org on 2011/09/23 01:57:20 UTC
svn commit: r1174459 - in /tapestry/tapestry5/trunk/tapestry-core/src:
main/java/org/apache/tapestry5/internal/services/
test/java/org/apache/tapestry5/internal/services/
test/resources/org/apache/tapestry5/internal/services/
Author: hlship
Date: Thu Sep 22 23:57:19 2011
New Revision: 1174459
URL: http://svn.apache.org/viewvc?rev=1174459&view=rev
Log:
TAP5-840: Support character references in tml files with HTML 5 Doctype
Added:
tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/internal/services/html5_with_entities.tml
Modified:
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/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=1174459&r1=1174458&r2=1174459&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 Thu Sep 22 23:57:19 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.
@@ -14,32 +14,28 @@
package org.apache.tapestry5.internal.services;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-
-import javax.xml.namespace.QName;
-
+import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.tapestry5.ioc.Location;
import org.apache.tapestry5.ioc.Resource;
import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
import org.apache.tapestry5.ioc.internal.util.InternalUtils;
import org.apache.tapestry5.ioc.internal.util.LocationImpl;
-import org.apache.tapestry5.ioc.internal.util.TapestryException;
-import org.xml.sax.Attributes;
-import org.xml.sax.ContentHandler;
-import org.xml.sax.EntityResolver;
-import org.xml.sax.InputSource;
-import org.xml.sax.Locator;
-import org.xml.sax.SAXException;
-import org.xml.sax.XMLReader;
+import org.xml.sax.*;
import org.xml.sax.ext.LexicalHandler;
import org.xml.sax.helpers.XMLReaderFactory;
-/** Parses a document as a stream of XML tokens */
+import javax.xml.namespace.QName;
+import java.io.*;
+import java.net.URL;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Parses a document as a stream of XML tokens. It includes a special hack (as of Tapestry 5.3) to support the HTML5 doctype ({@code <!DOCTYPE html>})
+ * as if it were the XHTML transitional doctype
+ * ({@code <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">}).
+ */
public class XMLTokenStream
{
private final class SaxHandler implements LexicalHandler, EntityResolver, ContentHandler
@@ -91,8 +87,7 @@ public class XMLTokenStream
{
if (url != null)
return new InputSource(url.openStream());
- }
- catch (IOException ex)
+ } catch (IOException ex)
{
throw new SAXException(String.format("Unable to open stream for resource %s: %s",
url, InternalUtils.toMessage(ex)), ex);
@@ -204,8 +199,7 @@ public class XMLTokenStream
if (attributes.getLength() == 0)
{
token.attributes = Collections.emptyList();
- }
- else
+ } else
{
token.attributes = CollectionFactory.newList();
@@ -294,36 +288,83 @@ public class XMLTokenStream
reader.setEntityResolver(handler);
reader.setProperty("http://xml.org/sax/properties/lexical-handler", handler);
- InputStream stream = resource.openStream();
+ InputStream stream = openStream();
try
{
reader.parse(new InputSource(stream));
- }
- catch (IOException ex)
+ } catch (IOException ex)
{
this.exceptionLocation = handler.getLocation();
throw ex;
- }
- catch (SAXException ex)
+ } catch (SAXException ex)
{
this.exceptionLocation = handler.getLocation();
throw ex;
- }
- catch (RuntimeException ex)
+ } catch (RuntimeException ex)
{
this.exceptionLocation = handler.getLocation();
throw ex;
- }
- finally
+ } finally
{
InternalUtils.close(stream);
}
}
+ private InputStream openStream() throws IOException
+ {
+
+ InputStream rawStream = resource.openStream();
+
+ InputStreamReader rawReader = new InputStreamReader(rawStream);
+ LineNumberReader reader = new LineNumberReader(rawReader);
+
+ try
+ {
+ String firstLine = reader.readLine();
+
+ if ("<!DOCTYPE html>".equals(firstLine))
+ {
+ return substituteTransitionalDoctype(reader);
+ }
+
+ // Open a fresh stream for the parser to operate on.
+
+ return resource.openStream();
+
+ } finally
+ {
+ reader.close();
+ }
+ }
+
+ private InputStream substituteTransitionalDoctype(LineNumberReader reader) throws IOException
+ {
+ ByteArrayOutputStream bos = new ByteArrayOutputStream(5000);
+ PrintWriter writer = new PrintWriter(bos);
+
+ writer.println("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">");
+
+ while (true)
+ {
+ String line = reader.readLine();
+ if (line == null)
+ {
+ break;
+ }
+
+ writer.println(line);
+ }
+
+ writer.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=1174459&r1=1174458&r2=1174459&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 Thu Sep 22 23:57:19 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.
@@ -26,11 +26,12 @@ import org.apache.tapestry5.test.Tapestr
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
-import static java.lang.String.format;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
+import static java.lang.String.format;
+
/**
* This is used to test the template parser ... and in some cases, the underlying behavior of the SAX APIs.
*/
@@ -567,7 +568,7 @@ public class TemplateParserImplTest exte
@Test
public void expansions_with_maps()
{
- List<TemplateToken> tokens= tokens("expansions_with_maps.tml");
+ List<TemplateToken> tokens = tokens("expansions_with_maps.tml");
assertEquals(tokens.size(), 11);
@@ -592,9 +593,9 @@ public class TemplateParserImplTest exte
List<TemplateToken> tokens = tokens("expansions_with_whitespace.tml");
assertEquals(tokens.size(), 9);
-
+
ExpansionToken expansion = get(tokens, 2);
- assertEquals( expansion.getExpression(), "message:messagekey1");
+ assertEquals(expansion.getExpression(), "message:messagekey1");
}
@@ -681,55 +682,55 @@ public class TemplateParserImplTest exte
@DataProvider
public Object[][] parse_failure_data()
{
- return new Object[][] {
+ return new Object[][]{
- { "mixin_requires_id_or_type.tml",
+ {"mixin_requires_id_or_type.tml",
"You may not specify mixins for element <span> because it does not represent a component (which requires either an id attribute or a type attribute).",
- 2 },
+ 2},
- { "unexpected_attribute_in_parameter_element.tml",
+ {"unexpected_attribute_in_parameter_element.tml",
"Element <parameter> does not support an attribute named 'grok'. The only allowed attribute name is 'name'.",
- 4 },
+ 4},
- { "name_attribute_of_parameter_element_omitted.tml",
- "The name attribute of the <parameter> element must be specified.", 4 },
+ {"name_attribute_of_parameter_element_omitted.tml",
+ "The name attribute of the <parameter> element must be specified.", 4},
- { "name_attribute_of_parameter_element_blank.tml",
- "The name attribute of the <parameter> element must be specified.", 4 },
+ {"name_attribute_of_parameter_element_blank.tml",
+ "The name attribute of the <parameter> element must be specified.", 4},
- { "unexpected_attribute_in_block_element.tml",
+ {"unexpected_attribute_in_block_element.tml",
"Element <block> does not support an attribute named 'name'. The only allowed attribute name is 'id'.",
- 3 },
+ 3},
- { "parameter_namespace_with_attributes.tml",
- ServicesMessages.parameterElementDoesNotAllowAttributes(), 4 },
+ {"parameter_namespace_with_attributes.tml",
+ ServicesMessages.parameterElementDoesNotAllowAttributes(), 4},
- { "invalid_library_namespace_path.tml",
- "The path portion of library namespace URI 'tapestry-library:subfolder/' is not valid", 2 },
+ {"invalid_library_namespace_path.tml",
+ "The path portion of library namespace URI 'tapestry-library:subfolder/' is not valid", 2},
- { "content_within_body_element.tml", "Content inside a Tapestry body element is not allowed", 2 },
+ {"content_within_body_element.tml", "Content inside a Tapestry body element is not allowed", 2},
- { "nested_content_element.tml",
- "The <content> element may not be nested within another <content> element.", 3 },
+ {"nested_content_element.tml",
+ "The <content> element may not be nested within another <content> element.", 3},
- { "container_must_be_root.tml", "Element <container> is only valid as the root element of a template.",
- 3 },
+ {"container_must_be_root.tml", "Element <container> is only valid as the root element of a template.",
+ 3},
- { "extend_must_be_root.tml", "Element <extend> is only valid as the root element of a template.", 3 },
+ {"extend_must_be_root.tml", "Element <extend> is only valid as the root element of a template.", 3},
- { "replace_must_be_under_extend.tml",
- "The <replace> element may only appear directly within an extend element.", 3 },
+ {"replace_must_be_under_extend.tml",
+ "The <replace> element may only appear directly within an extend element.", 3},
- { "only_replace_within_extend.tml", "Child element of <extend> must be <replace>.", 2 },
+ {"only_replace_within_extend.tml", "Child element of <extend> must be <replace>.", 2},
- { "missing_id_in_replace_element.tml", "The <replace> element must have an id attribute.", 3 },
+ {"missing_id_in_replace_element.tml", "The <replace> element must have an id attribute.", 3},
- { "extension_point_must_have_id.tml", "The <extension-point> element must have an id attribute.", 3 },
+ {"extension_point_must_have_id.tml", "The <extension-point> element must have an id attribute.", 3},
- { "misplaced_parameter.tml", "Block parameters are only allowed directly within component elements.",
- 5 },
+ {"misplaced_parameter.tml", "Block parameters are only allowed directly within component elements.",
+ 5},
- { "parameter_namespace_element_deprecated.tml", "The <parameter> element has been deprecated in Tapestry 5.3 in favour of 'tapestry:parameter' namespace.", 4 },
+ {"parameter_namespace_element_deprecated.tml", "The <parameter> element has been deprecated in Tapestry 5.3 in favour of 'tapestry:parameter' namespace.", 4},
};
}
@@ -741,13 +742,12 @@ public class TemplateParserImplTest exte
{
parse(fileName);
unreachable();
- }
- catch (TapestryException ex)
+ } catch (TapestryException ex)
{
if (!ex.getMessage().contains(errorMessageSubstring))
{
throw new AssertionError(format("Message [%s] does not contain substring [%s].", ex.getMessage(),
- errorMessageSubstring));
+ errorMessageSubstring));
}
assertEquals(ex.getLocation().getLine(), expectedLine);
@@ -757,8 +757,8 @@ public class TemplateParserImplTest exte
@DataProvider
public Object[][] doctype_parsed_correctly_data()
{
- return new Object[][] { { "xhtml1_strict_doctype.tml" }, { "xhtml1_transitional_doctype.tml" },
- { "xhtml1_frameset_doctype.tml" } };
+ return new Object[][]{{"xhtml1_strict_doctype.tml"}, {"xhtml1_transitional_doctype.tml"},
+ {"xhtml1_frameset_doctype.tml"}};
}
@Test(dataProvider = "doctype_parsed_correctly_data")
@@ -773,28 +773,28 @@ public class TemplateParserImplTest exte
@DataProvider
public Object[][] doctype_token_added_correctly_data()
{
- return new Object[][] {
+ return new Object[][]{
- { "xhtml1_strict_doctype.tml", "html", "-//W3C//DTD XHTML 1.0 Strict//EN",
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" },
+ {"xhtml1_strict_doctype.tml", "html", "-//W3C//DTD XHTML 1.0 Strict//EN",
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"},
- { "xhtml1_transitional_doctype.tml", "html", "-//W3C//DTD XHTML 1.0 Transitional//EN",
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" },
+ {"xhtml1_transitional_doctype.tml", "html", "-//W3C//DTD XHTML 1.0 Transitional//EN",
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"},
- { "xhtml1_frameset_doctype.tml", "html", "-//W3C//DTD XHTML 1.0 Frameset//EN",
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd" },
+ {"xhtml1_frameset_doctype.tml", "html", "-//W3C//DTD XHTML 1.0 Frameset//EN",
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"},
- { "html4_strict_doctype.tml", "HTML", "-//W3C//DTD HTML 4.01//EN",
- "http://www.w3.org/TR/html4/strict.dtd" },
+ {"html4_strict_doctype.tml", "HTML", "-//W3C//DTD HTML 4.01//EN",
+ "http://www.w3.org/TR/html4/strict.dtd"},
- { "html4_transitional_doctype.tml", "HTML", "-//W3C//DTD HTML 4.01 Transitional//EN",
- "http://www.w3.org/TR/html4/loose.dtd" },
+ {"html4_transitional_doctype.tml", "HTML", "-//W3C//DTD HTML 4.01 Transitional//EN",
+ "http://www.w3.org/TR/html4/loose.dtd"},
- { "html4_frameset_doctype.tml", "HTML", "-//W3C//DTD HTML 4.01 Frameset//EN",
- "http://www.w3.org/TR/html4/frameset.dtd" },
+ {"html4_frameset_doctype.tml", "HTML", "-//W3C//DTD HTML 4.01 Frameset//EN",
+ "http://www.w3.org/TR/html4/frameset.dtd"},
- { "system_doctype.xml", "foo", null,
- "src/test/resources/org/apache/tapestry5/internal/services/simple.dtd" } };
+ {"system_doctype.xml", "foo", null,
+ "src/test/resources/org/apache/tapestry5/internal/services/simple.dtd"}};
}
@Test(dataProvider = "doctype_token_added_correctly_data")
@@ -816,8 +816,7 @@ public class TemplateParserImplTest exte
{
parse("invalid_component_id.tml");
unreachable();
- }
- catch (RuntimeException ex)
+ } catch (RuntimeException ex)
{
assertMessageContains(ex, "Component id 'not-valid' is not valid");
}
@@ -830,8 +829,7 @@ public class TemplateParserImplTest exte
{
parse("invalid_block_id.tml");
unreachable();
- }
- catch (RuntimeException ex)
+ } catch (RuntimeException ex)
{
assertMessageContains(ex, "Block id 'not-valid' is not valid");
}
@@ -956,4 +954,16 @@ public class TemplateParserImplTest exte
checkType(title, 2, TokenType.END_ELEMENT);
}
+
+ @Test
+ public void html5_with_entities() throws Exception
+ {
+ List<TemplateToken> tokens = tokens("html5_with_entities.tml");
+
+ assertEquals(tokens.size(), 5);
+
+ TextToken token3 = get(tokens, 3);
+
+ assertEquals(token3.getText(), "©2011 Apache");
+ }
}
Added: tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/internal/services/html5_with_entities.tml
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/internal/services/html5_with_entities.tml?rev=1174459&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/internal/services/html5_with_entities.tml (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/internal/services/html5_with_entities.tml Thu Sep 22 23:57:19 2011
@@ -0,0 +1,2 @@
+<!DOCTYPE html>
+<html>©2011 Apache</html>
\ No newline at end of file