Как можно оптимизировать тест XPath не (previous-sibling :: sect1) для проверки, является ли это первым дочерним элементом sect1? - PullRequest
1 голос
/ 27 августа 2010

Я разрабатываю таблицу стилей XSLT 1.0 (и применяю ее, используя xsltproc ).Один из шаблонов в моем скрипте должен выполнить некоторую специальную обработку для первого элемента <sect1> в данном родительском узле, а некоторые - для последнего элемента <sect1>.Прямо сейчас эта специальная обработка реализована так:

<xsl:template match="sect1">
  <xsl:if test="not(preceding-sibling::sect1)">
    <!-- Special handling for first sect1 element goes here. -->
  </xsl:if>
  <!-- Common handling for all sect1 elements goes here. -->
  <xsl:if test="not(following-sibling::sect1)">
    <!-- Special handling for last sect1 element goes here. -->
  </xsl:if>
</xsl:template>

Мне было интересно (просто из любопытства, скорость выполнения скрипта мне подходит): есть ли более эффективный способ сделать это?Возможно ли, что процессор XSLT прекратит сборку набора узлов preceding-sibling::sect1 после первого найденного совпадения, потому что он знает, что ему просто нужно найти один или ноль элементов?

Ответы [ 3 ]

1 голос
/ 27 августа 2010

Если предположить, что контекст, в котором вызывается шаблон, является выбором дочернего узла , тогда я предлагаю следующее.Если контекст, в который они были вызваны, был через другую ось (скажем, предшествующий брат или родительский элемент), то путь к нему лучше всего подходит.

Две возможности - упростить тесты или заменить их другими шаблонами.:

Упрощенные тесты:

<xsl:template match="sect1">
  <xsl:if test="position() = 1">
    <!-- Special handling for first sect1 element goes here. -->
  </xsl:if>
  <!-- Common handling for all sect1 elements goes here. -->
  <xsl:if test="position() = last()">
    <!-- Special handling for last sect1 element goes here. -->
  </xsl:if>
</xsl:template>

Различные шаблоны:

<xsl:template name="handleSect1">
  <!-- Common handling for all sect1 elements goes here. -->
<xsl:template>
<xsl:template match="sect1">
  <xsl:call-template name="handleSect1"/>
</xsl:template>
<xsl:template match="sect1[1]">
  <!-- Special handling for first sect1 element goes here. -->
  <xsl:call-template name="handleSect1"/>
</xsl:template>
<xsl:template match="sect1[last()]">
  <xsl:call-template name="handleSect1"/>
  <!-- Special handling for last sect1 element goes here. -->
</xsl:template>
<xsl:template match="sect1[position() = 1 and position() = last()]">
  <!-- Special handling for first sect1 element goes here. -->
  <xsl:call-template name="handleSect1"/>
  <!-- Special handling for last sect1 element goes here. -->
</xsl:template>

Поскольку вы говорите "оптимизировать", я предполагаю, что вы заботитесь о том, что будет обрабатываться быстрее.Он будет варьироваться в зависимости от процессора xslt, режимов обработки (в некоторых есть опция «компилировать», и это будет влиять на более эффективную) и входного XML.Самым быстрым может быть либо один из них, либо ваш исходный.

Действительно, каждый из них должен быть столь же эффективным, как и другой, разница состоит в том, что процессору удается оптимизировать.

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

1 голос
/ 04 сентября 2010

Вероятно ли, что процессор XSLT прекратит сборку набора узлов предыдущий-sibling :: sect1 после первого найденного совпадения, потому что знает, что ему просто нужно найти один или ноль элементов?

Я не знаю о xsltproc, но Саксон очень хорош в такого рода оптимизации.Я считаю, что он будет проверять только первое найденное совпадение, потому что ему нужно только знать, пуст ли набор узлов или нет.

Однако вы всегда можете убедиться, изменив свои тесты следующим образом:

  <xsl:if test="not(preceding-sibling::sect1[1])">

и

  <xsl:if test="not(following-sibling::sect1[1])">

, поскольку это будет проверять только для первого брата по каждой оси,Обратите внимание, что [1] в каждом случае относится к порядку шага XPath, который является порядком оси, а не обязательно порядком документа.Таким образом, preceding-sibling::sect1[1] относится к брату sect1, непосредственно предшествующему текущему элементу, а не к первому брату sect1 в порядке документа.Потому что направление оси preceding-sibling обратное.

0 голосов
/ 27 августа 2010

Я думаю, вы просто должны быть в состоянии сделать

  <xsl:if test="position() = 1">
    <!-- Special handling for first sect1 element goes here. -->
  </xsl:if>
  <!-- Common handling for all sect1 elements goes here. -->
  <xsl:if test="position() = last()">
    <!-- Special handling for last sect1 element goes here. -->
  </xsl:if>

, поскольку position() и last() являются контекстно-зависимыми.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...