"Неправильное использование" <xsl: key> для проверки работоспособности

Я использую множество ключей, и иногда я помещаю в них проверки работоспособности, например:

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

Другой альтернативой может быть использование шаблонов вместо ключей. Я вижу два варианта здесь:

  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>

Здесь есть два недостатка:

  1. Требуется дополнительный шаблонный код. Если мы допустим ошибку, тесты не будут выполнены правильно, но мы не заметим. Нам нужно:
    • "преобразование идентичности" как шаблон
    • <xsl:apply-templates mode="sanity-check" select="node()|@*"/> в каждом шаблоне, содержащем более сложные тесты.
  2. Проблемы с перекрывающимися тестами, например, с match="A|B"другой с match="B|C"оба требуют некоторых <xsl:choose>/<xsl:if> решить, если нам нужно прекратить. Элемент <B> будет соответствовать только одному из шаблонов. С ключами не нужно беспокоиться о совпадении совпадений.

0 ответов

Другие вопросы по тегам