2009-10-15 13 views
5

Uso l'XML-API Java (6) per applicare una trasformazione xslt su un documento html dal Web. Questo documento è xhtml ben formato e quindi contiene una specifica DTD valida (<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">). Ora si verifica un problema: trasformazione Uppon il processore XSLT tenta di scaricare la DTD e il server w3 lo nega con un errore HTTP 503 (a causa di Bandwith Limitation da w3).Java, xml, XSLT: prevenzione convalida DTD

Come è possibile impedire al processore XSLT di scaricare il dtd? Non ho bisogno del mio documento di input convalidato.

Source è:

import javax.xml.transform.Source; 
import javax.xml.transform.Transformer; 
import javax.xml.transform.TransformerFactory; 
import javax.xml.transform.stream.StreamResult; 
import javax.xml.transform.stream.StreamSource; 

-

String xslt = "<?xml version=\"1.0\"?>"+ 
    "<xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">"+ 
    " <xsl:output method=\"text\" />"+   
    " <xsl:template match=\"//html/body//div[@id='bodyContent']/p[1]\"> "+ 
    "  <xsl:value-of select=\".\" />"+ 
    "  </xsl:template>"+ 
    "  <xsl:template match=\"text()\" />"+ 
    "</xsl:stylesheet>"; 

    try { 
    Source xmlSource = new StreamSource("http://de.wikipedia.org/wiki/Right_Livelihood_Award"); 
    Source xsltSource = new StreamSource(new StringReader(xslt)); 
    TransformerFactory ft = TransformerFactory.newInstance(); 

    Transformer trans = ft.newTransformer(xsltSource); 

    trans.transform(xmlSource, new StreamResult(System.out)); 
    } 
    catch (Exception e) { 
    e.printStackTrace(); 
    } 

ho letto le seguenti quesitons qui su SO, ma tutti usano un altro XML-Api:

Grazie!

risposta

5

Recentemente ho avuto questo problema durante unmarshalling XML utilizzando JAXB. La risposta è stata quella di creare una SAXSource da XmlReader e InputSource, quindi passarla al metodo unmarshaller di UnMarshaller di JAXB. Per evitare di caricare il DTD esterno, ho impostato un EntityResolver personalizzato su XmlReader.

SAXParserFactory spf = SAXParserFactory.newInstance(); 
SAXParser sp = spf.newSAXParser(); 
XMLReader xmlr = sp.getXMLReader(); 
xmlr.setEntityResolver(new EntityResolver() { 
    public InputSource resolveEntity(String pid, String sid) throws SAXException { 
     if (sid.equals("your remote dtd url here")) 
      return new InputSource(new StringReader("actual contents of remote dtd")); 
     throw new SAXException("unable to resolve remote entity, sid = " + sid); 
    } }); 
SAXSource ss = new SAXSource(xmlr, myInputSource); 

Come scritto, questa entità di risoluzione personalizzato un'eccezione se è mai chiesto di risolvere un soggetto diverso da quello che si desidera risolvere. Se vuoi solo che passi in avanti e carichi l'entità remota, rimuovi la linea "getta".

+1

Nel caso qualcuno abbia gli stessi problemi: questo porta nella giusta direzione (ecco perché ho accettato la risposta). Se non vuoi restituire il DTD, puoi anche restituirne uno vuoto. – theomega

+1

Per favore correggi le maiuscole: 'XmlReader' dovrebbe essere 'XMLReader' – wau

-1

è necessario essere utilizzando javax.xml.parsers.DocumentBuilderFactory

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); 
factory.setValidating(false); 
DocumentBuilder builder = factory.newDocumentBuilder(); 
InputSource src = new InputSource("http://de.wikipedia.org/wiki/Right_Livelihood_Award") 
Document xmlDocument = builder.parse(src.getByteStream()); 
DOMSource source = new DOMSource(xmlDocument); 
TransformerFactory tf = TransformerFactory.newInstance(); 
Transformer transformer = tf.newTransformer(xsltSource); 
transformer.transform(source, new StreamResult(System.out)); 
+0

Grazie per la risposta, ma questo codice in realtà getta la stessa eccezione: 'java.io.IOException: il server ha restituito il codice di risposta HTTP: 503 per l'URL: http: // www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd' Devi cambiare' src.getByteStream() 'per' src' nella riga 5 per farlo funzionare, ma c'è sempre la stessa eccezione. – theomega

+1

Questo non cambia nulla. È possibile analizzare il documento durante la trasformazione dall'origine del flusso, prima della trasformazione in DOMSource, ma in ogni caso si verificherà un'eccezione DTD mancante.Quindi questa "soluzione" non risolve nulla e solo inganna. – mvmn

3

impostazione di una funzione nella vostra DocumentBuilderFactory Prova:

URL url = new URL(urlString); 
InputStream is = url.openStream(); 
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); 
dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); 
DocumentBuilder db; 
db = dbf.newDocumentBuilder(); 
Document result = db.parse(is); 

In questo momento mi sto vivendo gli stessi problemi all'interno XSLT (2) quando si chiama la funzione di documento di analizzare XHTML-pagine esterne.

0

se si utilizza

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); 

si può provare disabilitare la convalida DTD con il codice fllowing:

dbf.setValidating(false); 
+0

Vedere la risposta di Chris, è esattamente la stessa cosa. – theomega

2

Le risposte precedenti mi hanno portato a una soluzione, ma non è stato ovvio per me così ecco uno completo:

private void convert(InputStream xsltInputStream, InputStream srcInputStream, OutputStream destOutputStream) throws SAXException, ParserConfigurationException, 
     TransformerFactoryConfigurationError, TransformerException, IOException { 
    //create a parser with a fake entity resolver to disable DTD download and validation 
    XMLReader xmlReader = SAXParserFactory.newInstance().newSAXParser().getXMLReader(); 
    xmlReader.setEntityResolver(new EntityResolver() { 
     public InputSource resolveEntity(String pid, String sid) throws SAXException { 
      return new InputSource(new ByteArrayInputStream(new byte[] {})); 
     } 
    }); 
    //create the transformer 
    Source xsltSource = new StreamSource(xsltInputStream); 
    Transformer transformer = TransformerFactory.newInstance().newTransformer(xsltSource); 
    //create the source for the XML document which uses the reader with fake entity resolver 
    Source xmlSource = new SAXSource(xmlReader, new InputSource(srcInputStream)); 
    transformer.transform(xmlSource, new StreamResult(destOutputStream)); 
}