[XSLT] Wie einen Knoten in eine XML einfügen ohne Dokumentstruktur nachzubauen?

Bexx

Verrückte Erfinderin bei Daniel Düsentrieb
Servus Foris,

ist es möglich in eine XML einen Knoten einzufügen, ohne im XSLT die übrige Dokumentstruktur manuell nachzubauen?
 
Hallo,

das kannst du mit dem Identity Template (o.a. Identity Copy) machen. Damit kopiert man das unveränderte Quelldokument in den Ausgabebaum:
XML:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

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

</xsl:stylesheet>
Wenn du jetzt ins Dokument etwas einfügen willst, dann musst du die Stelle irgendwie markieren. Beispielsweise mit einem Attribut.
Angenommen dein Quelldokument ist file1.xml und du willst file2.xml vor oder nach einem markierten Knoten einfügen:
XML:
<?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" indent="yes" encoding="UTF-8" />

<xsl:variable name="insertion" select="document('file2.xml')/node()" />

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

<!-- Fügt vor allen Knoten, die das Attribut [insert="before"] haben,
     den Knoten "$insertion" ein: -->
<xsl:template match="*[@insert='before']">
	<xsl:copy-of select="$insertion" />
	<xsl:copy>
		<xsl:apply-templates select="@* | node()"/>
	</xsl:copy>
</xsl:template>

<!-- Fügt nach allen Knoten, die das Attribut [insert="after"] haben,
     den Knoten "$insertion" ein: -->
<xsl:template match="*[@insert='after']">
	<xsl:copy>
		<xsl:apply-templates select="@* | node()"/>
	</xsl:copy>
	<xsl:copy-of select="$insertion" />
</xsl:template>

</xsl:stylesheet>
Ebenso lassen sich auch Knoten ersetzen:
XML:
<?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" indent="yes" encoding="UTF-8" />

<xsl:variable name="replacement" select="document('file2.xml')/node()" />

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

<!-- Ersetzt alle Knoten namens "replace" durch den Ersatzknoten "$replacement": -->
<xsl:template match="replace">
    <xsl:copy-of select="$replacement" />
</xsl:template>

</xsl:stylesheet>
 
Zuletzt bearbeitet von einem Moderator:
Das scheint ja genau dein Fachgebiet zu sein, tip top, das löst den Rest meiner Probleme! :)
Dein Buch hab ich mir gestern im Übrigen angesehn, bis auf dass es zu teuer fürs Azubibudget ist, liest sichs aber gut und scheint gut geschrieben :)
 
HALT! noch eine Frage. Das mit den Attributen, finde ich einen guten Ansatz. Aber ich verstehe nicht anhand welcher Logik er dann weiß, das Attribut VOR einem Knoten einzufügen... Danach einfügen ist klar, wie das funktioniert.
Aber wenn ich zum Beispiel sagen würde füge mir etwas vor(!) einem <Customer> Knoten ein, müsste ich dann nicht den Knoten davor mit dem Attribut flaggen? weil ich meine, die Attribute kann er ja nur interpretieren wenn ich ihm sage, was er damit tun soll...
 
Hi.
HALT! noch eine Frage. Das mit den Attributen, finde ich einen guten Ansatz. Aber ich verstehe nicht anhand welcher Logik er dann weiß, das Attribut VOR einem Knoten einzufügen... Danach einfügen ist klar, wie das funktioniert.
Da braucht es doch keine extra Logik. Beim Davor-Einfügen rufst du erst copy-of auf und danach apply-templates, beim Danach-Einfügen ist es umgekehrt.
Aber wenn ich zum Beispiel sagen würde füge mir etwas vor(!) einem <Customer> Knoten ein, müsste ich dann nicht den Knoten davor mit dem Attribut flaggen?
Nein. Wenn du das "before" Tag verwendest nicht.
weil ich meine, die Attribute kann er ja nur interpretieren wenn ich ihm sage, was er damit tun soll...
Wie bestimmte Knoten verarbeitet werden legst du im Template fest. Irgendwie verstehe ich da deine Argumentation nicht.

