Шаблон двухэтапного представления: 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="price":

<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, как бы я разобрал содержимое ценника?


person Joel    schedule 21.06.2009    source источник


Ответы (2)


Я не могу сказать много о том, почему вы должны пойти с одним или другим.

Я думаю, это сильно зависит от технических деталей вашего процесса рендеринга, хотите ли вы, чтобы это происходило на сервере или в браузере, насколько вам удобно работать с XSLT или, соответственно, с альтернативой XSLT.

Одной из особенностей для XSLT, безусловно, является то, что практически невозможно сгенерировать некорректный XML-выход (я не говорю о действительном). При написании строк легко что-то упустить.

Что касается вашей проблемы с синтаксическим анализом: без сомнения, лучший способ - разделить данные и формат прямо в 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>
person Tomalak    schedule 21.06.2009

Код, который вы предлагаете, имеет некоторые проблемы. Самый большой из них заключается в том, что вы жестко кодируете свой вывод, чтобы перейти к стандартному выходу, что затрудняет дополнительную постобработку. Это было бы нетрудно изменить, изменив метод рендеринга, чтобы он принимал поток вывода или запись.

Несмотря на это, то, что вы предлагаете, представляет собой тонну кода 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>
person Jherico    schedule 21.06.2009