两步视图模式:XSLT与对象图

时间:2009-06-21 05:35:35

标签: html xml xslt xhtml view

我打算实施Martin Fowler的Two-Step View Pattern  用于在我正在编写的Web应用程序中呈现HTML。一般的想法是,它不是让应用程序输出原始HTML,而是输出一个自定义中间XML,然后转换为HTML / CSS。这有许多优点,包括减少代码重复和更一致的输出。

Fowler建议将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()方法将在根节点上调用。我特别喜欢这种方法,因为它可以让我做很酷的事情。特别是,如果我有一个上面的单元格标签,属性类型=“价格”:

<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 个答案:

答案 0 :(得分:3)

我真的不能说你为什么要选择其中一个。

我认为这在很大程度上取决于渲染过程的技术细节,无论您是希望它在服务器上还是在浏览器上发生,您对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>

答案 1 :(得分:1)

您提出的代码存在一些问题。最大的问题是你很难对输出进行标准输出,这使得进行额外的后期处理变得更加困难。通过修改render方法以接受输出流或writer,这不难改变。

无论如何,你提出的是大量的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>