2016-04-18 21 views
0

mit dem folgenden XML-Dokument mit:Auswahl der ersten Elemente der Elementgruppen XSLT 1.0

<foo> 
    <bar> 
    <type>1</type> 
    <id>1</id> 
    <a1>0</a1> 
    <other_stuff/> 
    </bar> 
    <bar> 
    <type>1</type> 
    <id>1</id> 
    <a1>0</a1> 
    <other_stuff/> 
    </bar> 
    <bar> 
    <type>1</type> 
    <id>2</id> 
    <a1>0</a1> 
    <other_stuff/> 
    </bar> 
    <bar> 
    <type>1</type> 
    <id>2</id> 
    <a1>0</a1> 
    <other_stuff/> 
    </bar> 
</foo> 

Die XML-Elemente bar Listenelemente sind, logisch nach Typ und ID gruppiert. Das Beispieldokument enthält daher zwei geordnete Listen (Typ = 1 und ID = 1 und Typ = 1 und ID = 2) mit jeweils zwei Elementen. Im realen Dokument gibt es viel mehr Listen (mit verschiedenen Typen und IDs) unterschiedlicher Länge.

Jetzt muss ich das erste Element a1 jeder Liste mit einem anderen Wert, z. in folgendem Dokument:

<foo> 
    <bar> 
    <type>1</type> 
    <id>1</id> 
    <a1>-100</a1> 
    <other_stuff/> 
    </bar> 
    <bar> 
    <type>1</type> 
    <id>1</id> 
    <a1>0</a1> 
    <other_stuff/> 
    </bar> 
    <bar> 
    <type>1</type> 
    <id>2</id> 
    <a1>-100</a1> 
    <other_stuff/> 
    </bar> 
    <bar> 
    <type>1</type> 
    <id>2</id> 
    <a1>0</a1> 
    <other_stuff/> 
    </bar> 
</foo> 

In Pseudo-SQL würde dies wahrscheinlich so aussehen:

update bar set a1 = -100 where position() = 1 group by type, id 

Ist dies möglich mit XSLT 1.0? Ich denke, es läuft darauf hinaus, einen XPath-Ausdruck schreiben zu können, der das gleiche Ergebnis liefert wie meine Pseudo-SQL-Anweisung.

Antwort

2

Verwenden Muenchian grouping das erste Element in jeder Gruppe identifizieren und das Kind ändern, den Rest mit der Identitäts-Transformation kopieren:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    version="1.0"> 

    <xsl:param name="new-value" select="-100"/> 

    <xsl:key name="group" match="bar" use="concat(type, '|', id)"/> 

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

    <xsl:template match="bar[generate-id() = generate-id(key('group', concat(type, '|', id))[1])]/a1"> 
     <xsl:copy> 
      <xsl:value-of select="$new-value"/> 
     </xsl:copy> 
    </xsl:template> 
</xsl:stylesheet> 

Wie für eine weitere Erklärung, läßt die Schlüsseldefinition <xsl:key name="group" match="bar" use="concat(type, '|', id)"/> den XSLT-Prozessor Index die bar Elemente auf der concat(type, '|', id), so dass wir die Schlüsselfunktion mit z key('group', '1|1'), um alle bar Elemente mit diesem Wert für concat(type, '|', id) zu finden.

Sie nur das erste bar Element in jeder Gruppe ändern will, so dass wir eine Möglichkeit haben müssen, dass die erste Element innerhalb eines Prädikats zu bar[...] zu identifizieren, wo wir ein Muster finden müssen, dass die Bedingung

bar[. is the first item in its group] 
drückt

die Gruppe, die wir mit key('group', concat(type, '|', id)) innerhalb des Musters zu erhalten, so wollen wir eine Bedingung

bar[. is the first item in key('group', concat(type, '|', id))] 

, die wir fast wörtlich mit denin XSLT 2.0 zum Ausdruck bringen können, schreiben 10 Operator und das Muster

bar[. is key('group', concat(type, '|', id))[1]] 

mit XSLT 1.0 wir ausdrücken können unter Verwendung generate-ID, wie in

getan
bar[generate-id() = generate-id(key('group', concat(type, '|', id))[1])] 

die auswählt/entsprechen jenes bar Element, für das die erzeugte ID an den gleich generierte ID des ersten Elements ([1]) in der Gruppe, berechnet von key('group', concat(type, '|', id)).

+0

Nur für mein Verständnis: Der 'xsl: key' erzeugt einen Schlüssel für alle' bar' Elemente mit der String-Verkettung der Inhalte der Kindelemente 'type' und'd'. Und der 'generate-id (...)' Funktionsaufruf regeneriert dann diesen Schlüssel und prüft, ob er mit dem aktuellen Element übereinstimmt. Dadurch wird für jeden Typ ein ID-Paar erstellt, von dem das erste ausgewählt wird. Ist das mehr oder weniger korrekt? – Markus

+0

@Markus, ich habe einige Erklärungen über den verwendeten Ansatz hinzugefügt, ich habe einen Weg durch XSLT 2.0 genommen, da dort der Ausdruck leichter auszudrücken ist und näher an der natürlichen Sprache liegt. –

Verwandte Themen