Использование этого исходного документа:
<?xml version="1.0" encoding="UTF-8"?>
<Root>
<Element1 id="UniqueId1">
<SubElement1/>
<SubElement2>
<LeafElement1/>
<LeafElement1/>
</SubElement2>
</Element1>
<Element2 id="UniqueId2" AttributeToCheck="true">
<SubElement1>
<LeafElement1/>
<LeafElement1/>
</SubElement1>
</Element2>
</Root>
Я хочу добавить атрибут foo = "bar" к элементам, которые оба:
- Иметь одноуровневые элементы с одинаковым именем
- У любого предка с атрибутом AttributeToCheck
Это должен быть результат:
<?xml version="1.0"?>
<Root>
<Element1 id="UniqueId1">
<SubElement1/>
<SubElement2>
<LeafElement1/>
<LeafElement1/>
</SubElement2>
</Element1>
<Element2 id="UniqueId2" AttributeToCheck="true">
<SubElement1>
<LeafElement1 foo="bar"/>
<LeafElement1 foo="bar"/>
</SubElement1>
</Element2>
</Root>
Это моя таблица. Он добавляет элементы атрибута, соответствующие условию 1, но не учитывает условие 2.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" indent="yes"/>
<xsl:template match="* | @*">
<xsl:copy>
<xsl:apply-templates select="* | @*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[count(../*[name(.) = name(current())]) > 1]">
<xsl:copy>
<xsl:attribute name="foo">bar</xsl:attribute>
<xsl:apply-templates select="* | @*"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Неверный вывод:
<?xml version="1.0"?>
<Root>
<Element1 id="UniqueId1">
<SubElement1/>
<SubElement2>
<LeafElement1 foo="bar"/> (incorrect)
<LeafElement1 foo="bar"/> (incorrect)
</SubElement2>
</Element1>
<Element2 id="UniqueId2" AttributeToCheck="true">
<SubElement1>
<LeafElement1 foo="bar"/> (correct)
<LeafElement1 foo="bar"/> (correct)
</SubElement1>
</Element2>
</Root>
Поскольку второй шаблон уже правильно соответствует элементам, у которых есть братья и сестры с одинаковыми именами, должно быть легко использовать ось предка XPath для исключения элементов без предков AttributeToCheck. Я добавил еще один предикат ко второму шаблону.
<xsl:template match="*[ancestor::*[@AttributeToCheck]][count(../*[name(.) = name(current())]) > 1]">
Когда я применяю эту таблицу стилей, выходной документ совпадает с входным документом, показывая, что второй шаблон не соответствует никаким элементам. Я также попытался изменить новый предикат, чтобы использовать количество узлов.
<xsl:template match="*[count(ancestor::*[@AttributeToCheck]) > 0][count(../*[name(.) = name(current())]) > 1]">
Это также не сработало, выходной документ был таким же, как входной документ. Это удивительно, потому что, когда я использую это выражение предка для вывода имени узлов с AttributeToCheck, это работает. Я внес эти изменения в таблицу:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" indent="yes"/>
<xsl:template match="* | @*">
<xsl:copy>
<xsl:apply-templates select="* | @*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[count(../*[name(.) = name(current())]) > 1]">
<xsl:copy>
<xsl:attribute name="foo">bar</xsl:attribute>
<xsl:attribute name="AncestorCount">
<xsl:value-of select="count(ancestor::*[@AttributeToCheck])"/>
</xsl:attribute>
<xsl:attribute name="AncestorName">
<xsl:value-of select="name(ancestor::*[@AttributeToCheck])"/>
</xsl:attribute>
<xsl:apply-templates select="* | @*"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Производит этот вывод:
<?xml version="1.0"?>
<Root>
<Element1 id="UniqueId1">
<SubElement1/>
<SubElement2>
<LeafElement1 foo="bar" AncestorCount="0" AncestorName=""/>
<LeafElement1 foo="bar" AncestorCount="0" AncestorName=""/>
</SubElement2>
</Element1>
<Element2 id="UniqueId2" AttributeToCheck="true">
<SubElement1>
<LeafElement1 foo="bar" AncestorCount="1" AncestorName="Element2"/>
<LeafElement1 foo="bar" AncestorCount="1" AncestorName="Element2"/>
</SubElement1>
</Element2>
</Root>
Мой вопрос: почему предикат XPath *[ancestor::*[@AttributeToCheck]][count(../*[name(.) = name(current())]) > 1]
не соответствует элементам, соответствующим условиям 1 и 2? Какое выражение XPath я должен использовать вместо этого?