xsl:copy und/oder xsl:copy-of
Kerstin
- xsl
0 Thomas J.S.0 Kerstin0 Thomas J.S.0 Kerstin0 Kerstin0 Thomas J.S.
Hallihallo,
ich steh mächtig auf dem Schlauch. Habe ein XML-Dokument, dessen Struktur kopiert werden soll. Das geht wohl auf mehrere Arten, z.B.:
<xsl:template match="@*|node()">
xsl:copy
<xsl:apply-templates select="@*|node()">
</xsl:copy>
</xsl:template>
oder so:
<xsl:template match"/root">
xsl:copy
<xsl:copy-of select="/root/*"/>
</xsl:copy>
</xsl:template>
Allderings möchte ich an bestimmte Stellen ein neues Element einfügen. Wenn ich letzteres verwende, kann ich unterhalb von <root> sofort ein neues Element anschließen, so dass das Element <daten> mit der id="3" eingefügt wird:
<root><daten id="3"></daten>
<daten id="1"></daten>
<daten id="2"></daten>
<kontakte>
<kontakt id="1"></kontakt>
</kontakte>
</root>
Allerdings möchte ich auch unterhalb von <kontakte> oder in tiefer gelegenen Elementen neue Elemente einfügen und genau bei diesem Problem hakts grad arg.
Ich bin im Moment soweit:
<xsl:template match="/root">
xsl:copy
<xsl:element name="daten">
<xsl:attribute name="id">3</xsl:attribute>
</xsl:element>
<xsl:copy-of select="/root/*"/>
xsl:apply-templates/
</xsl:copy>
</xsl:template>
<xsl:template match="kontakte">
xsl:copy
<xsl:element name="kontakt">
<xsl:attribute name="id">2</xsl:attribute>
</xsl:element>
<xsl:copy-of select="kontakte/*"/>
xsl:apply-templates/
</xsl:copy>
</xsl:template>
Damit wird mir zwar
<kontakte>
<kontakt id="2"></kontakt>
</kontakte>
angelegt.
Die anderen Kontakte fehlen aber und drumrumm wird nur der Inhalt der Elemente kopiert ohne die Elemente.
Vielleicht fällt mir ja morgen eine Lösung ein. Vielleicht könntet ihr mir auch einen Tipp geben. Ich weiß im Moment nicht weiter. Das muss doch irgendwie gehen.
Gruß,
Kerstin
Hallo,
Ich bin im Moment soweit:
<xsl:template match="kontakte">
xsl:copy
<xsl:element name="kontakt">
<xsl:attribute name="id">2</xsl:attribute>
</xsl:element>
<xsl:copy-of select="kontakte/*"/>
xsl:apply-templates/
</xsl:copy>
</xsl:template>Damit wird mir zwar
<kontakte>
<kontakt id="2"></kontakt>
</kontakte>
angelegt.
Die anderen Kontakte fehlen aber und drumrumm wird nur der Inhalt der Elemente kopiert ohne die Elemente.
Nein, der Inhalt der Elemente wird nciht kopiert, es greift für sie das apply-templates bzw. durch dieses das build-in Template für Elemente, was den Text der Elemente in dem Ergebnisbaum schreibt.
Das "warum" liegt am <xsl:copy-of select="kontakte/*"/>.
Du bist im Template bereits im <kontakte> darunter gibt es aber kein weiteres <kontakte>-Elementen, es gibts also auch nichts zu kopieren.
Die Lösung wäre: <xsl:copy-of select="*"/> oder <xsl:copy-of select="./*"/> was dasselbe ist.
Grüße
Thomas
Hallo Thomas,
vielen Dank für Deine schnelle Antwort.
Hiermit:
<xsl:template match="kontakte">
xsl:copy
<xsl:element name="kontakt">
<xsl:attribute name="id">2</xsl:attribute>
</xsl:element>
<xsl:copy-of select="*"/>
</xsl:copy>
</xsl:template>
bekomme ich dann den gesamten Inhalt von <kontakte> + das Element, welches ich anlege.
Wenn ich jedoch im ersten Teil:
<xsl:template match="root">
xsl:copy
<xsl:element name="daten">
<xsl:attribute name="id">3</xsl:attribute>
</xsl:element>
<xsl:copy-of select="*"/>
xsl:apply-templates/
</xsl:copy>
</xsl:template>
kein xsl:apply-templates/ angebe, wird auch nicht auf das <xsl:template match="kontakte"> zugegriffen. Das neue XML sieht aus wie das alte ohne den neuen kontakt hinzuzufügen.
Ich müsste sagen könnte: Wenn du beim Kopieren auf <kontakte> triffst, führe das unterhalb von <xsl:template match="kontakte"> aus, also füge neuen kontakt hinzu, kopiere alles unterhalb und mache dann mit kopieren des rests weiter. Nur wie mache ich das dem XSL klar'??? *ratlosgugg*
Gruß,
Kerstin
Hallo,
vielen Dank für Deine schnelle Antwort.
Hiermit:
<xsl:template match="kontakte">
xsl:copy
<xsl:element name="kontakt">
<xsl:attribute name="id">2</xsl:attribute>
</xsl:element>
<xsl:copy-of select="*"/>
</xsl:copy>
</xsl:template>bekomme ich dann den gesamten Inhalt von <kontakte> + das Element, welches ich anlege.
OK: <xsl:copy-of select="child::node()"/> sollte dem abhelfen.
Wenn ich jedoch im ersten Teil:
[...]
Ich müsste sagen könnte: Wenn du beim Kopieren auf <kontakte> triffst, führe das unterhalb von <xsl:template match="kontakte"> aus, also füge neuen kontakt hinzu, kopiere alles unterhalb und mache dann mit kopieren des rests weiter. Nur wie mache ich das dem XSL klar'??? *ratlosgugg*
Das kannst du nicht so "einfach" machen, weil copy und copy-of eben fürs Kopieren gedacht sind.
Du kannst ein Template für alle Elemente erstellen, deren Inhalt du nciht verändern willst:
<xsl:template match="foo | bar | bla | blubb">
<xsl:copy-of select="."/>
wenn hierbei in der Verschachtelung Elemente vorkommen deren Inhalt du geändert haben willst, dann eben so:
<xsl:template match="foo | bar | bla | blubb">
xsl:copy
<xsl:copy-of select="@*"/>
xsl:apply-templates/
</xsl:copy>
Für die Elemente deren Inhalt du verändern willst muss du eigene Templates anlegen (wie für <kontakte>) und dort die Änderungen und das Kopieren machen.
Dann diese Templates eben mit xsl:apply-templates/ aufrufen.
Grüße
Thomas
Hallo Thomas,
Du kannst ein Template für alle Elemente erstellen, deren Inhalt du nciht verändern willst:
<xsl:template match="foo | bar | bla | blubb">
<xsl:copy-of select="."/>
Ohje, das wär ganz schön aufwendig dort oben alle Elemente einzutragen, die nicht verändert werden und nur kopiert werden sollen.
Jetzt hab ich soweit angefangen:
<xsl:template match = "@* | node()">
xsl:copy
<xsl:copy-of select="*"/>
<xsl:apply-templates />
</xsl:copy>
</xsl:template>
Soweit wird erstmal alles kopiert und auch andere Templates aufgerufen - denkt man zumindest.
zweites Template:
<xsl:template match="root">
xsl:copy
<xsl:if test="wenn was stimmt">
<!-- füge hinzu -->
<daten id="3"></daten>
</xsl:if>
<xsl:copy-of select="*"/>
</xsl:copy>
</xsl:template>
Klappt auch wunderbar!
Soll jetzt aber ein neuer <kontakt> unter root/kontakte angelegt werden, wird jedoch nicht in das template hineingegangen:
<xsl:template match="kontakte">
xsl:copy
<xsl:if test="wenn was stimmt">
<!-- füge hinzu -->
<kontakt id="3"></kontakt>
</xsl:if>
<xsl:copy-of select="*"/>
</xsl:copy>
</xsl:template>
Außer meiner Sicht sollte das doch funktionieren, oder?
Jemand noch eine Idee?
Gruß,
Kerstin
Ha,
Klappt auch wunderbar!
Soll jetzt aber ein neuer <kontakt> unter root/kontakte angelegt werden, wird jedoch nicht in das template hineingegangen:
<xsl:template match="kontakte">
xsl:copy
<xsl:if test="wenn was stimmt">
<!-- füge hinzu -->
<kontakt id="3"></kontakt>
</xsl:if>
<xsl:copy-of select="*"/>
</xsl:copy>
</xsl:template>Außer meiner Sicht sollte das doch funktionieren, oder?
gut ok, da müsste dann wohl auch ein xsl:apply-templates/ im <xsl:template match="root"> stehen, damit er drauf zugreift. Das gibt dann aber leider wieder unerwünschte Ausgaben im kopierten XML.
So ein Mist. ...
Hallo,
Ohje, das wär ganz schön aufwendig dort oben alle Elemente einzutragen, die nicht verändert werden und nur kopiert werden sollen.
Ja, möglicher Weise.
Jetzt hab ich soweit angefangen:
<xsl:template match = "@* | node()">
xsl:copy
<xsl:copy-of select="*"/>
Das kopiert zuerst alle Elemente
<xsl:apply-templates />
Dann werden Templates für Knoten (Elemente, PIs, Kommentare) und Attribte aufgerufen wobei du beachten musst, dass das kopieren "rekursiv" ist, weil das Template ja "rekursiv" d.h. eben für alle Knoten wirkt.
Soll jetzt aber ein neuer <kontakt> unter root/kontakte angelegt werden, wird jedoch nicht in das template hineingegangen:
Ja, und dir Gründe habe ich dir schon genannt: weil das Template <xsl:template match = "@* | node()"> mit dem Kopieren sich auf alle Knoten auswirkt.
Grüße
Thomas