Gruß
 
Hi.
Da braucht es doch keine extra Logik. Beim Davor-Einfügen rufst du erst copy-of auf und danach apply-templates, beim Danach-Einfügen ist es umgekehrt.

Hab verstanden. Das mit dem umgekehrten Aufruf ist mir nicht aufgefallen- ich hab nur gesehen, dass er die Attribute verändert hat. Alles weitere wird damit klar, danke.
 
Bestimmt nerv ich euch schon ... ;)
ich möchte das ganze Knoteneinfügen an eine Bedingung geknüpft ausführen.
Die Bedingung ist, dass der Wert mit aus mehreren verteilten, gleichnamigen Knoten aus file1.xml mit den Werten mehrerer verteilter gleichnamigen Knoten aus der file2.xml übereinstimmen muss und NUR DANN darf ich das entsprechende Knotenset an die DestinationLocation verschieben.

Da ich zumindest nicht wüsste wie ich das mit verschachtelten FOR-schleifen lösen kann, da ich mit der Angabe select="." keinen Unique Identifier mehr habe ist meine erste Idee nun, mir aus file1.xml den Count der betroffen Knoten ausgeben lassen, aus denen ich den Value auslesen will und mich dann im Anschluss mit position() durch die Knoten hangeln. Klingt für mich nach Spaghetti-Code, da gibts sicher was besseres oder?!
 
Bestimmt nerv ich euch schon ... ;)
Naja, wir müssen ja nicht antworten... ;)
ich möchte das ganze Knoteneinfügen an eine Bedingung geknüpft ausführen.
Die Bedingung ist, dass der Wert mit aus mehreren verteilten, gleichnamigen Knoten aus file1.xml mit den Werten mehrerer verteilter gleichnamigen Knoten aus der file2.xml übereinstimmen muss und NUR DANN darf ich das entsprechende Knotenset an die DestinationLocation verschieben.
Du mußt schon mal genauer spezifizieren wann die Knotensets gleich sind. Muss die Reihenfolge eingehalten werden? Sprich: sind
XML:
<r>
  <a>1</a>
  <a>2</a>
</r>
XML:
<r>
  <a>2</a>
  <a>1</a>
</r>
diese 2 Dokumente bzgl. Der Knotensets //a gleich?

Da ich zumindest nicht wüsste wie ich das mit verschachtelten FOR-schleifen lösen kann, da ich mit der Angabe select="." keinen Unique Identifier mehr habe ist meine erste Idee nun, mir aus file1.xml den Count der betroffen Knoten ausgeben lassen, aus denen ich den Value auslesen will und mich dann im Anschluss mit position() durch die Knoten hangeln. Klingt für mich nach Spaghetti-Code, da gibts sicher was besseres oder?!
Du könntest tatsächlich erstmal alle Knoten die für die Bedingung notwendig sind zählen. Dann zählst du die Knoten auf die die Bedingung zutrifft (kommt auf die Bedingung an wie du das Bewerkstelligen kannst). Sind diese Zähler gleich, trifft die Bedingung auf alle Knoten zu.

Gruß
 
Zuletzt bearbeitet von einem Moderator:
Vielen Dank für die nochmal sehr ausführliche Antwort. Ich gebe mir Mühe mein Problem nächstes Mal genauer darzustellen und bessere Beispiele zu nennen.
Ich konnte mein Problem doch mit einem XPfad-Ausdruck lösen, der ungefähr so aussieht:
XML:
    <xsl:template match="myLocation/mySubLocation/mySubSubLocation">

      <!-- THIS CONTAINS SOURCE OF INTENDED INSERTION -->
        <xsl:element name="mySubSubLocation">
                <xsl:copy-of select="document($sourceFile)/EBENE1/EBENE2/EBENE3/EBENE4/EBENE5[./ROLLE = current()/../../../EBENE4/EBENE5/EBENE6/EBENE7/EBENE8/text()]"/>          
        </xsl:element>
      <!-- END -->
        
    </xsl:template>
 
Zuletzt bearbeitet von einem Moderator:
Zurück