2010-05-26 15 views
5

Ho barato ogni volta che ho avuto bisogno di fare un conteggio delle righe in XSLT usando JScript, ma in questo caso non posso farlo. Voglio semplicemente scrivere un contatore di riga in un file di output. Questo esempio di base ha una soluzione semplice:Contatore linea XSLT - è così difficile?

<xsl:for-each select="Records/Record"> 
    <xsl:value-of select="position()"/> 
</xsl:for-each> 

uscita sarebbe:

ecc ...

Ma cosa succede se la struttura è più complessa con foreach nidificati di:

<xsl:for-each select="Records/Record"> 
    <xsl:value-of select="position()"/> 
    <xsl:for-each select="Records/Record"> 
     <xsl:value-of select="position()"/> 
    </xsl:for-each> 
</xsl:for-each> 

Qui, il foreach interno sarebbe solo azzerare il contatore (in modo da ottenere 1, 1, 2, 3, 2, 1, 2, 3, 1, 2 ecc.). Qualcuno sa come posso generare la posizione nel file (ad esempio un numero di righe)?

+0

Ottima domanda (+1). Vedere la mia risposta per una soluzione che produce numeri di riga per il testo. –

risposta

5

Una riga in un file XML non è proprio la stessa cosa di un elemento. Nel tuo primo esempio in realtà non conti le linee - ma il numero di elementi.

Un file XML potrebbe essere la seguente:

<cheeseCollection> 
<cheese country="Cyprus">Gbejna</cheese><cheese>Liptauer</cheese><cheese>Anari</cheese> 
</cheeseCollection> 

O lo stesso identico file XML può apparire così:

<cheeseCollection> 
    <cheese 
     country="Cyprus">Gbejna</cheese> 
    <cheese>Liptauer</cheese> 
    <cheese>Anari</cheese> 
</cheeseCollection> 

cui l'XSLT interpet esattamente lo stesso - non sarà davvero preoccuparsi delle interruzioni di linea.

Pertanto è difficile mostrare i numeri di riga nel modo in cui si desidera utilizzare XSLT: non è pensato per questo tipo di analisi.

Qualcuno mi corregge se ho torto, ma direi che avresti bisogno di Javascript o qualche altro linguaggio di scripting per fare quello che vuoi.

+1

Hai esattamente ragione - la "posizione" (ovvero il numero di riga) è completamente priva di significato in XML poiché gli spazi, inclusi i ritorni a capo, non sono considerati parte dell'albero del documento. – GalacticCowboy

+1

@GalacticCowboy: Gli spazi bianchi * sono * considerati parte dell'albero del documento, sono inclusi nei nodi di testo. – liori

+0

@liori: Penso che intendesse lo spazio tra gli attributi - questo spazio non è un oggetto separato nell'XDM e non è possibile accedervi tramite un'espressione XPath –

6

Mentre è del tutto impossibile per segnare i numeri di riga per la serializzazione di un documento XML (perché questo serializzazione di per sé è ambigua), è perfettamente possibile, e easy, per numerare le righe di testo normale.

Questa trasformazione:

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

<xsl:template match="/"> 
    <xsl:call-template name="numberLines"/> 
</xsl:template> 

<xsl:template name="numberLines"> 
    <xsl:param name="pLastLineNum" select="0"/> 
    <xsl:param name="pText" select="."/> 

    <xsl:if test="string-length($pText)"> 
    <xsl:value-of select="concat($pLastLineNum+1, ' ')"/> 

    <xsl:value-of select="substring-before($pText, '&#xA;')"/> 
    <xsl:text>&#xA;</xsl:text> 

    <xsl:call-template name="numberLines"> 
    <xsl:with-param name="pLastLineNum" 
     select="$pLastLineNum+1"/> 
    <xsl:with-param name="pText" 
     select="substring-after($pText, '&#xA;')"/> 
    </xsl:call-template> 
    </xsl:if> 
