2009-09-23 16 views
36

Sto utilizzando XML per memorizzare un piccolo elenco di contatti e sto provando a scrivere un modello XSL che lo trasformerà in un file CSV. Il problema che sto avendo riguarda gli spazi bianchi nell'output.XSLT - rimuove spazi bianchi dal modello

L'output:

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

ho frastagliata distanziati sia il file/XML di origine e il modello XSL associato per rendere più facile la lettura e lo sviluppo, ma tutto ciò che lo spazio vuoto supplementare si sta ottenendo in uscita . Lo stesso XML non ha spazi bianchi extra all'interno dei nodi, solo al di fuori di essi per la formattazione, e lo stesso vale per l'XSLT.

Affinché il file CSV sia valido, ogni voce deve essere sulla propria linea, non suddivisa. Oltre a rimuovere tutto lo spazio bianco extra da XML e XSLT (rendendoli solo una lunga riga di codice), c'è un altro modo per sbarazzarsi degli spazi bianchi nell'output?

Edit: Ecco un piccolo esempio XML:

<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> 

Ed ecco il 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

Perché usi 'disable-output-escaping' su ogni' '? Non è necessario per ''. Dalla specifica XSLT 1.0: "Il metodo di output del testo ignora l'attributo disable-output-escaping, poiché non esegue alcun escape di output." –

risposta

74

In XSLT, lo spazio bianco viene preservato per impostazione predefinita, poiché può benissimo essere dati rilevanti.

Il modo migliore per evitare uno spazio bianco indesiderato nell'output non è quello di crearlo in primo luogo.Non fare:

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

perché questo è "\n··foo\n", dal punto di vista del processore. Piuttosto fare

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

Lo spazio bianco nel foglio di stile viene ignorato finché si verifica solo tra gli elementi XML. In poche parole: non utilizzare mai il testo "nudo" in nessun punto del codice XSLT, racchiuderlo sempre in un elemento.

Inoltre, utilizzando un aspecifico:

<xsl:apply-templates /> 

è problematica, perché la regola XSLT predefinito per il testo nodi dice "copiarli l'uscita". Questo vale anche per i nodi "solo spazi bianchi". Per esempio:

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

contiene tre nodi di testo:

  1. "\n··" (a destra dopo <xml>)
  2. "·value·"
  3. "\n" (a destra prima </xml>)

per evitare che la # 1 e # 3 intrufolarsi nell'output (che è la ragione più comune per gli spazi indesiderati), è possibile ignorare la regola di default per i nodi di testo dichiarando un modello vuoto:

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

Tutti i nodi di testo sono ora disattivato e l'uscita del testo deve essere creato in modo esplicito:

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

Per rimuovere white-space da un valore, è possibile utilizzare la funzione normalize-space() XSLT:

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

Ma attenzione, dal momento che la funzione normalizza eventuali WHI te-spazio trovato nella stringa, ad es. "·value··1·" diventerebbe "value·1".

Inoltre, è possibile utilizzare gli elementi <xsl:strip-space> e <xsl:preserve-space>, sebbene in genere ciò non sia necessario (e personalmente, preferisco la gestione esplicita dello spazio bianco come indicato sopra).

7

Per impostazione predefinita, modelli XSLT hanno <xsl:preserve-space> set, che non mancherà di tenere gli spazi nell'output . È possibile aggiungere <xsl:strip-space elements="*"> per comunicarlo a dove eliminare lo spazio.

Si può anche necessario includere una direttiva normalize-space, in questo modo:

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

Ecco un example for preserve/strip space from W3 Schools.

+9

W3 Schools! = Riferimento W3, il riferimento W3 è qui intorno -> http://www.w3.org/TR/xslt#strip – Skuld

2

Per quanto riguarda la rimozione delle schede ma il mantenimento di righe separate, ho provato il seguente approccio XSLT 1.0 e funziona piuttosto bene. L'utilizzo della versione 1.0 o 2.0 dipende in gran parte dalla piattaforma che stai utilizzando. Sembra che la tecnologia .NET sia ancora dipendente da XSLT 1.0, quindi sei limitato a modelli estremamente disordinati (vedi sotto). Se stai usando Java o qualcos'altro, fai riferimento all'approccio XSLT 2.0 molto più pulito elencato verso il basso.

Questi esempi devono essere estesi da voi per soddisfare le vostre esigenze specifiche. Qui sto usando le schede qui sotto, ma questo dovrebbe essere abbastanza generico da essere estensibile.

XML:

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

       dsalkfjdsaflkj 

      lkasdfjlsdkfaj 
</text> 

... e il modello XSLT 1.0 (richiesto se si utilizza .NET):

<?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 rende questo banale con la funzione replace:

<?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

Altri hanno già evidenziato il problema generale. uno specifico per il vostro foglio di stile è che si è dimenticato <xsl:text> per le virgole:

<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" />, 

Questo rende gli spazi bianchi dopo ogni virgola significativa, e così finisce in uscita. Se si avvolge ogni virgola in <xsl:text>, il problema scompare.

Inoltre, eliminare quello disable-output-escaping. Non fa nulla qui, dal momento che non stai emettendo XML.

1

Aggiungere un modello nel vostro XSLT

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

Perché? Come? Grazie della tua risposta, ma dai sempre maggiori informazioni. – peterh

0

La mia risposta previouse è sbagliata, tutte le virgole devono essere emessi tramite tag 'testo'

<?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

modificare il codice che abbiamo usato per formato XML grezzo il file rimuovendo le righe sottostanti rimuoverà gli spazi bianchi extra aggiunti in excel esportato.

Durante la formattazione con il sistema di proprietà con rientro si aggiungono quegli spazi bianchi extra vuoti.

righe di commento relative alla formattazione xml come sotto la riga e provare.

xmlWriter.Formatting = System.Xml.Formatting.Indented; 
Problemi correlati