XSLT - это функциональный язык, и на любом функциональном языке значение переменной, одного набора, не может быть обновлено . Нужен «сдвиг парадигмы» - чтобы начать думать функционально - чтобы понять, что «способность» обновлять переменные вовсе не нужна. Для любого императивного алгоритма (который использует обновление переменной) существует соответствующий функциональный алгоритм (который не требует обновления какой-либо переменной).
Использование функционального стиля программирования по сравнению с императивным имеет ряд преимуществ - главное в том, что функциональную программу гораздо лучше читать, понимать, поддерживать и даже доказывать правильность. Поскольку переменные являются неизменяемыми, оптимизатор компилятора может выполнять гораздо более агрессивную оптимизацию, что приводит к более эффективным, высоко оптимизированным скомпилированным программам.
В этом конкретном случае нет необходимости обновлять переменную для получения необходимого количества :
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:w="w">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|@*">
<xsl:for-each select=
"//w:t
[contains(., 'Para8')
or
contains(., 'Para11')
]
">
<xsl:number level="any" count="w:tbl/w:tr"/>
<xsl:text>
</xsl:text>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Когда это преобразование применяется к предоставленному документу XML :
<w:document xmlns:w="w">
<w:body>
<w:p>
<w:r>
<w:t> Para1 </w:t>
</w:r>
</w:p>
<w:p>
<w:r>
<w:t> Para2 </w:t>
</w:r>
</w:p>
<w:p>
<w:r>
<w:t> Para3 </w:t>
</w:r>
</w:p>
<w:p>
<w:r>
<w:t> Para4 </w:t>
</w:r>
</w:p>
<w:p>
<w:r>
<w:t> Para5 </w:t>
</w:r>
</w:p>
<w:tbl>
<w:tr>
<w:tc>
<w:p>
<w:r>
<w:t> Para6 </w:t>
</w:r>
</w:p>
</w:tc>
<w:tc>
<w:p>
<w:r>
<w:t> Para7 </w:t>
</w:r>
</w:p>
</w:tc>
</w:tr>
</w:tbl>
<w:p>
<w:r>
<w:t> Para8 </w:t>
</w:r>
</w:p>
<w:tbl>
<w:tr>
<w:tc>
<w:p>
<w:r>
<w:t> Para9 </w:t>
</w:r>
</w:p>
</w:tc>
<w:tc>
<w:p>
<w:r>
<w:t> Para10 </w:t>
</w:r>
</w:p>
</w:tc>
</w:tr>
</w:tbl>
<w:p>
<w:r>
<w:t> Para11 </w:t>
</w:r>
</w:p>
</w:body>
</w:document>
желаемый, правильный результат получается :
1
2
В случае, если это значение должно содержаться в переменной - для последующего использования где-нибудь в ее области видимости, переменная будет просто определяться как :
<xsl:variable name="vMyCount">
<xsl:number level="any" count="w:tbl/w:tr"/>
</xsl:variable>
И вы можете использовать эту переменную как в приведенном ниже преобразовании:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:w="w">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|@*">
<xsl:for-each select=
"//w:t
[contains(., 'Para5')
or
contains(., 'Para8')
or
contains(., 'Para11')
]
">
<xsl:variable name="vMyCount">
<xsl:number level="any" count="w:tbl/w:tr"/>
</xsl:variable>
<xsl:value-of select=
"concat($vMyCount,
substring('0', 1 + boolean(string($vMyCount)))
)"/>
<xsl:text>
</xsl:text>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
выдаёт тот же правильный результат :
0
1
2