2009-10-15 18 views
5

Uso Java (6) XML-Api para aplicar una transformación xslt en un documento html desde la web. Este documento está bien formado xhtml y, por lo tanto, contiene una DTD-Spec válida (<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">). Ahora ocurre un problema: Transformación Uppon: el procesador XSLT intenta descargar el DTD y el servidor w3 lo niega mediante un error HTTP 503 (debido a Bandwith Limitation por w3).Java, xml, XSLT: Impedir DTD-Validación

¿Cómo puedo evitar que el XSLT-Processor descargue dtd? No necesito mi documento de entrada validado.

origen es:

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(); 
    } 

leí las siguientes quesitons aquí en SO, pero todos ellos utilizan otra API XML:

Gracias!

Respuesta

5

Recientemente tuve este problema, mientras que unmarshalling XML utilizando JAXB. La respuesta fue crear un SAXSource de un XmlReader y InputSource, luego pasarlo al método unmarshal() de JAXB UnMarshaller. Para evitar cargar la DTD externa, configuré un EntityResolver personalizado en el 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); 

Como está escrito, esta entidad resolución personalizada lanzará una excepción si alguna vez le preguntó a resolver una entidad distinta de la que usted quiere que resolver. Si solo quiere que siga adelante y cargue la entidad remota, elimine la línea "throws".

+1

Por si acaso alguien tiene los mismos problemas: Esto conduce a la dirección correcta (por eso acepté la respuesta). Si no desea devolver la DTD, también puede devolver una DTD vacía. – theomega

+1

Corrija las mayúsculas: 'XmlReader' debe ser 'XMLReader' – wau

-1

Usted necesita utilizar 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

Gracias por la respuesta, pero este código en realidad arroja la misma excepción: 'java.io.IOException: El servidor devolvió el código de respuesta HTTP: 503 para la URL: http: // www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd' Tiene que cambiar' src.getByteStream() 'to' src' en la línea 5 para que funcione, pero sigue existiendo la misma excepción. – theomega

+1

Esto no cambia nada. Puede analizar el documento durante la transformación del origen de la secuencia, antes de la transformación en DOMSource, pero se producirá una excepción de DTD en cualquier caso.Entonces esta "solución" no resuelve nada, y solo engaña. – mvmn

3

establecimiento de una característica en su DocumentBuilderFactory Probar:

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); 

En este momento estoy experimentando los mismos problemas en el interior de XSLT (2) cuando se llama a la función de analizar el documento XHTML páginas externas.

0

si utiliza

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); 

usted puede intentar desactivar la validación DTD con el código fllowing:

dbf.setValidating(false); 
+0

Vea la respuesta de Chris, es exactamente lo mismo. – theomega

2

Las respuestas anteriores me llevaron a una solución, pero es obvio que no era para mí, así aquí hay 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)); 
}