2010-09-24 19 views
6

Ho provato a passare uno w3c.dom.Document, Element e NodeList come parametri a una trasformazione xslt.passaggio di nodi xml/documenti/frammenti come parametri a xslt

Voglio essere in grado di elaborare entro l'XSLT:

<xsl:param name="links" /> 
<xsl:template match="/"> 
    <record> 
     <xsl:for-each select="$links/*"> 
      <test /> 
     </xsl:for-each> 
    </record> 
</xsl:template> 

passo il parametro come:

 Document params = createLinksParams(links); 
     transformer.setParameter("links", params); 

ottengo questa eccezione:

'di conversione non valido da 'com.sun.org.apache.xerces.internal.dom.DocumentImpl' a 'nodo-set'. '

ho provato anche exslt:node-set(), xalan:nodeset() ecc, ma non funziona.

Sembra che internamente xalan escluda la propria implementazione del Nodo.

Come posso fare qualcosa di simile senza incorrere in questo problema?

Non riesco a utilizzare document($param) perché costruisco il documento al volo.

risposta

3

(pubblicazione una nuova risposta, come il precedente non ha risolto il problema e questo nuovo è radicalmente diverso dal precedente)

sembra essere un problema noto con xalan compilazione processore (XALANJ-2057, How can I pass a node as parameter to translets for XSLTC Processor).

Quindi, quali sono le alternative?

  1. pasticciare con URI come delineato in una risposta al messaggio How can I pass a node as parameter to translets for XSLTC Processor
  2. Invece di Xalan compilazione processore (XSLTC), uso xalan processore interpretativa. O qualsiasi altro processore XSLT che supporti tale comportamento.
  3. Utilizzare DTMAxisIterator invece, anche delineato in una risposta al post How can I pass a node as parameter to translets for XSLTC Processor - non so se funzionerà, però.
  4. creare una nuova struttura DOM, unendo la tua "parametro" DOM ​​e l'ingresso XSLT documento originale
+0

Grazie, ho optato per 4 – ithkuil

+1

Soluzione 3 non sembra funzionare quando il nodo da passare come parametro proviene da un documento DOM che non è il documento che viene trasformato. – ithkuil

0

Se si guarda il Document JavaDoc, è possibile vedere che estende l'interfaccia Node ma non NodeList. Non so se funzionerà, ma potresti provare a passare in params.getChildNodes() anziché parametri.

+0

purtroppo anche provato a passare il NodeList ma senza fortuna – ithkuil

+0

Forse è legato a questo bug? http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5059947 –

+0

Ad ogni modo, suggerirei di prendere lo stacktrace di quell'errore e di rintracciare nel codice sorgente Xalan la circostanza specifica quando viene lanciata questa eccezione. –

0

Ecco un esempio di lavoro con l'URIResolver Gambit, # 1 nella lista delle soluzioni:

import javax.xml.transform.Source; 
import javax.xml.transform.Transformer; 
import javax.xml.transform.TransformerException; 
import javax.xml.transform.TransformerFactory; 
import javax.xml.transform.URIResolver; 
import javax.xml.transform.stream.StreamResult; 
import javax.xml.transform.stream.StreamSource; 
import java.io.StringReader; 
import java.io.StringWriter; 

public class XSLTest { 
    public static void main(String[] args) { 

     class MyResolver implements URIResolver { 
      String _xml; 
      MyResolver(String xml) { _xml = xml; } 
      @Override 
      public Source resolve(String href, String base) throws TransformerException { 
       return new StreamSource(new StringReader(_xml)); 
      } 
     } 

     String lookup = 
      "<?xml version='1.0' encoding='utf-8'?>\n" + 
      "<urls>\n" + 
      " <url id='google'>https://www.google.com</url>\n" + 
      " <url id='yahoo'>https://www.yahoo.com</url>\n" + 
      " <url id='apple'>https://www.apple.com</url>\n" + 
      "</urls>"; 

     String main = 
      "<?xml version='1.0' encoding='utf-8'?>" + 
      "<list>"+ 
      " <link ref='yahoo'>Yahoo</link>"+ 
      " <link ref='google'>Google</link>"+ 
      "</list>"; 

     String xsl = 
      "<?xml version='1.0' encoding='UTF-8'?>\n" + 
      "<xsl:stylesheet version='1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>\n" + 
      " <xsl:param name='lookup-doc' />\n" + 
      " <xsl:variable name='lookup' select='document($lookup-doc)'/>\n" + 
      " <xsl:template match='/'>\n" + 
      "  <xsl:for-each select='//link'>\n" + 
      "   <xsl:variable name='ref' select='@ref'/>\n" + 
      "   <xsl:element name='a'>\n" + 
      "    <xsl:attribute name='href'>\n" + 
      "     <xsl:value-of select='$lookup//url[@id=$ref]'/>\n" + 
      "    </xsl:attribute>\n" + 
      "    <xsl:value-of select='text()'/>\n" + 
      "   </xsl:element>\n" + 
      "  </xsl:for-each>\n" + 
      " </xsl:template>\n" + 
      "</xsl:stylesheet>"; 

     try { 

      // xsl doc 
      Source xsltSource = new StreamSource(new StringReader(xsl)); 

      TransformerFactory transFact = TransformerFactory.newInstance(); 
      Transformer trans = transFact.newTransformer(xsltSource); 

      // main doc 
      Source mainSource = new StreamSource(new StringReader(main)); 

      // lookup doc - stage it in the URI resolver 
      trans.setURIResolver(new MyResolver(lookup)); 
      // dummy URL, you could use different values here to 
      // support multiple document parameters 
      trans.setParameter("lookup-doc", "xml://lookup"); 

      StringWriter out = new StringWriter(); 
      trans.transform(mainSource, new StreamResult(out)); 

      System.out.println(out.toString()); 

     } catch (TransformerException e) { 
      System.err.println("It's the wrong trousers Gromit, and they've gone wrong!"); 
      e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. 
     } 

    } 
} 

ho avuto anche una versione funzionante dove ho messo il sorgente XML nel l'URI come

xml://<urls><url><url id='google'>https://www.google.com</url>... 

ma ho immaginato che potrebbe incorrere in limiti di lunghezza da qualche parte.

4

ho trovato una soluzione (qui: XSLT Processing with Java : passing xml content in parameter), che può funzionare per il vostro caso così:

String urls = "<urls><url id='google'>https://www.google.com</url>..."; 
trans.setParameter("lookupdoc", new StreamSource(new StringReader(urls))); 

invece di creare un uriresolver da una stringa, basta creare una fonte di flusso da un lettore di stringa e passarla al foglio di stile.

Dopo di che, sono stato in grado di accedere al documento normalmente come XML:

<xsl:param name="lookupdoc"><urls/></xsl:param> 
... 
<xsl:variable name="googleurl" select="$lookupdoc/@id='google"/> 

non prova con xalan, ma forse la risposta sarà aiutare gli altri che inciampano su questa domanda :)