Wie entferne ich Elemente aus xml mit xslt mit Stylesheet und xsltproc?


68

Ich habe viele XML-Dateien, die etwas von der Form haben:

<Element fruit="apple" animal="cat" />

Was ich aus der Datei entfernen möchte.

Wie kann ich dies mit einem XSLT-Stylesheet und dem Linux-Befehlszeilenprogramm xsltproc tun?

Zu diesem Zeitpunkt im Skript habe ich bereits die Liste der Dateien, die das Element enthalten, das ich entfernen möchte, sodass die einzelne Datei als Parameter verwendet werden kann.


EDIT: Die Frage hatte ursprünglich keine Absicht.

Was ich versuche zu erreichen, ist das gesamte Element "Element" wo (Frucht == "Apfel" && Tier == "Katze") zu entfernen. Im selben Dokument gibt es viele Elemente mit dem Namen "Element". Ich möchte, dass diese erhalten bleiben. Damit

<Element fruit="orange" animal="dog" />
<Element fruit="apple"  animal="cat" />
<Element fruit="pear"   animal="wild three eyed mongoose of kentucky" />

Würde werden:

<Element fruit="orange" animal="dog" />
<Element fruit="pear"   animal="wild three eyed mongoose of kentucky" />

Antworten:


134

Unter Verwendung eines der grundlegendsten XSLT-Entwurfsmuster: "Überschreiben der Identitätstransformation " wird nur Folgendes geschrieben:

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

 <xsl: Ausgabe omit-xml-declare = "yes" />

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

    <xsl: template match = "Element [@ obst = 'Apfel' und @ Tier = 'Katze']" />
</ xsl: Stylesheet>

Beachten Sie, dass die zweite Vorlage die Identitätsvorlage (1. Vorlage) nur für Elemente mit dem Namen "Element" überschreibt, die das Attribut "Frucht" mit dem Wert "Apfel" und das Attribut "Tier" mit dem Wert "Katze" haben. Diese Vorlage hat einen leeren Körper, was bedeutet, dass das übereinstimmende Element einfach ignoriert wird (beim Abgleichen wird nichts erzeugt).

Wenn diese Umwandlung auf das folgende XML-Quelldokument angewendet wird:

<doc> ... 
    <Element name = "same"> foo </ Element> ...
    <Element Frucht = "Apfel" Tier = "Katze" />
    <Element Frucht = "Birne" Tier = "Katze" />
    <Element name = "same"> baz </ Element> ...
    <Element name = "same"> foobar </ Element> ...
</ doc>

das gewünschte Ergebnis wird erzeugt:

<doc> ... 
    <Element name = "same"> foo </ Element> ...
    <Element Frucht = "Birne" Tier = "Katze" />
    <Element name = "same"> baz </ Element> ...
    <Element name = "same"> foobar </ Element> ...
</ doc>

Weitere Codefragmente zum Verwenden und Überschreiben der Identitätsvorlage finden Sie hier .


13
Obwohl ich nicht einmal die richtige Frage gestellt habe, haben Sie genau das beantwortet, was ich hätte stellen sollen! :)
Grundlefleck

3
Warum kennst du diesen Beitrag dann nicht als die richtige Antwort? Dann würde es aus der Liste der unbeantworteten Probleme verschwinden.
Dirk Vollmar

2
Ich musste warten, bis ich überprüft hatte, dass es funktionierte, und hatte heute keine Chance bei der Arbeit. Jetzt aber fertig, danke Dimitre.
Grundlefleck

Können Sie mir sagen, was die abgekürzte Version dieses xpath-Ausdrucks ist /bookstore/book[position() = 1 or position() = 3]/@*?
Arup Rakshit

2
@ Babai , /*/book[position() = 1 or position() = 3]/@*. In XPath 2.0:/*/book[position() = (1,3)]/@*
Dimitre Novatchev

3

Die Antwort von @Dimitre Novatchev ist sicherlich sowohl richtig als auch elegant, aber es gibt eine Verallgemeinerung (nach der das OP nicht gefragt hat): Was ist, wenn das Element, das Sie filtern möchten, auch untergeordnete Elemente oder Text enthält, den Sie behalten möchten ?

Ich glaube, diese kleine Variation deckt diesen Fall ab:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    version="2.0">

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

    <!-- drop DropMe elements, keeping child text and elements -->
    <xsl:template match="DropMe">
        <xsl:apply-templates/>
    </xsl:template>

</xsl:stylesheet>

Die Übereinstimmungsbedingung kann kompliziert sein, um andere Attribute usw. anzugeben, und Sie können mehrere solcher Vorlagen verwenden, wenn Sie andere Dinge löschen.

Also diese Eingabe:

<?xml version="1.0" encoding="UTF-8"?>
<mydocument>
    <p>Here's text to keep</p>
    <p><DropMe>Keep this text but not the element</DropMe>; and keep what follows.</p>
    <p><DropMe>Also keep this text and <b>this child element</b> too</DropMe>, along with what follows.</p>
</mydocument>

erzeugt diese Ausgabe:

<?xml version="1.0" encoding="UTF-8"?><mydocument>
    <p>Here's text to keep</p>
    <p>Keep this text but not the element; and keep what follows.</p>
    <p>Also keep this text and <b>this child element</b> too, along with what follows.</p>
</mydocument>

Gutschrift für das XSLT-Kochbuch .

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.