2010-09-19 11 views
7

È possibile passare XML a un modello XSL tramite un parametro? Ad esempio, di seguito ho il modello di chiamata modello bodytest1 che passa alcuni XML tramite il parametro var1. Ho quindi tentare di raggiungere a piedi il nodo di a utilizzando XPATHXSL, utilizzando XML come parametro per il modello

<xsl:template name="test1"> 
    <xsl:param name="var1" /> 
    <fo:block> 
     <xsl:value-of select="$var1/a" /> 
    </fo:block> 
</xsl:template> 

<xsl:template name="body"> 
    <xsl:call-template name="test1"> 
     <xsl:with-param name="var1" > 
      <a>foo</a> 
     </xsl:with-param> 
    </xsl:call-template> 
</xsl:template> 

Il problema è, questo fa sì che il mio XSL interprete a fallire con un messaggio di errore inutile. Sono costretto a utilizzare un sistema di fornitori closed source per la generazione di documenti, quindi non sono in grado di eseguire il debug. Ma prima di approfondire l'argomento, cerco conferma che si tratti di un uso valido di XSL.

+1

Buona domanda (+1). Vedi la mia risposta per una spiegazione dettagliata e una soluzione. –

risposta

14
<xsl:template name="body"> 
    <xsl:call-template name="test1"> 
     <xsl:with-param name="var1" > 
      <a>foo</a> 
     </xsl:with-param> 
    </xsl:call-template> 
</xsl:template> 

Il parametro $var1 passata al template è difficilmente utilizzabile in XSLT 1.0/XPath 1.0 a causa del famigerato RTF (Risultato-Tree Fragment) tipo.

Dal W3C XSLT 1.0 spec:.

11,1 dei risultati Albero Frammenti

variabili introducono un ulteriore tipo di dato in il linguaggio delle espressioni. Questo tipo di dati aggiuntivo è chiamato risultato frammento di albero. Una variabile può essere associata a a un frammento di albero dei risultati anziché a uno dei quattro tipi di dati XPath di base (stringa, numero, booleano, set di nodi). Un frammento di albero risultato rappresenta un frammento dell'albero dei risultati. Un risultato Il frammento di albero viene trattato in modo equivalente a in un set di nodi che contiene solo un nodo radice singola . Tuttavia, le operazioni consentite su un albero dei risultati Il frammento è un sottoinsieme di quelle consentite su un set di nodi. Un può essere impiegato su un risultato albero frammento solo se tale operazione sarebbe consentito su una stringa (l'operazione sulla stringa può comportare prima convertire la stringa in numero o boolean). In particolare, lo non può utilizzare gli operatori /, //, e [] nell'albero dei risultati frammenti. Quando un'operazione consentita viene eseguita su un frammento di albero dei risultati , viene eseguita esattamente come nel set di nodi equivalente.

Quando un frammento albero risultato viene copiato nell'albero risultato (vedi [11.3 Utilizzo Valori di variabili e parametri con xsl: copy-of]), poi tutti i nodi che sono figli del nodo radice in l'equivalente set di nodi viene aggiunto nella sequenza all'albero dei risultati.

espressioni possono restituire solo i valori di tipo frammento albero risultato per riferimento a variabili del risultato tipo albero frammento o chiamando estensione funzioni che restituiscono un albero risultato frammento o di ottenere una proprietà di sistema il cui valore è un frammento albero risultato .

Per aggirare questa decisione di progettazione paralizzante, quasi ogni processore XSLT ha una sua funzione di estensione, di solito chiamato xxx:node-set() dove il prefisso xxx deve essere associato a uno spazio dei nomi vendor-definito.

Soluzione:

trovare esattamente quello che è il nome di questa funzione di estensione offerto dal fornitore processore XSLT.

Oppure, se il processore XSLT supporta EXSLT, utilizzare la funzione di estensione exsl:node-set() come definito da EXSLT.

Ecco alcuni spazi dei nomi specifici del produttore:

MSXML e .NET XslCompiledTransform, XslCompiledTransform:

xmlns:vendor="urn:schemas-microsoft-com:xslt" 

Xalan (nota, il nome della funzione è:! xxx:nodeset()):

xmlns:vendor="http://xml.apache.org/xalan" 

Sax on (6.x):

xmlns:vendor="http://icl.com/saxon" 

Altova:

xmlns:vendor="http://www.altova.com/xslt-extensions" 

Tutti i processori che implementano XSLT EXSLT:

xmlns:vendor="http://exslt.org/common" 

Nel caso il corpo di il <xsl:param> non è dinamica ally costruito, si può evitare la funzione

xxx:node-set() nel seguente modo:

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

<xsl:variable name="vrtfparamXML"> 
    <a> 
    <b>foo</b> 
    </a> 
</xsl:variable> 

<xsl:variable name="vparamXML" select= 
"document('')/*/xsl:variable 
       [@name='vrtfparamXML']/*"/> 

<xsl:template match="/"> 
    <xsl:copy-of select="$vparamXML/b"/> 
</xsl:template> 
</xsl:stylesheet> 

quando questa trasformazione viene applicato su qualsiasi documento XML (non utilizzato), il risultato è il bambino desiderato del RTF :

<b xmlns:xsl="http://www.w3.org/1999/XSL/Transform">foo</b> 

Nota: XSLT 2.0/XPath 2.0 sbarazzati del "tipo" RTF e là non ha alcun problema di accesso alberi temporanei e navigare usando tutta la potenza di XPath 2.0

+2

Apprezzo la tua risposta approfondita Dimitre. Contatterò il mio fornitore e vedrò se tale estensione è possibile. – Mike

+0

@Mike: prego. Per comodità, ho modificato la mia risposta per fornire gli spazi dei nomi utilizzati da alcuni dei processori XSLT. –

+1

Ho trovato che il mio processore include il supporto per exsl. Grazie ancora per il vostro aiuto, questo mi permetterà di migliorare notevolmente il mio disegno – Mike

Problemi correlati