Kopieren von Knoten: xsl:copy und xsl:copy-of

(Auszug aus "XSLT 2.0 & XPath 2.0" von Frank Bongers, Kapitel 2.)

Wenn eine XML-Struktur in eine andere umzuwandeln ist, besteht häufig der Bedarf, den aktuellen Knoten (dies kann ein Element oder ein anderer Knoten sein) ohne weitere Änderungen einfach ins Ergebnisdokument zu kopieren: ähnlich wie es mit Literal Result Elements im Stylesheet der Fall ist.

Man unterscheidet hierbei zwei Arten von Kopien: die »flache« Kopie, die nur den Knoten selbst, nicht aber eventuelle Inhalte (oder Attribute) kopiert, und die »tiefe« Kopie, die den Knoten mitsamt daran hängendem Dokumentzweig kopiert. Die erste Variante wird durch xsl:copy abgedeckt, die zweite durch xsl:copy-of.

Kopieren mit xsl:copy – die flache Kopie

Die Instruktion xsl:copy stellt eine »flache« Kopieranweisung (shallow copy) dar. Sie kopiert, in Ermangelung eines select-Attributs, stets nur das aktuelle Item; aber nicht, falls es sich beim Gegenstand des Kopiervorgangs um einen Ele­mentknoten handelt, dessen Kindknoten. Seien es Elemente oder Textinhalte; Attributknoten sowieso nicht, da diese nicht zu den Kindknoten zählen.

<xsl:copy/>

Das Element ist oft leer, kann aber auch einen Template-Block enthalten, der dann erforderlich ist, wenn Elementknoten kopiert werden sollen. Jedenfalls dann, wenn auch die Inhalte kopierter Elemente berücksichtigt werden sollen. In diesem Fall können Sie mit xsl:apply-templates die Weiterverarbeitung der Kindknoten ermöglichen:

<xsl:template match="*">
  <xsl:copy>
    <xsl:apply-templates/> 
  </xsl:copy>
</xsl:template>

Eine Template-Regel, wie die oben gegebene, kopiert dank des Wildcard-Name­Tests * jedes beliebig benannte Element in die Ergebnissequenz (und erzeugt gleichzeitig eine weiterzuverarbeitende Sequenz der Kindknoten). Nicht berücksichtigt werden jedoch die Attribute des kopierten Elements, da xsl:apply-templates nicht von sich aus auf der Attributachse arbeitet.

In einer weniger pauschal arbeitenden Template-Regel kann das Abstreifen der Attribute gezielt auf einen bestimmten Elementtyp angewendet werden. Gleichzeitig ist xsl:copy in der Lage, einen Attributset mit neuen Attributen an das nun seiner Attribute beraubte Element zu binden:

<xsl:template match="beispiel">
  <xsl:copy use-attribute-sets="beispiel-set">
    <xsl:apply-templates/> 
  </xsl:copy>
</xsl:template>

Ein Element <beispiel> wird kopiert und erhält einen Satz neuer Attribute.

Die Instruktion ist, mit einem entsprechenden XPath-Ausdruck, selbstverständ­lich auch in der Lage, etwaige Attribute des aktuellen Knotens in die Ergebnis­sequenz zu übertragen. Bei der Serialisierung dieses Attributknotens muss allerdings in diesem Moment ein aufnahmebereiter (man sagt »offener«) Ele­mentknoten vorhanden sein.

Folgende Template-Kombination erreicht dies:

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

Im Ergebnisdokument:

...
<ergebnis kopiertes-attribut="kopierter Wert">
  ... Inhalte ...
</ergebnis>
...

Der offene Elementknoten heißt in jedem Fall <ergebnis>, da dieser Knoten in die Ergebnissequenz geschrieben wird, bevor in das Attribut-Kopier-Template match="@*" gewechselt wird; nach der »Rückkehr« aus jenem Template wird der Knoten geschlossen. Der select-Wert "@*|node()" von xsl:apply-tem­plates ermöglicht, dass außer allen Attributen @* auch alle Kindknoten node() beliebiger Natur, also Elemente, Texte, Kommentare usw. verarbeitet werden.

