Konvertieren von XML in Klartext - wie soll ich ignorieren / handele Leerzeichen im XSLT?

StackOverflow https://stackoverflow.com/questions/184431

  •  06-07-2019
  •  | 
  •  

Frage

Ich versuche, eine XML-Datei in das Markup von dokuwiki, mit XSLT verwendet zu konvertieren. Das funktioniert tatsächlich bis zu einem gewissen Grad, aber die Vertiefung in der XSL-Datei wird in die Ergebnisse eingefügt zu werden. Im Moment habe ich zwei Möglichkeiten: aufgibt diese XSLT Sache ganz, und eine andere Art und Weise von XML zu konvertieren findet Markup dokuwiki, oder etwa 95% der Leerzeichen aus der XSL-Datei löschen, es nahezu unleserlichen und eine Wartung Alptraum zu machen.

Gibt es eine Möglichkeit, die Vertiefung in der XSL-Datei zu halten, ohne auf das endgültige Dokument all das Leerzeichen vorbei?

Hintergrund: Ich bin ein Autodoc Tool von statischen HTML-Seiten der Migration über dokuwiki, so dass die API von dem Server-Team entwickelt wird, kann weiter durch das Applikationsteam dokumentiert werden, wenn das Apps Team in schlecht dokumentierte Code ausgeführt wird. Die Logik ist einen Abschnitt jeder Seite für den Autodoc Werkzeugsatz haben beiseite und Kommentare außerhalb dieser Blöcke überall zu ermöglichen. Ich bin mit XSLT, weil wir bereits die XSL-Datei von XML zu XHTML zu konvertieren, und ich nehme an, es wird schneller sein, die XSL neu zu schreiben, als meine eigene Lösung von Grund auf zu rollen.

Edit: Ah, richtig, dumm mich, ich den Einzug Attribut vernachlässigt. (Weitere Hintergrundinformationen. Ich bin neu in XSLT) Auf der anderen Seite muss ich noch mit Zeilenumbrüche beschäftigen. Dokuwiki verwendet Rohre zwischen Tabellenspalten zu unterscheiden, was bedeutet, dass alle Daten in einer Tabellenzeile auf einer Linie liegen. Gibt es eine Möglichkeit neue Zeilen ausgegeben werden (nur gelegentlich) zu unterdrücken, so dass ich für jede Tabellenzelle in einem etwas lesbar fasion einige ziemlich komplexe Logik tun?

War es hilfreich?

Lösung

Es gibt drei Gründe für unerwünschte Leerzeichen in Folge einer XSLT-Transformation erhalten:

  1. Leerzeichen, die von zwischen den Knoten in dem Quelldokument kommt
  2. Leerzeichen, die aus Knoten im Quelldokument kommt
  3. Leerzeichen, die aus dem Stylesheet
  4. kommt

Ich werde über alle drei sprechen, weil es schwer zu sagen, wo Leerzeichen aus, so kommen müssen Sie möglicherweise mehrere Strategien verwendet werden.

, um die Leerzeichen zu adressieren, die zwischen den Knoten in Ihrem Quelldokument ist, sollten Sie <xsl:strip-space> verwenden alle Leerzeichen Streifen aus, die zwischen zwei Knoten angezeigt wird, und verwenden Sie dann <xsl:preserve-space> den signifikanten Leerzeichen zu erhalten, die in gemischtem Inhalt erscheinen. Zum Beispiel, wenn Ihr Quelldokument wie folgt aussieht:

<ul>
  <li>This is an <strong>important</strong> <em>point</em></li>
</ul>

dann werden Sie die Leerzeichen zwischen den <ul> und dem <li> und zwischen dem </li> und dem </ul> zu ignorieren, die nicht signifikant ist, aber die Leerzeichen zwischen den <strong> und <em> Elemente erhalten, die ist signifikant (sonst würden Sie bekommen „Dies ist ein wichtiger ** *** Punkt *“). Um diese Anwendung zu tun

<xsl:strip-space elements="*" />
<xsl:preserve-space elements="li" />

Das elements Attribut auf <xsl:preserve-space> grundsätzlich alle Elemente in Ihrem Dokument auflisten sollte, die Inhalte gemischt haben.

  

Neben. Mit <xsl:strip-space> reduziert auch die Größe des Quellbaum im Speicher und macht Ihr Sheet effizienter zu gestalten, so lohnt es sich, zu tun, auch wenn Sie keine Leerzeichen Probleme dieser Art haben Sie

