Pregunta

Soy nuevo en Scala, así que puede ser fuera de la base en esto, yo quiero saber si el problema es mi código. Dada la httpparse archivo Scala, simplificada a:

object Http {
   import java.io.InputStream;
   import java.net.URL;

   def request(urlString:String): (Boolean, InputStream) =
      try {
         val url = new URL(urlString)
         val body = url.openStream
         (true, body)
      }
      catch {
         case ex:Exception => (false, null)
      }
}

object HTTPParse extends Application {
   import scala.xml._;
   import java.net._;

   def fetchAndParseURL(URL:String) = {
      val (true, body) = Http request(URL)
      val xml = XML.load(body) // <-- Error happens here in .load() method
      "True"
   }
}

que se ejecuta con (URL no importa, este es un ejemplo broma):

scala> HTTPParse.fetchAndParseURL("http://stackoverflow.com")

El resultado invariablemente:

   java.io.IOException: Server returned HTTP response code: 503 for URL: http://www.w3.org/TR/html4/strict.dtd
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1187)
    at com.sun.org.apache.xerces.internal.impl.XMLEntityManager.setupCurrentEntity(XMLEntityManager.java:973)
    at com.sun.org.apache.xerces.internal.impl.XMLEntityManager.startEntity(XMLEnti...

He visto el hilo en esto con respecto a Java, así como la Equipo Sistema de W3C Blog entrada de no intentar acceder a esta DTD través de la web. He aislado también el error con el método XML.load (), que es un método de biblioteca Scala por lo que yo puedo decir.

Mi Pregunta: ¿Cómo puedo solucionar este problema ¿Es esto algo que es un subproducto de mi código (cribbed de de Rafael Ferreira posterior ), un subproducto de algo de Java específico que necesito para hacer frente como en el hilo anterior , o algo que es específico Scala? ¿Dónde está ocurriendo esta llamada, y se trata de un error o una característica? ( "¿Soy yo? Es ella, ¿verdad?" )

¿Fue útil?

Solución 5

Funciona. Después de un trabajo de detective, los detalles de lo mejor que pueda entenderlos:

Tratando de analizar una interfaz REST desarrollo, construyo el analizador y obtener el error anterior (más bien, una similar). Trato varios parámetros para cambiar la salida XML, pero conseguir el mismo error. Trato de conectar a un documento XML azoto rápidamente (cribbed estúpidamente desde la propia interfaz) y obtener el mismo error. Entonces intento conectar a cualquier cosa, sólo por diversión, y obtener el mismo error (de nuevo, es probable que sólo similar).

empecé a cuestionar si se ha producido un error con las fuentes o el programa, así que empecé a buscar alrededor, y se ve como un problema- en curso con muchas Google y lo que las visitas sobre el mismo tema. Esto, por desgracia, me hizo centro en los aspectos (lenguaje) aguas arriba del error, en lugar de localizar averías más aguas abajo en las mismas fuentes.

Un avance rápido y el analizador funciona de repente en el ORIGINAL salida XML. Me confirmó que había algo de trabajo adicional que se ha hecho del lado del servidor (sólo una coincidencia loco?). No tengo ya sea XML anterior, pero se sospecha que está relacionado con los identificadores de documento que se cambie.

Ahora, el analizador funciona bien en la interfaz REST, así como cualquier XML bien formateado puedo lanzar en él. También falla en todos los DTD de XHTML He tratado (por ejemplo www.w3.org). Esto es contrario a lo que @SeanReilly espera, pero parece jive con lo que el estados W3 .

Todavía soy nuevo en Scala, por lo que no puedo determinar si tengo un caso especial, o típica. Tampoco puedo estar seguro de que este problema no va a volver a ocurrir por mí en otra forma en la línea. Parece que la tracción XHTML seguirá causando este error si no se utiliza una solución similar a los sugeridos por @GClaramunt $ @ J-16 SDiZ han utilizado. Realmente no estoy capacitado para saber si esto es un problema con el idioma, o mi implementación de una solución (probablemente la más adelante)

En el plazo inmediato, sospecho que la mejor solución habría sido para mí para asegurarse de que era posible para analizar XML que source-- en lugar de ver que otros de haber tenido el mismo error y se supone que había un problema funcional con el idioma.

Espero que esto ayuda a los demás.

Otros consejos

He encontré con el problema MISMO, y no he encontrado una solución elegante (estoy pensando en publicar la pregunta a la lista de correo de Scala) Mientras tanto, he encontrado una solución: poner en práctica su propia SAXParserFactoryImpl para que pueda establecer el f.setFeature ( " http://apache.org/xml/features/disallow -doctype-decl ", true); propiedad. Lo bueno es que no requiere ningún cambio en el código de la base de código Scala (Estoy de acuerdo que debe fijarse, sin embargo). En primer lugar les extiendo la fábrica analizador por defecto:

package mypackage;

public class MyXMLParserFactory extends SAXParserFactoryImpl {
      public MyXMLParserFactory() throws SAXNotRecognizedException, SAXNotSupportedException, ParserConfigurationException {
        super();
        super.setFeature("http://xml.org/sax/features/validation", false);
        super.setFeature("http://apache.org/xml/features/disallow-doctype-decl", false); 
        super.setFeature("http://apache.org/xml/features/nonvalidating/load-dtd-grammar", false); 
        super.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); 
      } 
    }

No hay nada especial, sólo quiero la oportunidad de establecer la propiedad.