</xsl:template> 
</xsl:stylesheet> 

quando applicato su questo documento XML:

<t>The biggest airlines are imposing "peak travel surcharges" 
this summer. In other words, they're going to raise fees 
without admitting they're raising fees: Hey, it's not a $30 
price hike. It's a surcharge! This comes on the heels of 
checked-baggage fees, blanket fees, extra fees for window 
and aisle seats, and "snack packs" priced at exorbitant 
markups. Hotels in Las Vegas and elsewhere, meanwhile, are 
imposing "resort fees" for the use of facilities (in other 
words, raising room rates without admitting they're 
raising room rates). The chiseling dishonesty of these 
tactics rankles, and every one feels like another nail in 
the coffin of travel as something liberating and 
pleasurable. 
</t> 

produce la desiderata linea di numerazione:

1 The biggest airlines are imposing "peak travel surcharges" 
2 this summer. In other words, they're going to raise fees 
3 without admitting they're raising fees: Hey, it's not a $30 
4 price hike. It's a surcharge! This comes on the heels of 
5 checked-baggage fees, blanket fees, extra fees for window 
6 and aisle seats, and "snack packs" priced at exorbitant 
7 markups. Hotels in Las Vegas and elsewhere, meanwhile, are 
8 imposing "resort fees" for the use of facilities (in other 
9 words, raising room rates without admitting they're 
10 raising room rates). The chiseling dishonesty of these 
11 tactics rankles, and every one feels like another nail in 
12 the coffin of travel as something liberating and 
13 pleasurable. 
3

Grazie per le risposte ragazzi - sì sei completamente corretto, alcune funzioni esterne sono l'unico modo per ottenere questo comportamento in XSLT.Per coloro che cercano, è così che ho fatto quando si utilizza un compilato trasformata in Net 3.5:

Creare una classe di supporto per la funzione (s)

/// <summary> 
/// Provides functional support to XSLT 
/// </summary> 
public class XslHelper 
{ 
    /// <summary> 
    /// Initialise the line counter value to 1 
    /// </summary> 
    Int32 counter = 1; 

    /// <summary> 
    /// Increment and return the line count 
    /// </summary> 
    /// <returns></returns> 
    public Int32 IncrementCount() 
    { 
     return counter++; 
    } 
} 

Aggiungere un'istanza a un elenco args per XSLT

XslCompiledTransform xslt = new XslCompiledTransform(); 
xslt.Load(XmlReader.Create(s)); 
XsltArgumentList xslArg = new XsltArgumentList(); 
XslHelper helper = new XslHelper(); 
xslArg.AddExtensionObject("urn:helper", helper); 
xslt.Transform(xd.CreateReader(), xslArg, writer); 

Usalo in voi XSLT

mettere questo nell'elemento dichiarazione di foglio di stile:

xmlns:helper="urn:helper" 

Quindi utilizzare in questo modo:

<xsl:value-of select="helper:IncrementCount()" /> 
1

Generalmente, position() si riferisce al numero del nodo corrente rispetto all'intero gruppo di nodi che si elabora attualmente.

Con l'esempio "nested for-each", è possibile ottenere facilmente la numerazione progressiva quando si interrompe la nidificazione per ogni costrutto e basta selezionare tutti gli elementi desiderati contemporaneamente.

Con questo XML:

<a><b><c/><c/></b><b><c/></b></a> 

un ciclo costrutto come questo

<xsl:for-each "a/b"> 
    <xsl:value-of select="position()" /> 
    <xsl:for-each "c"> 
    <xsl:value-of select="position()" /> 
    </xsl:for-each> 
</xsl:for-each> 

si tradurrà in

11221 
bccbc // referred-to nodes 

ma si potrebbe semplicemente fare questo, invece:

<xsl:for-each "a/b/c"> 
    <xsl:value-of select="position()" /> 
</xsl:for-each> 

e si otterrebbe

123 
ccc // referred-to nodes 
Problemi correlati