Двухшаговая модель просмотра: XSLT против графов объектов

StackOverflow https://stackoverflow.com/questions/1023281

  •  06-07-2019
  •  | 
  •  

Вопрос

Я намереваюсь реализовать двухэтапный шаблон представления .  для рендеринга 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>
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top