Двухшаговая модель просмотра: XSLT против графов объектов
Вопрос
Я намереваюсь реализовать двухэтапный шаблон представления . для рендеринга HTML в веб-приложении, которое я пишу. Общая идея заключается в том, что вместо того, чтобы приложение выводило необработанный HTML, оно выводит собственный промежуточный XML, который затем преобразуется в HTML / CSS. Это имеет ряд преимуществ, включая уменьшение дублирования кода и более согласованный вывод.
Подход, предложенный Фаулером для преобразования XML в окончательный HTML, заключается в использовании XSLT.
Я раньше использовал XSLT и знаю основы. Однако мне интересно, каковы преимущества использования XSLT. Альтернативный подход, который я рассматриваю, выглядит следующим образом:
Вот пример выходных данных XML первого шага рендеринга:
<grid>
<headingRow>
<cell>Product</cell>
<cell>Price</cell>
</headingRow>
<row>
<cell>A product</cell>
<cell type="price">$54.95</cell>
</row>
</grid>
И желаемый конечный вывод HTML:
<table class="grid">
<tr>
<th>Product</th>
<th>Price</th>
</tr>
<tr>
<td>A product</td>
<td>
<span class="currency_symbol">$</span>
<span class="decimal_number">54.95</span>
</td>
</tr>
</table>
Подход, который я рассматриваю, будет иметь один объект для каждого тега.
class GridTag extends Tag {
...
public void render() {
System.out.println("<table class=\"grid\">");
foreach(Tag child: children) {
child.render();
}
System.out.println("</table>");
}
...
}
Объекты будут построены в дерево путем анализа XML. Метод render () будет вызываться на корневом узле. Мне особенно нравится этот подход, потому что он позволяет мне делать крутые вещи. В частности, если у меня есть тег ячейки, как указано выше, с атрибутом type = & Quot; price & Quot;:
<cell type="price">$54.95</price>
Связанный с ним класс Tag может анализировать содержимое тега, чтобы разделить символ валюты и числовое значение на отдельные теги HTML, чтобы обеспечить выравнивание символа валюты и десятичной точки, как в приведенном выше выводе HTML.
<td>
<span class="currency_symbol">$</span>
<span class="decimal_number">54.95</span>
</td>
Вопросы:
Должен ли я сделать это или я должен использовать XSLT? Какие преимущества использования XSLT я могу упустить? Если бы я использовал XSLT, как бы я проанализировал содержимое ценника?
Решение
Я не могу много сказать о том, почему вы должны идти с тем или другим. Р>
Я думаю, что это во многом зависит от технических деталей вашего процесса рендеринга, от того, хотите ли вы, чтобы это происходило на сервере или в браузере, насколько вам удобно с XSLT или, соответственно, альтернативой XSLT.
Одним из пунктов для XSLT, безусловно, является то, что практически невозможно генерировать вывод XML, который не является правильно сформированным (я не говорю о valid ). Легко что-то пропустить при написании строк.
Относительно вашей проблемы с синтаксическим анализом: без сомнения, лучший способ - разделить данные и формат прямо в XML. XSLT не для анализа, поэтому я не понимаю, почему ваш XML не может быть в этом формате с самого начала:
<cell type="price" symbol="$">54.95</cell>
Однако, если вы ничего не можете с этим поделать, XSLT позаботится об этом.
<xsl:template match="cell[@type='price']">
<td>
<xsl:variable name="vNonNumbers" select="translate(., '0123456789.', '')" />
<xsl:variable name="vTheNumbers" select="translate(., $vNonNumbers, '')" />
<span class="currency_symbol">
<xsl:value-of select="$vNonNumbers" />
</span>
<span class="decimal_number">
<xsl:value-of select="$vTheNumbers" />
</span>
</td>
</xsl:template>
Надеюсь, вы поймете, почему вышеприведенный код по сути плохой. Сравните с альтернативой (если ваш XML будет разделять данные и формат):
<xsl:template match="cell[@type='price']">
<td>
<span class="currency_symbol">
<xsl:value-of select="@symbol" />
</span>
<span class="decimal_number">
<xsl:value-of select="." />
</span>
</td>
</xsl:template>
Другие советы
Код, который вы предлагаете, имеет некоторые проблемы. Самое главное, что вы жестко программируете свой вывод, чтобы перейти к стандартному выводу, что затрудняет дополнительную постобработку. Это не составит труда изменить, изменив метод рендеринга так, чтобы он принимал выходной поток или модуль записи. Р>
Несмотря на это, вы предлагаете тонну Java-кода, который в основном будет реализовывать очень специфическое XSLT-преобразование. Вы намного лучше просто изучаете и используете XSLT для преобразования XML в HTML. Преимущество состоит в том, что XSLT - это инструмент общего назначения, предназначенный именно для этого вида преобразования. Р>
Вот пример XSLT, который почти делает то, что вы пытаетесь сделать. К сожалению, у меня кончились заботы о том времени, когда мне пришлось анализировать значение валюты в числовой и символической частях, но этого, безусловно, достаточно, чтобы начать работу. р>
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/grid">
<table class="grid">
<xsl:apply-templates select="headingRow"/>
<xsl:apply-templates select="row"/>
</table>
</xsl:template>
<xsl:template match="headingRow">
<tr>
<xsl:apply-templates select="cell" mode="heading"/>
</tr>
</xsl:template>
<xsl:template match="row">
<tr>
<xsl:apply-templates select="cell" mode="normal"/>
</tr>
</xsl:template>
<xsl:template match="cell" mode="heading">
<th><xsl:value-of select="."/></th>
</xsl:template>
<xsl:template match="cell" mode="normal">
<xsl:choose>
<xsl:when test="@type='price'">
<td>
<span class="currency_symbol">
<xsl:value-of select="." />
</span>
<span class="decimal_number">
<xsl:value-of select="." />
</span>
</td>
</xsl:when>
<xsl:otherwise>
<td>
<xsl:value-of select="." />
</td>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>