/ / Zastosowane szablony nie pasują do reguły z wieloma predykatami - xml, xslt, xpath, xslt-2.0

Zastosowane szablony nie pasują do reguły z wieloma predykatami - xml, xslt, xpath, xslt-2.0

Próbowałem skopiować węzeł i zmienić jego atrybuty. Zasadniczo chcę <parent id="1"> mieć również <child id="3"> i dodaj do niego atrybut, w tym dokumencie:

 <container>
<parent id="1">
<child id="1"/>
<child id="2"/>
</parent>
<parent id="2">
<child id="1"/>
<child id="2"/>
<child id="3" attrs="I am special"/>
</parent>
</container>

Powstały dokument wyglądałby następująco:

 <container>
<parent id="1">
<child id="1"/>
<child id="2"/>
<child id="3" attrs="I am special" cloned="I have been cloned"/>
</parent>
<parent id="2">
<child id="1"/>
<child id="2"/>
<child id="3" attrs="I am special"/>
</parent>
</container>

Aby skopiować dziecko, po prostu zaznaczam plik parent Chcę wypełnić i apply-templates z przedmiotem jego pragnienia, podobnie:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" indent="yes"/>

<!-- copy everything verbatim -->
<xsl:template match="@*|node()" name="identity">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>

<xsl:template match="parent[@id="1"]/child[last()]">
<xsl:call-template name="identity"/>
<xsl:apply-templates select="//*/child[@id="3"]"/>
</xsl:template>
</xsl:stylesheet>

Po zadbaniu o kopię próbowałem zmienić atrybut, ale bezskutecznie. Nic nigdy nie jest dopasowywane, a atrybut nie jest dodawany z następującym szablonem:

<xsl:template match="child[@id="3" and ../@id="1"]">
<xsl:apply-templates select="@*|node()" />
<xsl:attribute name="clone">I have been cloned</xsl:attribute>
</xsl:template>

Przy moim ograniczonym zrozumieniu XSLT zostałoby to wyzwolone podczas apply-templates, skopiowałoby węzły i dodał mój atrybut. Dane wyjściowe mówią inaczej: child id="3" zostanie skopiowany, ale bez znaku atrybutu.

Myślałem, że być może nowo dodany węzełnie był jeszcze "t" dostępny "lub coś w tym stylu, ale prosta reguła będzie do niego pasować (to nie jest dobre, ponieważ modyfikuje oryginalny węzeł, z którego kopiuję):

<xsl:template match="child[@id="3"]">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
<xsl:attribute name="att1">I have been cloned?!</xsl:attribute>
</xsl:copy>
</xsl:template>

Myślałem, że mogłem zepsuć predykat, ale dodanie atrybutu z podobnym predykatem (bez poprzedniej kopii) działa jak urok:

  <xsl:template match="child[@id="1" and ../@id="1"]">
<xsl:copy>
<xsl:attribute name="clone">Nope, just a normal kid</xsl:attribute>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>

Pomyślałem też, że mój szablon „kopiowania” mógł mieć wyższy priorytet, ale granie z priorytetem też nie pomogło.

Czy czegoś brakuje?

Odpowiedzi:

1 dla odpowiedzi № 1

Nowy element jest częścią drzewa wyników, nie można go dopasować w tym samym kroku transformacji. Sugerowałbym użycie trybu do zmiany przetwarzania elementu do dodania:

<?xml version="1.0" encoding="utf-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">

<xsl:template match="@*|node()" mode="#all">
<xsl:copy>
<xsl:apply-templates select="@*|node()" mode="#current"/>
</xsl:copy>
</xsl:template>

<xsl:template match="parent[@id="1"]/child[last()]">
<xsl:next-match/>
<xsl:apply-templates select="//*/child[@id="3"]" mode="add-att"/>
</xsl:template>

<xsl:template match="child[@id="3"]" mode="add-att">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:attribute name="att1">I have been cloned?!</xsl:attribute>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>

</xsl:transform>

Online w http://xsltransform.net/ncntCTd.