2段階表示パターン:XSLTとオブジェクトグラフ
質問
Martin Fowlerの 2段階表示パターンを実装する予定です 私が書いているWebアプリケーションでHTMLをレンダリングするため。一般的な考え方は、アプリケーションに生のHTMLを出力させるのではなく、カスタムの中間XMLを出力してから、HTML / CSSに変換するというものです。これには、コードの重複が少なくなり、出力の一貫性が向上するなど、多くの利点があります。
XMLを最終的なHTMLに変換するためにFowlerが提案したアプローチは、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>
検討しているアプローチでは、タグごとに1つのオブジェクトがあります。
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の 1つのポイントは、整形式でない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>
他のヒント
提案しているコードにはいくつかの問題があります。最大のものは、標準出力に出力するために出力をハードコーディングすることです。これにより、追加の後処理を行うことが難しくなります。これは、出力ストリームまたはライターを受け入れるようにrenderメソッドを変更することで変更するのは難しくありません。
とにかく、あなたが提案しているのは、基本的に非常に特定のXSLT変換を実装するJavaコードのトンです。 XSLTを学習して使用し、XMLをHTMLに変換するだけの方がはるかに優れています。利点は、XSLTがまさにこの種の変換のために設計された汎用ツールであることです。
これは、あなたがやろうとしていることをほとんど行うXSLTの例です。残念ながら、通貨値を数値部分と記号部分に解析しなければならなかった頃に cares を使い果たしましたが、これは確かにあなたが始めるのに十分です。
<?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>