2009-09-23 24 views
36

Ich verwende XML, um eine kleine Kontaktliste zu speichern und versuche, eine XSL-Vorlage zu schreiben, die sie in eine CSV-Datei umwandeln wird. Das Problem, das ich habe, ist mit Leerzeichen in der Ausgabe.XSLT - Entfernen von Leerzeichen aus der Vorlage

Der Ausgang:

Friend, John, Smith, Home, 
     123 test, 
     Sebastopol, 
     California, 
     12345, 
    Home 1-800-123-4567, Personal [email protected] 

Ich habe eingekerbten/Abstand sowohl die Quelle als XML-Datei und die zugehörige XSL-Vorlage, um es einfacher zu lesen und zu entwickeln, aber alle, dass zusätzliche Leerraum wird sich in den Ausgang bekommen . Der XML-Code selbst enthält keine zusätzlichen Leerzeichen in den Knoten, die direkt außerhalb der Knoten für die Formatierung liegen. Dies gilt auch für XSLT.

Damit die CSV-Datei gültig ist, muss jeder Eintrag in einer eigenen Zeile stehen und nicht unterbrochen sein. Abgesehen davon, dass der gesamte zusätzliche Leerraum aus XML und XSLT entfernt wird (was nur eine lange Codezeile darstellt), gibt es eine andere Möglichkeit, den Leerraum in der Ausgabe loszuwerden?

Edit: Hier ist ein kleines XML-Beispiel:

<PHONEBOOK> 
    <LISTING> 
     <FIRST>John</FIRST> 
     <LAST>Smith</LAST> 
     <ADDRESS TYPE="Home"> 
      <STREET>123 test</STREET> 
      <CITY>Sebastopol</CITY> 
      <STATE>California</STATE> 
      <ZIP>12345</ZIP> 
     </ADDRESS> 
     <PHONE>1-800-123-4567</PHONE> 
     <EMAIL>[email protected]</EMAIL> 
     <RELATION>Friend</RELATION> 
    </LISTING> 
</PHONEBOOK> 

Und hier ist die XSLT:

<?xml version="1.0" ?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output method="text" /> 

<xsl:template match="/"> 
    <xsl:for-each select="//LISTING"> 
    <xsl:value-of select="RELATION" /><xsl:text>, </xsl:text> 
    <xsl:value-of select="FIRST" /><xsl:text>, </xsl:text> 
    <xsl:value-of select="LAST" /><xsl:text>, </xsl:text> 

    <xsl:if test="ADDRESS"> 
    <xsl:for-each select="ADDRESS"> 
     <xsl:choose> 
     <xsl:when test="@TYPE"> 
     <xsl:value-of select="@TYPE" />, 
     </xsl:when> 
      <xsl:otherwise> 
      <xsl:text>Home </xsl:text> 
      </xsl:otherwise> 
     </xsl:choose> 
     <xsl:value-of select="STREET" />, 
     <xsl:value-of select="CITY" />, 
     <xsl:value-of select="STATE" />, 
     <xsl:value-of select="ZIP" />, 
    </xsl:for-each> 
    </xsl:if> 

    <xsl:for-each select="PHONE"> 
     <xsl:choose> 
     <xsl:when test="@TYPE"> 
     <xsl:value-of select="@TYPE" /> 
     </xsl:when> 
     <xsl:otherwise><xsl:text>Home </xsl:text></xsl:otherwise> 
     </xsl:choose> 
    <xsl:value-of select="." /><xsl:text >, </xsl:text> 
    </xsl:for-each> 

    <xsl:if test="EMAIL"> 
    <xsl:for-each select="EMAIL"> 
     <xsl:choose> 
     <xsl:when test="@TYPE"> 
     <xsl:value-of select="@TYPE" /><xsl:text > </xsl:text> 
     </xsl:when> 
     <xsl:otherwise><xsl:text >Personal </xsl:text></xsl:otherwise> 
     </xsl:choose> 
     <xsl:value-of select="." /><xsl:text >, </xsl:text> 
    </xsl:for-each> 
    </xsl:if> 
    <xsl:text>&#10;&#13;</xsl:text> 
    </xsl:for-each> 
</xsl:template> 

</xsl:stylesheet> 
+4

Warum verwenden Sie 'disable-output-escaping' auf jedem' '? Sie brauchen das nicht für ''. Aus XSLT 1.0-Spezifikation: "Die Textausgabemethode ignoriert das Attribut disable-output-escaping, da kein Ausgabe-Escaping ausgeführt wird." –

Antwort

74

In XSLT wird standardmäßig Leerraum beibehalten, da es sich sehr wohl um relevante Daten handeln kann.

Der beste Weg, um unerwünschten Leerraum in der Ausgabe zu verhindern, ist es nicht, ihn an erster Stelle zu erstellen.Sie nicht tun:

