Я пытаюсь использовать XSLT для преобразования документа, помечая группу узлов XML целочисленными идентификаторами, начиная с 0 и увеличивая на единицу для каждого узла в группе. XML, переданный в таблицу стилей, должен быть отражен, но дополнен, чтобы включить эту дополнительную информацию.
Чтобы было ясно, о чем я говорю, вот как это преобразование будет выражаться с помощью DOM:
states = document.getElementsByTagName("state");
for( i = 0; i < states.length; i++){
states.stateNum = i;
}
Это очень просто с DOM, но у меня гораздо больше проблем с этим с XSLT. Текущая стратегия, которую я разработал, состояла в том, чтобы начать с преобразования идентификаторов, а затем создать глобальную переменную, которая выбирает и хранит все узлы, которые я хочу нумеровать. Затем я создаю шаблон, соответствующий этому виду узла. Таким образом, идея заключается в том, что в шаблоне я бы искал положение соответствующего узла в списке переменных глобальной переменной, что дало бы мне уникальный номер, который я мог бы затем установить в качестве атрибута.
Проблема с этим подходом состоит в том, что функция позиции может использоваться только с узлом контекста, поэтому что-то вроде следующего недопустимо:
<template match="state">
<variable name="stateId" select="@id"/>
<variable name="uniqueStateNum" select="$globalVariable[@id = $stateId]/position()"/>
</template>
То же самое верно для следующего:
<template match="state">
<variable name="stateId" select="@id"
<variable name="stateNum" select="position($globalVariable[@id = $stateId])/"/>
</template>
Чтобы использовать position () для поиска позиции элемента в $ globalVariable, необходимо изменить контекстный узел.
Я нашел решение, но оно крайне неоптимально. По сути, в шаблоне я использую for-each для перебора глобальной переменной. For-each изменяет узел контекста, поэтому это позволяет мне использовать position () так, как я описал. Проблема заключается в том, что это превращает то, что обычно является операцией O (n), в операцию O (n ^ 2), где n - длина списка узлов, поскольку для этого требуется выполнять итерацию по всему списку всякий раз, когда сопоставляется шаблон. Я думаю, что должно быть более элегантное решение.
В целом, вот моя текущая (немного упрощенная) таблица стилей xslt:
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:s="http://www.w3.org/2005/07/scxml"
xmlns="http://www.w3.org/2005/07/scxml"
xmlns:c="http://msdl.cs.mcgill.ca/"
version="1.0">
<xsl:output method="xml"/>
<!-- we copy them, so that we can use their positions as identifiers -->
<xsl:variable name="states" select="//s:state" />
<!-- identity transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="s:state">
<xsl:variable name="stateId">
<xsl:value-of select="@id"/>
</xsl:variable>
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:for-each select="$states">
<xsl:if test="@id = $stateId">
<xsl:attribute name="stateNum" namespace="http://msdl.cs.mcgill.ca/">
<xsl:value-of select="position()"/>
</xsl:attribute>
</xsl:if>
</xsl:for-each>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Буду признателен за любые советы. Спасибо.