Domanda

Essendo relativamente nuovo per XSLT ho quello che spero è una domanda semplice. Ho alcuni file flat XML, che può essere piuttosto grande (ad es. 7MB) che ho bisogno di rendere 'più gerarchica'. Ad esempio, l'XML piatta potrebbe essere simile a questo:

<D0011>
    <b/>
    <c/>
    <d/>
    <e/>
    <b/>
    ....
    ....
</D0011>

e dovrebbe finire per assomigliare a questo:

<D0011>
  <b>
    <c/>
    <d/>
    <e/>
  </b>
  <b>
 ....
 ....
</D0011>

Ho una XSLT lavorare per questo, e diventa essenzialmente una serie di nodi di tutti gli elementi b e quindi utilizza il 'seguente-sibling' all'asse di ottenere una serie di nodi dei nodi seguendo il nodo corrente b (es. Following-sibling :: * [position () = $ nodePos]). Poi la ricorsione viene utilizzata per aggiungere i fratelli nella struttura risultato finché non viene trovato un altro elemento b (ho parametrizzati che, naturalmente, per renderlo più generico).

Ho anche una soluzione che solo invia la posizione nel XML del nodo successivo b e seleziona i nodi dopo che uno dopo l'altro (utilizzando la ricorsione) attraverso una selezione * [position () = $ nodePos].

Il problema è che il tempo per eseguire gli incrementi di trasformazione in modo inaccettabile con la dimensione del file XML. Guardando dentro con XML Spy sembra che sia il 'seguente-sibling' e 'position () =' che prendono il tempo nei due rispettivi metodi.

Quello che ho veramente bisogno è un modo di limitare il numero di nodi nelle selezioni di cui sopra, vengono eseguite in modo meno confronti: ogni volta che la posizione è testato, ogni nodo della serie di nodi è testato per vedere se la sua posizione è quella giusta . C'è un modo per farlo? Altri suggerimenti?

Grazie,

Mike

È stato utile?

Soluzione

Sì, c'è un modo per farlo in modo più efficiente: See Muenchian raggruppamento . Se dopo aver guardato questo hai bisogno di aiuto con i dettagli, fatecelo sapere. La chiave avrete bisogno è qualcosa di simile:

<xsl:key name="elements-by-group" match="*[not(self::b)]"
   use="generate-id(preceding-sibling::b[1])" />

Poi si può iterare gli elementi <b>, e per ciascuno di essi, l'uso key('elements-by-group', generate-id()) per ottenere gli elementi che seguono subito che <b>.

Il compito di "rendere il più gerarchica XML" è talvolta chiamato up-conversion, e lo scenario è un classico caso per esso. Come forse sapete, XSLT 2.0 ha caratteristiche di raggruppamento molto utili che sono più facili da utilizzare rispetto al metodo Muenchian.

Nel tuo caso suona come si usa <xsl:for-each-group group-starting-with="b" /> o, per parametrizzare il nome dell'elemento, <xsl:for-each-group group-starting-with="*[local-name() = 'b']" />. Ma forse avete già considerato che non è possibile utilizzare XSLT 2.0 nel proprio ambiente.

Aggiornamento:

In risposta alla richiesta di parametrizzazione, ecco un modo per farlo senza una chiave. Nota però che potrebbe essere molto più lento, a seconda del processore XSLT.

<xsl:template match="D0011">
   <xsl:for-each select="*[local-name() = $sep]">
      <xsl:copy>
         <xsl:copy-of select="following-sibling::*[not(local-name() = $sep)
               and generate-id(preceding-sibling::*[local-name() = $sep][1]) =
                    generate-id(current())]" />
      </xsl:copy>
   </xsl:for-each>      
</xsl:template>

Come osservato nel commento, è possibile mantenere il miglioramento delle prestazioni delle chiavi definendo diverse chiavi diverse, una per ogni possibile valore del parametro. Quindi si seleziona il tasto da utilizzare utilizzando un <xsl:choose>.

Aggiornamento 2:

Per realizzare l'elemento di gruppo partendo da definire in base /*/*[2], anziché basato su un parametro, uso

<xsl:key name="elements-by-group"
   match="*[not(local-name(.) = local-name(/*/*[2]))]"
   use="generate-id(preceding-sibling::*
                           [local-name(.) = local-name(/*/*[2])][1])" />

<xsl:template match="D0011">
   <xsl:for-each select="*[local-name(.) = local-name(../*[2])]">
      <xsl:copy>
         <xsl:copy-of select="key('elements-by-group', generate-id())"/>
      </xsl:copy>
   </xsl:for-each>
</xsl:template>

Altri suggerimenti

<xsl:key name="k1" match="D0011/*[not(self::b)]" use="generate-id(preceding-sibling::b[1])"/>

<xsl:template match="D0011">
  <xsl:copy>
    <xsl:apply-templates select="b"/>
  </xsl:copy>
</xsl:template>

<xsl:template match="D0011/b">
  <xsl:copy>
    <xsl:copy-of select="key('k1', generate-id())"/>
  </xsl:copy>
</xsl:template>

Questa è la grana fine modello trasversale:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="node()|@*" name="identity">
        <xsl:copy>
            <xsl:apply-templates select="node()[1]|@*"/>
        </xsl:copy>
        <xsl:apply-templates select="following-sibling::node()[1]"/>
    </xsl:template>
    <xsl:template match="b[1]" name="group">
        <xsl:copy>
            <xsl:apply-templates select="following-sibling::node()[1]"/>
        </xsl:copy>
        <xsl:apply-templates select="following-sibling::b[1]" mode="group"/>
    </xsl:template>
    <xsl:template match="b[position()!=1]"/>
    <xsl:template match="b" mode="group">
        <xsl:call-template name="group"/>
    </xsl:template>
</xsl:stylesheet>

Output:

<D0011>
    <b>
        <c></c>
        <d></d>
        <e></e>
    </b>
    <b>
    ....
    ....
    </b>
</D0011>
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top