, um die Leerzeichen zu adressieren, die innerhalb von Knoten in Ihrem Quelldokument erscheint, sollten Sie normalize-space() verwenden. Zum Beispiel, wenn Sie:

<dt>
  a definition
</dt>

und Sie können sicher sein, dass das <dt> Element werden keine Elemente enthalten, die Sie mit etwas tun wollen, dann können Sie tun:

<xsl:template match="dt">
  ...
  <xsl:value-of select="normalize-space(.)" />
  ...
</xsl:template>

Die führende und nachfolgende Leerzeichen wird von dem Wert des <dt> Element abgezogen werden, und Sie werden nur die Zeichenfolge "a definition" erhalten.

Leerzeichen, die sich aus dem Stylesheet kommen, das ist vielleicht derjenige Sie erleben, ist, wenn Sie Text in einer Vorlage wie folgt aussehen:

<xsl:template match="name">
  Name:
  <xsl:value-of select="." />
</xsl:template>

XSLT Stylesheets werden auf die gleiche Weise wie die Quelldokumente analysiert, die sie verarbeiten, so dass die obige XSLT als Baum interpretiert wird, der mit einem <xsl:template> Attribut, dessen erstes Kind ist ein Textknoten und dessen zweites Kind eine match Element hält ein <xsl:value-of> Element mit einem select Attribute. Der Text Knoten führende und nachfolgende Leerzeichen (einschließlich Zeilenumbrüche); da es im Stylesheet wörtliche Text ist, wird es buchstäblich in das Ergebnis kopiert, mit allen führenden und nachfolgenden Leerzeichen.

Aber einige Leerzeichen in XSLT-Stylesheets werden automatisch abgezogen, nämlich die zwischen den Knoten. Sie haben nicht einen Zeilenumbruch in Ihrem Ergebnis bekommen, weil es zwischen dem <xsl:value-of> und dem Ende des <xsl:template> ein Zeilenumbruch ist.

Um nur den Text, den Sie im Ergebnis wollen, verwenden Sie das <xsl:text> Element wie folgt:

<xsl:template match="name">
  <xsl:text>Name: </xsl:text>
  <xsl:value-of select="." />
</xsl:template>

Der XSLT-Prozessor wird die Zeilenumbrüche und Einrückungen ignorieren, die zwischen den Knoten, und nur dann ausgegeben, um den Text innerhalb des <xsl:text> Elements erscheinen.

Andere Tipps

Sind Sie indent mit = "no" in der Ausgabe-Tag?

<xsl:output method="text" indent="no" />

Auch wenn Sie xsl verwenden. Value-of Sie das disable-output-escaping verwenden = "yes" mit einigen Leerzeichen Problemen zu helfen

@ JeniT Antwort ist groß, ich will nur einen Trick, darauf hinzuweisen für Leerzeichen zu verwalten. Ich bin nicht sicher, es ist der beste Weg (oder sogar eine gute Art und Weise), aber es funktioniert für mich jetzt.

( "s" für Raum "e" für leer, "n" für Newline).

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xsl:transform [
  <!ENTITY s "<xsl:text xmlns:xsl='http://www.w3.org/1999/XSL/Transform'> </xsl:text>" >
  <!ENTITY s2 "<xsl:text xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>  </xsl:text>" >
  <!ENTITY s4 "<xsl:text xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>    </xsl:text>" >
  <!ENTITY s6 "<xsl:text xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>      </xsl:text>" >
  <!ENTITY e "<xsl:text xmlns:xsl='http://www.w3.org/1999/XSL/Transform'></xsl:text>" >
  <!ENTITY n "<xsl:text xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>
</xsl:text>" >
]>

<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output method="text"/>
<xsl:template match="/">
  &e;Flush left, despite the indentation.&n;
  &e;  This line will be output indented two spaces.&n;

      <!-- the blank lines above/below won't be output -->

  <xsl:for-each select="//foo">
    &e;  Starts with two blanks: <xsl:value-of select="@bar"/>.&n;
    &e;  <xsl:value-of select="@baz"/> The 'e' trick won't work here.&n;
    &s2;<xsl:value-of select="@baz"/> Use s2 instead.&n;
    &s2;    <xsl:value-of select="@abc"/>    <xsl:value-of select="@xyz"/>&n;
    &s2;    <xsl:value-of select="@abc"/>&s;<xsl:value-of select="@xyz"/>&n;
  </xsl:for-each>
</xsl:template>
</xsl:transform>

Angewandt auf:

<?xml version="1.0" encoding="UTF-8"?>
<foo bar="bar" baz="baz" abc="abc" xyz="xyz"></foo>