(Nota: que este es el código de Java normal, más probable es que puede escribir lo mismo en Scala también)

Y en el código Scala, es necesario configurar la JVM a utilizar su nueva fábrica:

System.setProperty("javax.xml.parsers.SAXParserFactory", "mypackage.MyXMLParserFactory");

A continuación, puede llamar XML.load sin validación

Si no se abordan, por ahora, el problema, ¿qué esperas que suceda si la solicitud de la función return false abajo?

def fetchAndParseURL(URL:String) = {      
  val (true, body) = Http request(URL)

a pasar es que una excepción será lanzada. Se podría volver a escribir de esta manera, sin embargo:

def fetchAndParseURL(URL:String) = (Http request(URL)) match {      
  case (true, body) =>      
    val xml = XML.load(body)
    "True"
  case _ => "False"
}

Ahora, para solucionar el problema de análisis XML, inhabilitaremos DTD de carga en el analizador, según lo sugerido por otros:

def fetchAndParseURL(URL:String) = (Http request(URL)) match {      
  case (true, body) =>
    val f = javax.xml.parsers.SAXParserFactory.newInstance()
    f.setNamespaceAware(false)
    f.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
    val MyXML = XML.withSAXParser(f.newSAXParser())
    val xml = MyXML.load(body)
    "True"
  case _ => "False"
}

Ahora, no lo tengo en myXML cosas dentro fetchAndParseURL sólo para mantener la estructura del ejemplo en forma invariable como sea posible. Por el uso real, me separo en un objeto de nivel superior, y hacer "analizador" en una definición en lugar de val, para evitar problemas con analizadores mutables:

import scala.xml.Elem
import scala.xml.factory.XMLLoader
import javax.xml.parsers.SAXParser
object MyXML extends XMLLoader[Elem] {
  override def parser: SAXParser = {
    val f = javax.xml.parsers.SAXParserFactory.newInstance()
    f.setNamespaceAware(false)
    f.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
    f.newSAXParser()
  }
}

Importar el paquete se define en, y que son buenos para ir.

La solución de GClaramunt hizo maravillas para mí. Mi conversión Scala es el siguiente:

package mypackage
import org.xml.sax.{SAXNotRecognizedException, SAXNotSupportedException}
import com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl
import javax.xml.parsers.ParserConfigurationException

@throws(classOf[SAXNotRecognizedException])
@throws(classOf[SAXNotSupportedException])
@throws(classOf[ParserConfigurationException])
class MyXMLParserFactory extends SAXParserFactoryImpl() {
    super.setFeature("http://xml.org/sax/features/validation", false)
    super.setFeature("http://apache.org/xml/features/disallow-doctype-decl", false)
    super.setFeature("http://apache.org/xml/features/nonvalidating/load-dtd-grammar", false)
    super.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false)
}

Como se mencionó su post original, es necesario colocar la siguiente línea en su código en algún lugar:

System.setProperty("javax.xml.parsers.SAXParserFactory", "mypackage.MyXMLParserFactory")

Este es un problema Scala. Nativo de Java tiene una opción para desactivar la carga de la DTD:

f.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);

No hay equivalente en Scala.

Si quieres un poco de repararlo usted mismo, compruebe scala/xml/parsing/FactoryAdapter.scala y poner la línea en

278   def loadXML(source: InputSource): Node = {
279     // create parser
280     val parser: SAXParser = try {
281       val f = SAXParserFactory.newInstance()
282       f.setNamespaceAware(false)

<- inserte aquí

283       f.newSAXParser()
284     } catch {
285       case e: Exception =>
286         Console.err.println("error: Unable to instantiate parser")
287         throw e
288     }

Hay dos problemas con lo que estamos tratando de hacer:

  • analizador XML de Scala está tratando de recuperar físicamente el DTD cuando no debe. J-16 SDiZ parece tener algún consejo para este problema.
  • La página de desbordamiento de pila que está tratando de analizar no es XML. Es html4 estricta.

El segundo problema no es realmente posible fijar en su código Scala. Incluso una vez que el problema DTD, encontrará que la fuente no es XML válido (etiquetas vacías no se cierran correctamente, por ejemplo).

Hay que sea analizar la página con algo más que un analizador XML, o investigar el uso de una utilidad como ordenada para convertir el HTML a XML.

Mi conocimiento de Scala es bastante pobre, pero no podía usar ConstructingParser lugar?

  val xml = new java.io.File("xmlWithDtd.xml")
  val parser = scala.xml.parsing.ConstructingParser.fromFile(xml, true)
  val doc = parser.document()
  println(doc.docElem)

Para Scala 2.7.7 logré hacer esto con scala.xml.parsing.XhtmlParser

Configuración de Xerces interruptores sólo funciona si está usando Xerces. Una resolución de entidad funciona para cualquier analizador JAXP.

Hay entidad más generalizada resolutores por ahí, pero esta aplicación hace el truco, cuando todo lo que estoy tratando de hacer es analizar XHTML válido.

http://code.google.com/p/ java en XHTML-cache-DTD-EntityResolver /

Muestra lo trivial que es para almacenar en caché los DTD y renunciar al tráfico de la red.

En cualquier caso, esto es ¿Cómo lo arreglo . Siempre lo olvido. Siempre sale el error. Siempre va búsqueda de resolución de esta entidad. Entonces estoy de vuelta en los negocios.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top