Fast identisches Kopieren von xml nach xml
Matthias
- xsl
Hallo,
ich habe eine Reihe von DocBook-xml-Dokumenten, die überarbeitet wurden. Dabei wurden revision-attribute verwendet. Da die Überarbeitung nun abgeschlossen ist, möchte ich alle revision-Attribute löschen, damit bei der nächsten Überarbeitung die Dateien nicht zu unübersichtlich werden.
Folgende Schritte soll das .xsl tun:
Das klappt auch soweit ganz gut, bis auf folgende Probleme:
Ich habe im root-element xmlns:xlink="http://www.w3.org/1999/xlink" angegeben, dieses wird aber nicht im result.xml im root ausgegeben, stattdessen aber in jedem element aus dem Namensraum. Ich häte das aber gerne wieder nur einmal im root.
nodes, die wegen @revisionflag='deleted' nicht ausgegeben werden, generieren eine Leerzeile. Wie kann ich diese unterdrücken?
Bei der Transformation erhalte ich jede Menge warnings:
Ambiguous rule match for /processing-instruction()[1] Matches both "processing-instruction()" on line 72 and "node()" on line 19
Ambiguous rule match for /article[1]/text()[1] Matches both "text()" and "node()" on line 19
Ich bin schon ganz stolz soweit gekommen zu sein, da mir die xsl-Danke immer wieder Probleme bereitet, an den drei Punkten beisse ich mir aber nun die Zähne aus. Kann mir jemand einen Tip geben?
Vielen Dank.
Hier die Quelltexte:
removeRevisions.xml
<?xml version="1.0" encoding="UTF-8"?>
<?oxygen RNGSchema="http://www.oasis-open.org/docbook/xml/5.0/rng/docbook.rng" type="xml"?>
<article
version="5.0"
xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink">
<info>
<title>Test</title>
</info>
<para>Absatz 1.</para>
<para
revision="test"
revisionflag="deleted">Absatz 2.</para>
<para
revision="test"
revisionflag="added">Absatz 3.</para>
<para>Absatz 4.</para>
<para>Dies ist ein Absatz mit einem <link
xlink:href="http://www.google.de">Link</link> auf google.de.</para>
</article>
removeRevisions.xsl
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
version="1.0"
xmlns="http://docbook.org/ns/docbook"
xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template
match="/">
<xsl:apply-templates />
</xsl:template>
<xsl:template
match="node()">
<xsl:variable
name="check">
<xsl:choose>
<xsl:when
test="attribute::revision = 'test'">
<xsl:choose>
<xsl:when
test="attribute::revisionflag = 'added'">TRUE</xsl:when>
<xsl:otherwise>FALSE</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>TRUE</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:if
test="$check = 'TRUE'">
<xsl:element
name="{name()}">
<xsl:for-each
select="attribute::*">
<xsl:choose>
<xsl:when
test="name() = 'revision'" />
<xsl:when
test="name() = 'revisionflag'" />
<xsl:otherwise>
<xsl:attribute
name="{name()}">
<xsl:value-of
select="." />
</xsl:attribute>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
<xsl:apply-templates />
</xsl:element>
</xsl:if>
</xsl:template>
<xsl:template
match="text()">
<xsl:value-of
select="." />
</xsl:template>
<xsl:template
match="processing-instruction()">
<xsl:processing-instruction
name="{name()}">
<xsl:value-of
select="." />
</xsl:processing-instruction>
</xsl:template>
</xsl:stylesheet>
result.xml
<?xml version="1.0" encoding="utf-8"?><?oxygen RNGSchema="http://www.oasis-open.org/docbook/xml/5.0/rng/docbook.rng" type="xml"?>
<article
version="5.0"
xmlns="http://docbook.org/ns/docbook">
<info>
<title>Test</title>
</info>
<para>Absatz 1.</para>
<para>Absatz 3.</para>
<para>Absatz 4.</para>
<para>Dies ist ein Absatz mit einem <link
xlink:href="http://www.google.de"
xmlns:xlink="http://www.w3.org/1999/xlink">Link</link> auf google.de.</para>
</article>
Hallo Matthias,
Ich bin schon ganz stolz soweit gekommen zu sein, da mir die xsl-Danke immer wieder Probleme bereitet, an den drei Punkten beisse ich mir aber nun die Zähne aus. Kann mir jemand einen Tip geben?
Probiere es so:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://docbook.org/ns/docbook"
xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl"
xmlns:xlink="http://www.w3.org/1999/xlink">
<xsl:output method="xml" version="1.0" encoding="UTF-8"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[@revision='test' and @revisionflag='deleted']"/>
<xsl:template match="@revision[.='test'] | @revisionflag[.='added']"/>
<xsl:template match="text()[normalize-space(.)='']"/>
</xsl:stylesheet>
Das letzte Template vermeidet alle Whitespace-Knoten, im XML-Editor kann via "Pretty-Print"-Knopf die eingerückte Variante wiederhergestellt werden.
Grüße,
Thomas
[Nachtrag:]
Falls der XSLT-Prozessor indent="yes" unterstützt (etwa Saxon), wird die Ausgabe gleich wieder lesbar strukturiert erzeugt, also:
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
Grüße,
Thomas
Hallo Thomas,
vielen Dank, perfekt, tut genau das, was ich zu erreichen versucht habe. Und das mit viel weniger Zeilen.
Was ich nicht ganz nachvollziehen kann ist, wie
<xsl:template
match="@* | node()">
<xsl:copy>
<xsl:apply-templates
select="@* | node()" />
</xsl:copy>
</xsl:template>
und
<xsl:template
match="*[@revision='test' and @revisionflag='deleted']" />
interagieren.
Das | hängt alternative Ausdrücke aneinander, bedeutet also meinem Verständnis nach soviel wie 'oder'. Also in dem ersten Template "ein beliebiges Attribut" ODER "ein Element".
Das zweite Template schliesst aber alle Elemente mit der angegebenen Attributs/Werte-Kombination aus.
Wieso greift dieses zweite Template vor dem ersten?
Hat das etwas mit dem nicht explizit angegebenen, und dadurch mit Standardwerten belegten, @priority des xsl:template zu tun wie http://de.selfhtml.org/xml/darstellung/xsltelemente.htm#template@title=hier beschrieben?
Also
<xsl:template
match="@* | node()" />
~~~ entspricht @priority=0.25 für Attribute und @priority="0" for Nodes.
~~~xml
<xsl:template
match="*[@revision='test' and @revisionflag='deleted']" />
~~~ entspricht @priority=0.25 für Nodes mit beiden Attributen/Werten
~~~xml
<xsl:template
match="@revision[.='test'] | @revisionflag[.='added']" />
~~~ entspricht @priority='0.5' für die spezifizierten Attribute.
Stimmt dies so?
Das ist genau das, was ich mit "die xsl-Denke macht mir Probleme" in meinem ersten Post gemeint habe, auf so eine Idee wäre ich nie gekommen.
Vielen Dank.
Gruß
Matthias
Hallo Matthias,
Was ich nicht ganz nachvollziehen kann ist, wie
<xsl:template
match="@* | node()">
xsl:copy
<xsl:apply-templates
select="@* | node()" />
</xsl:copy>
</xsl:template>
> und
> ~~~xml
<xsl:template
> match="*[@revision='test' and @revisionflag='deleted']" />
interagieren.
Das erste ist ein Identitäts-Template, welches alle Knoten ausgibt. Die anderen Templates haben keinen Inhalt, machen also genau gar nichts mit den selektierten Elementknoten, schließen diese also von der Verarbeitung aus.
Grüße,
Thomas