Frammenti di nodi nelle trasformazioni

I frammenti di nodi, detti anche frammenti di struttura risultato, sono semplicemente un particolare tipo di gruppo di nodi. Sui frammenti di nodi è possibile eseguire le stesse funzioni eseguite sui gruppi di nodi. È inoltre possibile utilizzare la funzione node-set() per convertire un frammento di struttura risultato in un gruppo di nodi, quindi utilizzarlo in qualsiasi posizione adatta a un gruppo di nodi.

Un frammento di struttura risultato viene creato utilizzando in un modo specifico un elemento <xsl:variable> o <xsl:param> in un foglio di stile. La sintassi degli elementi variable e parameter è la seguente:

<xsl:param name=Qname select= XPathExpression >
    template body
</xsl:param>

<xsl:variable name=Qname select=XPathExpression >
    template body
</xsl:variable>

Il valore di Qname dell'elemento parameter può essere assegnato in vari modi. È possibile assegnare al parametro un valore predefinito tramite il contenuto restituito dall'espressione XPath nell'attributo select oppure utilizzando il contenuto del corpo del template.

Anche il valore dell'elemento variable può essere assegnato in diversi modi. È possibile assegnarlo tramite il contenuto restituito dall'espressione XPath nell'attributo select oppure utilizzando il contenuto del corpo del template.

Da entrambi gli elementi parameter e variable, nel caso in cui venga assegnato un valore dall'espressione XPath, viene restituito uno dei quattro tipi XPath principali: Boolean, string, number o node set. Se il valore viene assegnato utilizzando un corpo del template non vuoto, verrà restituito un tipo di dati non XPath, cioè un frammento di struttura risultato.

Una query XPath restituisce un tipo di dati che non appartiene ai quattro tipi di oggetti XPath unicamente nel caso in cui una variabile viene associata a un frammento di struttura risultato, anziché a uno dei quattro tipi di dati XPath di base. I frammenti di struttura risultato e il relativo comportamento sono descritti dalle specifiche W3C, all'indirizzo http://www.w3.org/XSLT, dalla sezione 11.1 Result Tree Fragments alla sezione 11.6 Passing Parameters to Templates (informazioni in lingua inglese). Nella sezione 1, Introduction, viene illustrato come i template possano contenere elementi dello spazio dei nomi XSLT che restituiscono o creano frammenti di struttura risultato.

Un frammento di struttura risultato si comporta, teoricamente, come un gruppo di nodi con un unico nodo di primo livello, mentre gli altri nodi restituiti sono nodi figlio. Per visualizzare i nodi figlio a livello di codice, copiare il frammento di struttura risultato nella struttura risultato stessa utilizzando l'elemento <xsl:copy-of>. Questa operazione consente di copiare in sequenza tutti i nodi figlio nella struttura risultato. Il frammento di struttura risultato non farà parte della struttura risultato o dell'output della trasformazione finché non viene utilizzato il comando copy o copy-of.

Per eseguire un'iterazione sui nodi restituiti in un frammento di struttura risultato, utilizzare XPathNavigator. Nel codice di esempio riportato di seguito viene illustrata la creazione di un frammento di struttura risultato in un foglio di stile, chiamando la funzione con un parametro fragment contenente dati XML.

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:msxsl="urn:schemas-microsoft-com:xslt"
                xmlns:user="http://www.adventure-works.com"
                version="1.0">
    <xsl:var name="fragment">
        <node1>
            <node2/>
        </node1>
    <xsl:var>

  <msxsl:script language="C#" implements-prefix="user">
    function NodeFragment(XPathNavigator nav)
    {
      if (nav.HasSelection == false)
        XPathNavigator.MoveToNext();
      return;
    }
  </msxsl:script>
 
    <xsl:template match="/">
            <xsl:value-of select="user:NodeFragment(msxml:node-set($fragment))"/>
    </xsl:template>
</xsl:stylesheet>