<xsl:template match="foo"> 
    foo 
</xsl:template> 

weil die "\n··foo\n" ist, vom Standpunkt des Prozessors Ansicht. Eher tun

<xsl:template match="foo"> 
    <xsl:text>foo</xsl:text> 
</xsl:template> 

Leerraum im Stylesheet wird ignoriert, solange es nur zwischen XML-Elementen auftritt. Einfach ausgedrückt: Verwenden Sie niemals "nackten" Text irgendwo in Ihrem XSLT-Code, schließen Sie ihn immer in ein Element ein.

Auch unter Verwendung eines unspezifischen:

<xsl:apply-templates /> 

ist problematisch, da die Standard-XSLT-Regel für Textknoten sagt „sie an den Ausgang kopieren“. Dies gilt auch für "white-space-only" -Knoten. Zum Beispiel:

<xml> 
    <data> value </data> 
</xml> 

enthält drei Textknoten:

  1. "\n··" (direkt nach <xml>)
  2. "·value·"
  3. "\n" (rechts vor </xml>)

Um zu vermeiden, dass # 1 und # 3 schleichen sich in die Ausgabe ein der häufigste Grund für unerwünschte Leerzeichen ist), können Sie die Standardregel für Textknoten überschreiben, indem Sie eine leere Vorlage deklarieren:

<xsl:template match="text()" /> 

Alle Textknoten sind nun stumm geschaltet und Textausgabe muss explizit erstellt werden:

<xsl:value-of select="data" /> 

Um white-space von einem Wert zu entfernen, können Sie die normalize-space() XSLT-Funktion verwenden:

<xsl:value-of select="normalize-space(data)" /> 

Aber Vorsicht, da die Funktion keine WHI normalisieren der in der Kette gefundene te-Raum, z. "·value··1·" würde "value·1" werden.

Zusätzlich können Sie die <xsl:strip-space> und <xsl:preserve-space> Elemente verwenden, obwohl dies normalerweise nicht notwendig ist (und ich persönlich bevorzuge explizite Leerraumbehandlung wie oben angegeben).

7

standardmäßig XSLT-Vorlagen <xsl:preserve-space> gesetzt haben, die Leerzeichen in der Ausgabe halten . Sie können <xsl:strip-space elements="*"> hinzufügen, um es an zu teilen, wo Whitespace gelöscht werden soll.

Sie können auch eine normalize-space-Richtlinie, wie so umfassen müssen:

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

Hier ein example for preserve/strip space from W3 Schools ist.

+9

W3 Schulen! = W3 Referenz, die W3 Referenz ist hier -> http://www.w3.org/TR/xslt#strip – Skuld

2

So weit wie entfernen Tabs, aber separate Zeilen beibehalten, habe ich versucht, die folgende XSLT 1.0 Ansatz, und es funktioniert ziemlich gut. Ihre Verwendung von Version 1.0 oder 2.0 hängt weitgehend davon ab, welche Plattform Sie verwenden. Es sieht so aus, als ob die .NET-Technologie immer noch von XSLT 1.0 abhängig ist. Daher sind Sie auf extrem unordentliche Vorlagen beschränkt (siehe unten). Wenn Sie Java oder etwas anderes verwenden, beachten Sie bitte den viel saubereren XSLT 2.0-Ansatz, der ganz unten aufgeführt ist.

Diese Beispiele sollen von Ihnen erweitert werden, um Ihre spezifischen Bedürfnisse zu erfüllen. Ich verwende hier die Tabs als Beispiel, aber dies sollte generisch genug sein, um erweiterbar zu sein.

XML:

<?xml version="1.0" encoding="UTF-8"?> 
<text> 
     adslfjksdaf 

       dsalkfjdsaflkj 

      lkasdfjlsdkfaj 
</text> 

... und die XSLT 1.0-Vorlage (erforderlich, wenn Sie .NET verwenden):

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 
<xsl:template name="search-and-replace"> 
    <xsl:param name="input"/> 
    <xsl:param name="search-string"/> 
    <xsl:param name="replace-string"/> 
    <xsl:choose> 
    <xsl:when test="$search-string and 
        contains($input,$search-string)"> 
     <xsl:value-of 
      select="substring-before($input,$search-string)"/> 
     <xsl:value-of select="$replace-string"/> 
     <xsl:call-template name="search-and-replace"> 
     <xsl:with-param name="input" 
       select="substring-after($input,$search-string)"/> 
     <xsl:with-param name="search-string" 
       select="$search-string"/> 
     <xsl:with-param name="replace-string" 
       select="$replace-string"/> 
     </xsl:call-template> 
    </xsl:when> 
    <xsl:otherwise> 
     <xsl:value-of select="$input"/> 
    </xsl:otherwise> 
    </xsl:choose> 
    </xsl:template>     
    <xsl:template match="text"> 
    <xsl:call-template name="search-and-replace"> 
    <xsl:with-param name="input" select="text()" /> 
    <xsl:with-param name="search-string" select="'&#x9;'" /> 
    <xsl:with-param name="replace-string" select="''" /> 
    </xsl:call-template>  
    </xsl:template> 