Dies geschieht für Elementknoten (sofern keine ranghöhere Regel vorliegt) durch die Template-Regel match="*", ansonsten mit den üblichen Default-Tem­plates. Im Grunde läuft dies darauf hinaus, alle Elemente des Quelldokuments, für die keine eigene Regel besteht, unter Beibehaltung der ursprünglichen Attribute (Bezeichner und Wert) in <ergebnis> umzubenennen.

Vor- und Nachteile von xsl:copy

Die Instruktion xsl:copy kopiert den aktuellen Knoten in die Ergebnisse­quenz, unter Beibehaltung des Bezeichners. Dessen Inhalte oder Attribute kön­nen ebenfalls verarbeitet werden, dafür ist aber ein expliziter Befehl bzw. eine rekursive Ausführung des Kopierbefehls über die Child-Knoten erforderlich.

Diese Rekursivität kann umständlich zu formulieren sein. Sie haben aber im Endeffekt die beste Kontrolle darüber, was genau ins Ergebnisdokument gelangt.

Das Kopieren ganzer Dokumentzweige lässt sich unpräziser, weil pauschal, dafür aber einfacher mit xsl:copy-of erreichen.

Kopieren mit xsl:copy-of – die tiefe Kopie

Die Instruktion xsl:copy-of wird eingesetzt, wenn, ausgehend von einem Elementknoten, ein ganzer »Zweig« des Quelldokuments kopiert werden soll. Genauso gut kann die Instruktion auf eine beliebige Sequenz angewendet wer­den und kopiert diese, im Fall von Elementknoten, mitsamt Inhalten, Attribu­ten und Namensräumen, in die Ergebnissequenz. Da alle am verarbeitenden Knoten »hängenden« Nachfolgerknoten mitkopiert werden, spricht man hier von einer »tiefen« Kopieranweisung (deep copy).

Die Zusammensetzung einer solchen Kopie ist jedoch nicht im Einzelnen steu­erbar, stets wird pauschal alles kopiert. Die einzige Ausnahme sind Namensraum­knoten, deren Kopie durch das Attribut copy-namespaces="no" untersagt werden können (Default ist "yes").

Die Instruktion besitzt ein obligatorisches select-Attribut, das die Sequenz oder die Wurzel des zu kopierenden Dokumentzweigs durch einen XPath-Aus­druck bestimmt (dies kann auch "." für den aktuellen Knoten sein, was diesen mit allen seinen Nachfahren in die Ergebnissequenz befördert). Die Instruktion ist hilfreich für den Fall, dass ganze Strukturen (subtrees) mehrmals ins Ergeb­nisdokument kopiert werden müssen.

<xsl:copy-of select="XPath-Ausdruck"/>

Um alle <buch>-Elemente eines <regal>-Elements ohne weitere Änderungen in das Ergebnisdokument zu kopieren, würde man beispielsweise schreiben:

<xsl:template match="regal">
  <kiste>
    <xsl:copy-of select="buch"/>
  </kiste>
</xsl:template>

Dies führt dazu, dass alle Bücher unverändert (auch in gleicher Reihenfolge!) aus dem XML-Regal in die XML-Kiste wandern. XSLT erweist sich, zumindest für Daten, als idealer Umzugshelfer.

Für schemabezogene XSLT-Verarbeitung wird in Zukunft die Möglichkeit rele­vant sein, einen mit xsl:copy-of kopierten Baum zu validieren. Hierfür kann, mit Hilfe des type-Attributs, ein Sequenz-Typ als Vergleich herangezogen wer­den, aber auch ein Schema-Typ aus einer erreichbaren Typdeklaration. Eine alternative Möglichkeit bietet das validation-Attribut.

   

<< zurück vor >>
Tipp der data2type-Redaktion:
Zum Thema XSLT bieten wir auch folgende Schulungen zur Vertiefung und professionellen Fortbildung an:

Copyright © Galileo Press, Bonn 2008
Für Ihren privaten Gebrauch dürfen Sie die Online-Version ausdrucken.
Ansonsten unterliegt dieses Kapitel aus dem Buch "XSLT 2.0 & XPath 2.0 ― Das umfassende Handbuch" denselben Bestimmungen wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


Galileo Press, Rheinwerkallee 4, 53227 Bonn