Ausgänge:

Flush left, despite the indentation.
  This line will be output indented two spaces.
  Starts with two blanks: bar.
baz The 'e' trick won't work here.
  baz Use s2 instead.
  abcxyz
  abc xyz

Der ‚e‘ Trick funktioniert vor einem Textknoten mindestens ein Nicht-Leerzeichen enthält, weil es dazu erweitert:

<xsl:template match="/">
  <xsl:text></xsl:text>Flush left, despite the indentation.<xsl:text>
</xsl:text>

Da die Regeln für Leerzeichen Strippen sagen, dass durch Leerzeichen nur Textknoten abgezogen bekommen, die newline und Vertiefung zwischen dem und get gestrippt (gut). Da die Regeln ein Textknoten mit mindestens einem Leerzeichen sagen beibehalten wird, der implizite Textknoten enthält " This line will be output indented two spaces." seine führende Leerzeichen hält (aber ich denke, das auch von den Einstellungen für den Streifen ist abhängig / bewahren / Normalisieren). Dann;" am Ende der Zeile fügt eine neue Zeile, aber es stellt auch sicher, dass jede folgende Leerzeichen ignoriert wird, weil es zwischen zwei Knoten angezeigt wird.

Das Problem ich habe, ist, wenn ich die Ausgabe zergliederte Linie will, die mit einem beginnt. In diesem Fall wird die „& e;“ wird nicht helfen, weil die Vertiefung Leerzeichen nicht „gebunden“ ist nicht auf irgendwelche nicht-Leerzeichen. Also für diejenigen Fälle, verwende ich „& s2;“ oder "& s4;". Je nachdem, wie viel Vertiefung Ich möchte

Es ist ein hässlicher Hack Ich bin sicher, aber zumindest habe mich nicht den ausführlichen „“ Tags meine XSLT Littering, und zumindest kann ich einrücken noch den XSLT selbst, so dass es lesbar ist. Ich fühle mich wie ich bin XSLT missbrauchen für etwas, das es nicht für (Textverarbeitung) entworfen wurde, und das ist das Beste, was ich tun kann.


Edit: In Reaktion auf die Kommentare, das ist, wie es aussieht, ohne dass die „Makros“:

<xsl:template match="/">
  <xsl:text>Flush left, despite the indentation.</xsl:text>
  <xsl:text>  This line will be output indented two spaces.</xsl:text>
  <xsl:for-each select="//foo">
    <xsl:text>  Starts with two blanks: </xsl:text><xsl:value-of select="@bar"/>.<xsl:text>
</xsl:text>
    <xsl:text>    </xsl:text><xsl:value-of select="@abc"/><xsl:text> </xsl:text><xsl:value-of select="@xyz"/><xsl:text>
</xsl:text>
  </xsl:for-each>
</xsl:template>

Ich denke, das macht es weniger klar die beabsichtigte Ausgabe Vertiefung zu sehen, und es vermasselt die Vertiefung des XSL selbst, weil die </xsl:text> Endtags in Spalte 1 der XSL-Datei angezeigt haben (sonst Sie unerwünschte Leerzeichen erhalten in der Ausgabedatei).

In Bezug auf Ihr bearbeiten über neue Linien, können Sie diese Vorlage verwenden, um rekursiv eine Zeichenfolge innerhalb einer anderen Zeichenfolge zu ersetzen, und man kann es für Zeilenumbrüche verwenden:

<xsl:template name="replace.string.section">
  <xsl:param name="in.string"/>
  <xsl:param name="in.characters"/>
  <xsl:param name="out.characters"/>
  <xsl:choose>
    <xsl:when test="contains($in.string,$in.characters)">
      <xsl:value-of select="concat(substring-before($in.string,$in.characters),$out.characters)"/>
      <xsl:call-template name="replace.string.section">
        <xsl:with-param name="in.string" select="substring-after($in.string,$in.characters)"/>
        <xsl:with-param name="in.characters" select="$in.characters"/>
        <xsl:with-param name="out.characters" select="$out.characters"/>
      </xsl:call-template>
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="$in.string"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template> 

Nennen Sie es wie folgt (in diesem Beispiel ersetzt Zeilenumbrüche in dem $ some.string Variable mit einem Leerzeichen):

    <xsl:call-template name="replace.string.section">
        <xsl:with-param name="in.string" select="$some.string"/>
        <xsl:with-param name="in.characters" select="'&#xA;'"/>
        <xsl:with-param name="out.characters" select="' '"/>
    </xsl:call-template>
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top