Используйте
.//*[@auto and $tempId = ancestor::*[@auto][1]/@tempId]
При этом выбираются все элементы-потомки (узла контекста), которые имеют атрибут auto
и чей первый предок, имеющий атрибут auto
, также имеет атрибут tempId
с тем же значением, что и у атрибута tempId
узла контекста (последний хранится в переменной $tempId
).
Здесь мы предполагаем, что никакие два разных элемента не имеют одинакового значения своих атрибутов tempId
.
Быстрая проверка на основе XSLT :
<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="a">
<xsl:variable name="tempId" select="@tempId"/>
<xsl:copy-of select=
".//*[@auto and $tempId = ancestor::*[@auto][1]/@tempId]"/>
</xsl:template>
</xsl:stylesheet>
Когда это преобразование применяется к предоставленному документу XML :
<root>
<a auto="1" tempId="current">
<b>
<c auto="1">
<d auto="1"></d>
</c>
</b>
<e auto="1">
<f>
<g auto="1"></g>
</f>
</e>
</a>
</root>
желаемый, правильный результат (два элемента c
и e
) получается :
<c auto="1">
<d auto="1"/>
</c>
<e auto="1">
<f>
<g auto="1"/>
</f>
</e>
Производительность не может быть улучшена только в выражении XPath , а неэффективность связана с необходимостью использования псевдооператора //
XPath.
При использовании XSLT можно получить эффективное решение, используя клавиши :
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="kfirstDescendents" match="*[@auto]"
use="generate-id(ancestor::*[@auto][1])"/>
<xsl:template match="a">
<xsl:copy-of select=
"key('kfirstDescendents', generate-id())"/>
</xsl:template>
</xsl:stylesheet>
Это преобразование дает тот же результат, что и первое, и значительно быстрее для документов со многими вложенными элементами, имеющими атрибут auto
.
Если использование XSLT абсолютно исключено, можно добиться того же эффекта, что и ключи XSLT, с использованием хеш-таблиц (извините, PHP не знаю).