Thymeleaf 的 XHTML 基本支持?
Posted
技术标签:
【中文标题】Thymeleaf 的 XHTML 基本支持?【英文标题】:XHTML Basic support for Thymeleaf? 【发布时间】:2016-11-15 04:18:56 【问题描述】:我正在尝试让 Spring 4.1.9 和 Thymeleaf 2.1.5 呈现 Xhtml Basic 1.1 页面,它们具有以下序言:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN"
"http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
仅在模板中使用它是行不通的,因为 Thymeleaf 无法识别文档类型。
org.thymeleaf.exceptions.TemplateProcessingException:使用 PUBLICID“-//W3C//DTD XHTML Basic 1.1//EN”和 SYSTEMID“http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd”请求的不受支持的实体。确保您的方言提供了相应的 org.thymeleaf.doctype.resolution.IDocTypeResolutionEntry 实现(索引:1)
设置
我浏览了 Thymeleaf extension documentation 和 source code 并以此为起点,定义了一个继承自 SpringStandardDialect 的新方言。我通过反复试验找出了缺少的模块,从 w3.org 下载它们并将它们添加到我的项目的资源目录中:
XhtmlBasicDialect.java
import java.util.LinkedHashSet;
import java.util.Set;
import org.thymeleaf.doctype.DocTypeIdentifier;
import org.thymeleaf.doctype.resolution.ClassLoaderDocTypeResolutionEntry;
import org.thymeleaf.doctype.resolution.IDocTypeResolutionEntry;
import org.thymeleaf.spring4.dialect.SpringStandardDialect;
public class XhtmlBasicDialect extends SpringStandardDialect
private static final String DTD_STANDARD_PATH = "org/thymeleaf/dtd/standard/";
private static final DocTypeIdentifier XHTML_BASIC_11_PUBLICID = DocTypeIdentifier.forValue("-//W3C//DTD XHTML Basic 1.1//EN");
private static final DocTypeIdentifier XHTML_BASIC_11_SYSTEMID = DocTypeIdentifier.forValue("http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd");
private static final DocTypeIdentifier ENTITIES_XHTML_BASIC_11_DOCUMENT_MODEL_1_PUBLICID = DocTypeIdentifier.forValue("-//W3C//ENTITIES XHTML Basic 1.1 Document Model 1.0//EN");
private static final DocTypeIdentifier ELEMENTS_XHTML_BASIC_TABLES_1_PUBLICID = DocTypeIdentifier.forValue("-//W3C//ELEMENTS XHTML Basic Tables 1.0//EN");
private static final DocTypeIdentifier ELEMENTS_XHTML_INPUTMODE_1_PUBLICID = DocTypeIdentifier.forValue("-//W3C//ELEMENTS XHTML Inputmode 1.0//EN");
private static final DocTypeIdentifier ELEMENTS_XHTML_TARGET_1_PUBLICID = DocTypeIdentifier.forValue("-//W3C//ELEMENTS XHTML Target 1.0//EN");
private static final IDocTypeResolutionEntry XHTML_BASIC_STRICT_DOC_TYPE_RESOLUTION_ENTRY = new ClassLoaderDocTypeResolutionEntry(XHTML_BASIC_11_PUBLICID, XHTML_BASIC_11_SYSTEMID, DTD_STANDARD_PATH + "xhtml-basic11.dtd");
private static final IDocTypeResolutionEntry ENTITIES_XHTML_BASIC_11_DOCUMENT_MODEL_1_DOC_TYPE_RESOLUTION_ENTRY = new ClassLoaderDocTypeResolutionEntry(ENTITIES_XHTML_BASIC_11_DOCUMENT_MODEL_1_PUBLICID, DocTypeIdentifier.ANY, DTD_STANDARD_PATH + "xhtml-basic11-model-1.mod");
private static final IDocTypeResolutionEntry ELEMENTS_XHTML_BASIC_TABLES_1_DOC_TYPE_RESOLUTION_ENTRY = new ClassLoaderDocTypeResolutionEntry(ELEMENTS_XHTML_BASIC_TABLES_1_PUBLICID, DocTypeIdentifier.ANY, DTD_STANDARD_PATH + "xhtml-basic-table-1.mod");
private static final IDocTypeResolutionEntry ELEMENTS_XHTML_INPUTMODE_1_DOC_TYPE_RESOLUTION_ENTRY = new ClassLoaderDocTypeResolutionEntry(ELEMENTS_XHTML_INPUTMODE_1_PUBLICID, DocTypeIdentifier.ANY, DTD_STANDARD_PATH + "xhtml-inputmode-1.mod");
private static final IDocTypeResolutionEntry ELEMENTS_XHTML_TARGET_1_DOC_TYPE_RESOLUTION_ENTRY = new ClassLoaderDocTypeResolutionEntry(ELEMENTS_XHTML_TARGET_1_PUBLICID, DocTypeIdentifier.ANY, DTD_STANDARD_PATH + "xhtml-target-1.mod");
@Override
protected Set<IDocTypeResolutionEntry> getAdditionalDocTypeResolutionEntries()
final Set<IDocTypeResolutionEntry> docTypeResolutionEntries = new LinkedHashSet<IDocTypeResolutionEntry>();
docTypeResolutionEntries.add(XHTML_BASIC_STRICT_DOC_TYPE_RESOLUTION_ENTRY);
docTypeResolutionEntries.add(ENTITIES_XHTML_BASIC_11_DOCUMENT_MODEL_1_DOC_TYPE_RESOLUTION_ENTRY);
docTypeResolutionEntries.add(ELEMENTS_XHTML_BASIC_TABLES_1_DOC_TYPE_RESOLUTION_ENTRY);
docTypeResolutionEntries.add(ELEMENTS_XHTML_INPUTMODE_1_DOC_TYPE_RESOLUTION_ENTRY);
docTypeResolutionEntries.add(ELEMENTS_XHTML_TARGET_1_DOC_TYPE_RESOLUTION_ENTRY);
return docTypeResolutionEntries;
我配置自定义方言如下:
mvc-config.xml
...
<bean id="templateResolver" class="org.thymeleaf.templateresolver.ServletContextTemplateResolver">
<property name="prefix" value="/WEB-INF/templates/" />
<property name="suffix" value=".xhtml" />
<property name="characterEncoding" value="UTF-8" />
<property name="templateMode" value="XHTML" />
<property name="xhtmlTemplateModePatterns" value="*.xhtml" />
</bean>
<bean id="templateEngine" class="org.thymeleaf.spring4.SpringTemplateEngine">
<property name="templateResolver" ref="templateResolver" />
<property name="additionalDialects">
<set>
<bean class="demo.XhtmlBasicDialect" />
</set>
</property>
</bean>
<bean id="xhtmlViewResolver" class="org.thymeleaf.spring4.view.ThymeleafViewResolver">
<property name="templateEngine" ref="templateEngine" />
<property name="characterEncoding" value="UTF-8" />
<property name="contentType" value="application/xhtml+xml" />
</bean>
...
我的模板如下:
DemoTemplate.xhtml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN"
"http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<title>Demo</title>
<link th:href="$'style' + '.css'" rel="stylesheet" type="text/css"/>
</head>
<body>
<div>
<p>Demo content</p>
</div>
</body>
</html>
问题
乍一看,这似乎很好,只是生成的 XHTML 缺少 XML 标头,并且有几个额外的属性添加到每个元素。
渲染输出:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="-//W3C//DTD XHTML Basic 1.1//EN">
<head xmlns="http://www.w3.org/1999/xhtml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<title xmlns="http://www.w3.org/1999/xhtml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Demo</title>
<link rel="stylesheet" type="text/css" xmlns="http://www.w3.org/1999/xhtml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xml:space="preserve" href="style.css" />
</head>
<body xmlns="http://www.w3.org/1999/xhtml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xml:space="preserve">
<div xmlns="http://www.w3.org/1999/xhtml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xml:space="preserve">
<p xmlns="http://www.w3.org/1999/xhtml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xml:space="preserve">Demo content</p>
</div>
</body>
</html>
这与 XHTML Basic preamable 不太匹配;一方面,我想保留 XML 声明 <?xml version="1.0" encoding="utf-8"?>
更重要的是,我不希望几乎每个元素都添加xmlns="http://www.w3.org/1999/xhtml"
、xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
和xml:space="preserve"
属性。还有一个version="-//W3C//DTD XHTML Basic 1.1//EN"
属性添加到<html>
元素。
我是不是做错了什么,我需要进行不同的配置,还是我在自定义方言中遗漏了一些东西?
【问题讨论】:
同意这么令人沮丧。 【参考方案1】:好吧,我没有“规范的”证据表明 XHTML Basic 模板不能按照您希望的方式使用 Thymeleaf 2.x 进行处理,并且可能有一种方法可以通过足够的努力。但我确实看到了:
Thymeleaf 2.1 中的XhtmlAndHtml5NonValidatingSAXTemplateParser
看起来很可疑,在 Thymeleaf 3.0 中不再存在
XHTML TemplateMode
和 xhtmlTemplateModePatterns
现已弃用
所有parsing code in 2.1 在3.0 中都是rewritten
这一点,加上我自己努力让某件事情发挥作用,让我相信 Thymeleaf 2.X 中的 XHTML 处理从未完全成熟。然而,它似乎在 3.0 中工作得很好,没有特别的努力。只需配置一个ViewResolver
,如下:
<bean id="viewResolver" class="org.thymeleaf.spring4.view.ThymeleafViewResolver">
<property name="characterEncoding" value="UTF-8"/>
<property name="templateEngine">
<bean class="org.thymeleaf.spring4.SpringTemplateEngine">
<property name="enableSpringELCompiler" value="true"/>
<property name="templateResolver">
<bean class="org.thymeleaf.spring4.templateresolver.SpringResourceTemplateResolver">
<property name="prefix" value="/WEB-INF/templates/"/>
<property name="suffix" value=".xhtml"/>
<property name="templateMode" value="XML"/>
</bean>
</property>
</bean>
</property>
</bean>
我发了complete working example on github。
【讨论】:
以上是关于Thymeleaf 的 XHTML 基本支持?的主要内容,如果未能解决你的问题,请参考以下文章