2011-01-24 12 views
8

Vorrei sapere come spostare i nodi di un livello utilizzando XSLT se sono soddisfatte determinate condizioni. Per fare un esempio dare un'occhiata al seguente sorgente XML:XSLT: Spostare il nodo di livello superiore su

<Settings> 
    <String [...]> 
    <Boolean [...]/> 
    </String> 
</Settings> 

Questo è il file XML che ho come punto di partenza la situazione. Per essere chiari, i nomi dei nodi "Impostazioni", "Stringa", "Booleano" sono nodi speciali che abbiamo definito.

Il problema è che i nodi "booleani" non sono consentiti all'interno dei nodi "String". Ecco perché devo spostare quei nodi "booleani" al livello superiore. L'XML desiderato sarebbe simile a questa:

<Settings> 
    <String [...]></String> 
    <Boolean [...]/> 
</Settings> 

Il XSLT ha anche a lavorare con ogni nodo stringa che ha un nodo booleano pari livello, indipendentemente dalla posizione in XML-albero.

Finora ho imparato che si deve prima copiare tutti i tuoi XML utilizzando una "regola identità" e quindi applicare alcune regole speciali per le trasformazioni desiderate:

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet version="2.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"   
    xmlns:fo="http://www.w3.org/1999/XSL/Format" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" 
    xmlns:fn="http://www.w3.org/2005/xpath-functions"> 

    <!-- Identity rule --> 
    <xsl:template match="node() | @*"> 
    <xsl:copy> 
     <xsl:apply-templates select="node() | @*"/> 
    </xsl:copy> 
    </xsl:template> 

    <!-- special rules ... --> 

</xsl:stylesheet> 

La cosa sto lottando con la regola per spostare tutti i nodi "booleani" che sono fratelli di nodi "String" un livello in alto. Come lo posso fare?!?

+0

Buona domanda, +1. Vedi la mia risposta per una variazione del modello di progettazione "sovrascrivi la regola dell'identità": ho fornito un override leggermente più accurato. :) –

risposta

6

La mia interpretazione del requisito dà la soluzione, come

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output method="xml" indent="yes"/> 

<xsl:template match="node() | @*"> 
    <xsl:copy> 
     <xsl:apply-templates select="node() | @*"/> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="String"> 
    <xsl:copy> 
     <xsl:apply-templates select="child::node()[not(self::Boolean)]"/> 
    </xsl:copy> 
    <xsl:apply-templates select="Boolean"/> 
</xsl:template> 

</xsl:stylesheet> 
+1

Grazie, Michael. La tua risposta sembra funzionare bene.Solo sarebbe solo proporre una piccola modifica: diventa Con questa modifica vengono copiati anche gli attributi dei nodi String. Grazie mille. – Jens

+0

+1 Risposta corretta. –

3

provare quanto segue:

<!-- copy all --> 
<xsl:template match="*"> 
    <xsl:copy> 
     <xsl:copy-of select="@*" /> 
     <xsl:apply-templates /> 
    </xsl:copy> 
</xsl:template> 

<!-- ignore booleans-inside-strings --> 
<xsl:template match="String/Boolean" /> 

<!-- place the booleans-inside-strings into the settings element --> 
<xsl:template match="Settings"> 
    <xsl:copy> 
     <xsl:copy-of select="//String/Boolean" /> 
     <xsl:apply-templates /> 
    </xsl:copy> 
</xsl:template> 
+1

C'è un motivo per cui non 'match =" @ * | node() "' e 'select =" @ * | node() "' nel tuo modello "copia tutto"? Solo curioso ... – Filburt

+0

Grazie per la risposta. Questo funziona bene per il mio esempio. Ma non funzionerà sempre, poiché copia sempre il nodo booleano nell'elemento impostazioni. La regola dovrebbe copiare l'elemento booleano di un livello in alto. Pensate a Questo dovrebbe trasformare a: Jens

+0

Inoltre, perché la partenza '' // // in 'String/boolean'? –

3

Questa soluzione è abbastanza simile a quella di @ Michae-Kay. Tuttavia, l'imperativo della regola identità è un po 'più precisi - solo String elementi che in realtà hanno un bambino Boolean sono abbinati:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 
<xsl:strip-space elements="*"/> 

<xsl:template match="node()|@*"> 
    <xsl:copy> 
     <xsl:apply-templates select="node()|@*"/> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="String[Boolean]"> 
    <xsl:copy> 
    <xsl:apply-templates select="node()[not(self::Boolean)]|@*"/> 
    </xsl:copy> 
    <xsl:apply-templates select="Boolean"/> 
</xsl:template> 
</xsl:stylesheet> 

quando questa trasformazione viene applicato contro il seguente documento XML:

<Settings> 
    <String> 
     <Boolean /> 
    </String> 
    <String/> 
</Settings> 

The Wanted, risultato corretto è prodotta:

<Settings> 
    <String/> 
    <Boolean/> 
    <String/> 
</Settings> 
+0

potresti anche dare un'occhiata alla mia risposta? Non riesco a trovare un errore che valga la pena di fare downvoting. Non mi importa del downvote stesso, voglio solo vedere se ho perso qualche errore. – Flack

+0

@Flack: Penso che la soluzione sia OK. Devi solo applicare i modelli agli attributi di "Setings" - altrimenti andranno persi. Ho votato più volte la tua risposta, ma per favore aggiungi anche questa soluzione consigliata. –

+0

È stata un'omissione consapevole, a causa del campione fornito dall'OP. Anche se ho scelto di rimuovere la mia risposta in quanto ce ne sono due che sono meglio progettati. In cambio ovviamente. Stavo aspettando il respawn dei voti disponibili. – Flack

Problemi correlati