0

私は非常に多くのキーを使用していることに気づき、時には次のようなサニティ チェックを入れます。

<xsl:key name="foo-with-bar" match="foo[contains(., 'bar')]">
  <xsl:if test="@baz='xyz'">
    <xsl:message terminate="yes">
      Can't handle &lt;foo> containing "bar" if @baz="xyz"
    </xsl:message>
  </xsl:if>
  <xsl:value-of select="generate-id()"/>
</xsl:key>

(これは実際には非常に単純なテストです。実際のテストは非常に複雑になる可能性があります。) そのため、実際にはキーが必要なく、サニティ チェックのみが必要な場合にキーを使用しないのはなぜでしょうか? 例えば:

<xsl:key name="sanity-check" match="foo[contains(., 'bar')][@baz='xyz']">
  <xsl:message terminate="yes">
    Can't handle &lt;foo> containing "bar" if @baz="xyz"
  </xsl:message>
</xsl:key>

キーを実際に使用しない限り、Saxon は終了しないことに気付きました。

<xsl:template match="/">
  <xsl:apply-templates select="key('sanity-check', '')"/>
  <xsl:copy-of select="."/>
</xsl:template>

しかし、XSLT プロセッサが実際にこのパターンで終了することを確信できますか? これは、キーが使用されるように設計された方法ではないと思います。

背景: 魅力的でない代替案 (tl;dr の場合は無視してください)

Schematron がこのアプローチの代わりになる可能性があることは認識していますが、これらのテストはドキュメントの有効性ではなく、スタイルシートがドキュメントを処理できるかどうかに関するものであるため、スタイルシート自体によって実装されるテストは非常に魅力的です。

別の方法として、キーの代わりにテンプレートを使用することもできます。ここに 2 つのオプションがあります。

  1. テストと終了のテンプレートは、通常の処理中に「通常の」テンプレートを無効にします。ただし、通常の処理中に、テストする必要があるすべてのノードが、却下可能なテンプレート マッチによって必ずしも処理されるわけではありません。
  2. 次のように、テンプレートを使用して別のテストを実行します。

    <xsl:template match="/">
      <xsl:apply-templates mode="sanity-check"/>
      <xsl:apply-templates mode="actual-processing"/>
    </xsl:template>
    
    <xsl:template match="node()|@*" mode="sanity-check">
      <xsl:apply-templates select="node()|@*" mode="sanity-check"/>
    </xsl:template>
    
    <xsl:template mode="sanity-check" match="foo[contains(., 'bar')][@baz='xyz']">
      <xsl:message terminate="yes">
        foo containing bar can't have @baz set to xyz
      </xsl:message>
    </xsl:template>
    

単純なパターンでは表現できないより複雑なチェックが追加の労力なしで可能になるため、キーにはまだ利点があります。テンプレートを使用すると、次のような構成が必要になります。

<xsl:template mode="sanity-check" match="foo">
  <xsl:variable name="variable" select="some-complicated-expression"/>
  <xsl:if test="some-test-requiring[$variable=@bar]">
    <xsl:message terminate="yes">
      Fail!
    </xsl:message>
  </xsl:if>
  <xsl:apply-templates mode="sanity-check" select="node()|@*"/>
</xsl:template>

ここには 2 つの欠点があります。

  1. より多くのボイラープレート コードが必要です。そこを間違えると、テストが正しく実行されませんが、気が付きません。必要なもの:
    • テンプレートのような「恒等変換」
    • <xsl:apply-templates mode="sanity-check" select="node()|@*"/>より複雑なテストを含む各テンプレートで。
  2. オーバーラップするテストの問題。たとえば、1 つがmatch="A|B"、もう 1 つが でmatch="B|C"、どちらも<xsl:choose>/<xsl:if>を終了する必要があるかどうかを判断する必要があります。要素<B>はテンプレートの 1 つにのみ一致します。キーを使用すると、一致が重複することを心配する必要はありません。
4

0 に答える 0