Первый элемент title
в документе выбирается с помощью :
(//title)[1]
Многие ошибочно полагают, что //title[1]
выбирает первый title
в документе, и это часто совершаемая ошибка. //title[1]
выбирает каждый title
элемент, который является первым title
дочерним элементом его родителя, а не того, что здесь требуется.
Используя это, следующее преобразование производит требуемый вывод :
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match=
"title[count(.|((//title)[1])) = 1]">
<PageTitle>
<xsl:apply-templates />
</PageTitle>
</xsl:template>
</xsl:stylesheet>
При применении к этому документу XML :
<t>
<a>
<b>
<title>Page Title</title>
</b>
</a>
<b>
<title/>
</b>
<c>
<title/>
</c>
</t>
желаемый результат получен :
<t>
<a>
<b>
<PageTitle>Page Title</PageTitle>
</b>
</a>
<b>
<title />
</b>
<c>
<title />
</c>
</t>
Обратите внимание, как мы используем известный метод Кейса пересечения множеств в XPath 1.0 :
Если есть два набора узлов $ns1
и $ns2
, следующее выражение выбирает каждый узел, который принадлежит как $ns1
, так и $ns2
:
$ns1[count(.|$ns2) = count($ns2)]
В конкретном случае, когда оба набора узлов содержат только один узел , и один из них является текущим узлом, следующее выражение оценивается как true()
точно, когда два узла идентичны:
count(.|$ns2) = 1
Вариант этого используется в шаблоне совпадения шаблона, который переопределяет правило идентификации:
title[count(.|((//title)[1])) = 1]
соответствует только первому элементу title
в документе.