Подтвердить что ты не робот

XHTML Базовая поддержка Thymeleaf?

Я пытаюсь получить 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 не распознает doctype.

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 предоставляется вами диалектом (index: 1)


Настройка

Я просмотрел документацию расширений Thymeleaf и исходный код и используя это как отправную точку, определил новый диалект, наследующий от 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" добавлялись примерно к каждому элементу. Также в элемент <html> добавлен атрибут version="-//W3C//DTD XHTML Basic 1.1//EN".

Я делаю что-то неправильно, мне нужно настроить что-то по-другому или я что-то упустил из пользовательского диалекта?

4b9b3361

Ответ 1

Ну, у меня нет "канонических" доказательств того, что базовые шаблоны XHTML не могут обрабатываться так, как вы хотите, с Thymeleaf 2.x, и, вероятно, есть способ, который дает достаточно усилий. Но я видел это:

Это, наряду с моей собственной борьбой за то, чтобы что-то работать, заставляет меня поверить, что обработка XHTML в Thymeleaf 2.X никогда не была полностью испечена. Тем не менее, он, кажется, отлично работает в версии 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>

Я опубликовал полный рабочий пример github.