Di seguito è riportato un altro esempio in cui viene mostrata una variabile RTF e, quindi, un tipo di frammento di nodo non convertito in un gruppo di nodi. Il frammento viene passato a una funzione script e per esplorare i nodi viene utilizzato XPathNavigator.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:msxsl="urn:schemas-microsoft-com:xslt"
        xmlns:user="http://my.com"
        exclude-result-prefixes="msxsl">

<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>

<xsl:variable name="node-fragment">
    <book>Book1</book>
    <book>Book2</book>
    <book>Book3</book>
    <book>Book4</book>
</xsl:variable>

<msxsl:script implements-prefix="user" language="c#">

<![CDATA[
    string func(XPathNavigator nav)
    {
        bool b = nav.MoveToFirstChild();
        if (b)
            return nav.Value;
        else
            return "Does not exist";
    }

]]>

</msxsl:script>

<xsl:template match="/">
    <first_book>
        <xsl:value-of select="user:func($node-fragment)"/>
    </first_book>
</xsl:template>

</xsl:stylesheet>

Il risultato della trasformazione dei dati XML ottenuto utilizzando questo foglio di stile è illustrato nell'output seguente.

Output

<first_book xmlns:user="http://my.com">Book1</first_book>

Come già ricordato, la funzione node-set consente di convertire un frammento di struttura risultato in un gruppo di nodi. Il nodo risultante contiene sempre un nodo singolo, costituito dal nodo principale della struttura. Se un frammento di struttura risultato viene convertito in un gruppo di nodi, potrà essere utilizzato come un normale gruppo di nodi, ad esempio in un'istruzione for-each oppure nel valore di un attributo select. Nelle righe di codice riportate di seguito viene mostrato un frammento convertito in un gruppo di nodi e utilizzato come tale.

<xsl:for-each select="msxsl:node-set($node-fragment)">

<xsl:value-of select="user:func(msxsl:node-set($node-fragment))"/>

Per esplorare un frammento convertito in un gruppo di nodi non si utilizza più XPathNavigator, bensì XPathNodeIterator.

Nell'esempio seguente, $var è una variabile che rappresenta la struttura dei nodi nel foglio di stile. L'istruzione for-each combinata con la funzione node-set consente all'utente di eseguire un'iterazione su questa struttura come gruppo di nodi.

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:msxsl="urn:schemas-microsoft-com:xslt"
                xmlns:user="http://www.adventure-works.com"
                version="1.0">
    <xsl:variable name="states">
        <node1>AL</node1>
        <node1>CA</node1>
        <node1>CO</node1>
        <node1>WA</node1>
    </xsl:variable>

    <xsl:template match="/">
            <xsl:for-each select="msxsl:node-set($states)"/> 
    </xsl:template>
</xsl:stylesheet>

Di seguito è riportato un altro esempio di variabile RTF, e quindi di tipo frammento di nodi, convertita in gruppo di nodi prima di essere passata a una funzione script come "XPathNodeIterator".

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:msxsl="urn:schemas-microsoft-com:xslt"
        xmlns:user="http://my.com"
        exclude-result-prefixes="msxsl">

<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>

<xsl:variable name="node-fragment">
    <book>Book1</book>
    <book>Book2</book>
    <book>Book3</book>
    <book>Book4</book>
</xsl:variable>

<msxsl:script implements-prefix="user" language="c#">

<![CDATA[
    string func(XPathNodeIterator it)
    {
        it.MoveNext(); 
        return it.Current.Value; 
        //it.Current returns XPathNavigator positioned on the current node
    }

]]>

</msxsl:script>
<xsl:template match="/">
    <books>
        <xsl:value-of select="user:func(msxsl:node-set($node-fragment))"/>
    </books>
</xsl:template>

</xsl:stylesheet>

Il risultato della trasformazione di dati XML con il presente foglio di stile è il seguente:

<books xmlns:user="http://my.com">Book1Book2Book3Book4</books>

Vedere anche

Trasformazioni XSLT con la classe XslTransform | Implementazione del processore XSLT da parte della classe XslTransform | Classe XPathNodeIterator | Membri XPathNodeIterator