Двухшаговая модель просмотра: XSLT против графов объектов - PullRequest
2 голосов
/ 21 июня 2009

Я намереваюсь реализовать паттерн Мартина Фаулера для рендеринга 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, как бы я проанализировал содержимое ценника?

Ответы [ 2 ]

3 голосов
/ 21 июня 2009

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

Я думаю, что это во многом зависит от технических деталей вашего процесса рендеринга, от того, хотите ли вы, чтобы это происходило на сервере или в браузере, насколько вам удобно с 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>
1 голос
/ 21 июня 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>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...