2 Stimmen

XSLT: Entfernen doppelter br-Tags aus Fließtext

Bei der Bearbeitung von Rich-Text-Inhalten generiert unser CMS XML-Dateien mit doppeltem <br/> -tags. Ich würde sie gerne entfernen, um eine Ausgabe zu erzeugen, die von einer anderen Anwendung gelesen werden kann, die das Auftreten dieser Duplikate nicht schätzt.

Beispiel Eingabe:

<p>
   Lorem ipsum...<br />
   <br />
   ..dolor sit
</p>

Dies würde etwa so aussehen:

<p>
   Lorem ipsum...<br />
   ..dolor sit
</p>

Ich verwende bereits XSLT, um die Ausgabe auf andere Weise zu bearbeiten, und habe einige Beispiele für regexps und PHP gefunden, die dasselbe bewirken. Ich denke nur, dass es besser wäre, wenn ich dies mit XSLT aufgrund der Geschwindigkeit der Engine in unserem CMS (Roxen) tun könnte.

Vielen Dank im Voraus!

4voto

LarsH Punkte 26458

Aufbauend auf der Antwort von @Nic könnten Sie Folgendes verwenden

<xsl:template match='br[preceding-sibling::node()[1][self::br]]'/>

Ich habe gerade die * a node() . Dies würde das Problem der Vermischung von zwei <br/> s, zwischen denen Text steht. Allerdings würde es aufhören, doppelte Einträge zu entfernen <br/> s, auch wenn nur ein Leerzeichen dazwischen liegt.

Um das zu lösen...

Abgelehnt

Zuerst hatte ich vorgeschlagen, dass man nur Leerzeichen enthaltende Knoten aus p Elemente im Eingabedokument, indem Sie dies auf die oberste Ebene Ihrer XSLT setzen:

<xsl:strip-space  elements="p"/>

Aber @Alejandro wies darauf hin, dass Dies kann leicht dazu führen, dass Sie wichtige Räume verlieren. wie in <p><em>bar</em> <em>baz</em></p> .

Also stattdessen,

dieses geänderte Suchmuster verwenden:

<xsl:template match='br[preceding-sibling::node()
                        [not(self::text() and normalize-space(.) = "")][1]
                        [self::br]]'/>

Etwas hässlich, aber es sollte funktionieren. Dies wird "jedes br, für das der vorangehende Geschwisterknoten, der kein reiner Leerzeichen-Textknoten ist, ebenfalls ein br ist" finden und unterdrücken. :-)

Da das Übereinstimmungsmuster so komplex ist, können Sie es vorziehen, einen Teil dieser Logik in den Schablonenteil zu verlagern, wie im Folgenden beschrieben. Ich denke, das ist eher eine Frage des persönlichen Geschmacks und Stils:

<xsl:template match="br">
   <xsl:if test="not(preceding-sibling::node()
                        [not(self::text() and normalize-space(.) = '')][1]
                        [self::br])">
      <xsl:copy>
          <xsl:apply-templates select="@*|node()" />
      </xsl:copy>
   </xsl:if>
</xsl:template>

Hier verwenden wir eine Kopie der Identitätstransformation, wenn die <br /> ist keine, die wir unterdrücken wollen. Ich glaube nicht, dass <br /> kann untergeordnete Elemente oder Text enthalten, aber es schadet nicht, auf Nummer sicher zu gehen.

( Die obigen Angaben wurden aktualisiert. Ich hatte vergessen, den Beispielcode zu beenden, als ich das letzte Mal Änderungen gespeichert habe).

3voto

Nic Gibson Punkte 6866

Wenn Sie eine Identitätstransformation verwenden, um alles andere in Ruhe zu lassen, können Sie einfach alle <br/> die unmittelbar vor einer anderen steht. Natürlich können Sie die Vorlage dann einfach in Ihre bestehende XSLT einfügen.

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

<xsl:template match='br[(preceding-sibling::*)[1][self::br]]'/>

Die leere Vorlage unterdrückt einfach diese <br/> .

Aktualisierung: Wie @LarsH bemerkt hat, ist diese Vorlage zu großzügig in ihrer Anpassung und sollte wahrscheinlich in etwa so lauten:

<xsl:template match='br[preceding-sibling::node()[1]
    [not(self::text() and normalize-space(.) = "")][self::br]]'/>

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X