</xsl:stylesheet> 

XSLT 2.0 diese trivial mit der replace Funktion macht:

<?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" 
     exclude-result-prefixes="xs" 
     version="2.0"> 
<xsl:template match="text"> 
    <xsl:value-of select="replace(text(), '&#x9;', '')" /> 
</xsl:template> 
</xsl:stylesheet> 
1

Andere haben bereits auf das allgemeine Problem hingewiesen. Spezifische für Ihren Sheet ist, dass Sie <xsl:text> für Kommas vergessen:

<xsl:choose> 
    <xsl:when test="@TYPE"> 
    <xsl:value-of select="@TYPE" />, 
    </xsl:when> 
    <xsl:otherwise>Home </xsl:otherwise> 
    </xsl:choose> 
    <xsl:value-of select="STREET" />, 
    <xsl:value-of select="CITY" />, 
    <xsl:value-of select="STATE" />, 
    <xsl:value-of select="ZIP" />, 

Dieses Leerzeichen machen jedes Komma signifikante folgenden, und so endet es in der Ausgabe auf. Wenn Sie jedes Komma in <xsl:text> umbrechen, verschwindet das Problem.

Auch loswerden disable-output-escaping. Es führt hier nichts aus, da Sie kein XML ausgeben.

1

Fügen Sie eine Vorlage in Ihr Xslt

<xsl:template match="text()"/> 
+0

Warum? Wie? Danke deine Antwort, aber gib immer mehr Infos. – peterh

0

Meine previouse Antwort ist falsch, alle Kommata müssen Ausgabe über Tag 'Text'

<?xml version="1.0" ?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="text"/> 
    <xsl:template match="/PHONEBOOK"> 
     <xsl:for-each select="LISTING"> 
      <xsl:value-of select="RELATION" /><xsl:text>, </xsl:text> 
      <xsl:value-of select="FIRST" /><xsl:text>, </xsl:text> 
      <xsl:value-of select="LAST" /><xsl:text>, </xsl:text> 

       <xsl:for-each select="ADDRESS"> 
        <xsl:choose> 
         <xsl:when test="@TYPE"> 
          <xsl:value-of select="@TYPE" /><xsl:text>,</xsl:text> 
         </xsl:when> 
         <xsl:otherwise><xsl:text>Home </xsl:text></xsl:otherwise> 
        </xsl:choose> 
       <xsl:value-of select="STREET/text()" /><xsl:text>,</xsl:text> 
        <xsl:value-of select="CITY/text()" /><xsl:text>,</xsl:text> 
        <xsl:value-of select="STATE/text()" /><xsl:text>,</xsl:text> 
        <xsl:value-of select="ZIP/text()" /><xsl:text>,</xsl:text> 
       </xsl:for-each> 

      <xsl:for-each select="PHONE"> 
       <xsl:choose> 
        <xsl:when test="@TYPE"> 
         <xsl:value-of select="@TYPE" /> 
        </xsl:when> 
        <xsl:otherwise><xsl:text>Home </xsl:text></xsl:otherwise> 
       </xsl:choose> 
       <xsl:value-of select="." /><xsl:text >, </xsl:text> 
      </xsl:for-each> 

      <xsl:if test="EMAIL"> 
       <xsl:for-each select="EMAIL"> 
        <xsl:choose> 
         <xsl:when test="@TYPE"> 
          <xsl:value-of select="@TYPE" /><xsl:text > </xsl:text> 
         </xsl:when> 
         <xsl:otherwise><xsl:text >Personal </xsl:text></xsl:otherwise> 
        </xsl:choose> 
        <xsl:value-of select="." /><xsl:text >, </xsl:text> 
       </xsl:for-each> 
      </xsl:if> 
      <xsl:text>&#10;&#13;</xsl:text> 
     </xsl:for-each> 
    </xsl:template> 
    <xsl:template match="text()|@*"> 
     <xsl:text>-</xsl:text> 
    </xsl:template> 

</xsl:stylesheet> 
0

den Code ändern, die wir roh XML-Format verwendet Datei durch Entfernen unter Linien entfernt zusätzliche weiße Leerzeichen, die im exportierten Excel hinzugefügt wurden.

Bei der Formatierung mit eingerückten Eigenschaften fügt das System zusätzliche Leerräume hinzu.

Kommentarzeilen im Zusammenhang mit der Formatierung von XML wie unter Linie und versuchen.

xmlWriter.Formatting = System.Xml.Formatting.Indented; 
Verwandte Themen