Я разрабатываю таблицу стилей XSLT 1.0 (и применяю ее с помощью xsltproc). Один из шаблонов моего скрипта должен выполнять некоторую специальную обработку для первого
элемента в данном родительском узле и некоторую для последнего
элемента. Сейчас эта специальная обработка реализована следующим образом:
<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
после первого найденного совпадения, потому что он знает, что ему нужно найти только один или ноль элементов?
Предполагая, что контекст, в котором вызывается шаблон, является выбором дочернего узла, тогда я предлагаю следующее. Если контекст, в котором они были вызваны, был через другую ось (скажем, предыдущий брат или предок), то способ приблизиться к нему лучше всего.
Есть две возможности упростить тесты или заменить их другими шаблонами:
Более простые тесты:
<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. Самым быстрым может быть любой из них или ваш оригинал.
На самом деле, каждый из них должен быть столь же эффективным, как и другой, разница заключается в оптимизации, которую процессор может сделать.
В данном случае я бы предпочел первый вариант ответа, так как он наиболее лаконичен, но если бы мне не нужно было использовать общую обработку для всех 4 случаев, я бы предпочел подход во втором ответе, который затем четко отмечает различные подходы для каждого случая.
Я думаю, вы должны уметь это делать
<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()
являются контекстно-зависимыми.