Domanda

Sono nuovo in Scala, quindi potrei essere fuori base su questo, voglio sapere se il problema è il mio codice.Dato il file Scala httpparse, semplificato in:

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"
   }
}

Che viene eseguito con (l'URL non ha importanza, questo è un esempio scherzoso):

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

Il risultato invariabilmente:

   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...

Ho visto il Discussione di stack overflow su questo rispetto a Java, così come il Voce del blog del team di sistema del W3C di non tentare di accedere a questo DTD tramite il web.Ho anche isolato l'errore nel metodo XML.load(), che per quanto ne so è un metodo della libreria Scala.

La mia domanda:Come posso risolvere questo problema? È qualcosa che è un sottoprodotto del mio codice (paralizzato da Il post di Raffaello Ferreira), un sottoprodotto di qualcosa di specifico di Java che devo affrontare come in il thread precedente, o qualcosa che sia specifico di Scala?Dove si verifica questa chiamata ed è un bug o una funzionalità?("Sono io?È lei, vero?")

È stato utile?

Soluzione 5

Funziona. Dopo qualche lavoro da detective, i dettagli come meglio posso li capire:

Cercando di analizzare un'interfaccia RESTful sviluppo, costruisco il parser e ottengo l'errore di cui sopra (anzi, una simile). Provo vari parametri per cambiare l'output XML, ma ottenere lo stesso errore. Provo a collegarlo a un documento XML ho subito improvvisare (cribbed stupidamente dall'interfaccia stessa) e ottenere lo stesso errore. Allora provo a collegarlo a qualsiasi cosa, solo per calci, e ottenere lo stesso errore (di nuovo, di solito solo simile).

Ho iniziato a chiedersi se si è verificato un errore con le fonti o il programma, così ho iniziato a cercare in giro, e sembra che un problema- in corso con molti Google e colpisce SO sullo stesso argomento. Questo, purtroppo, mi ha fatto concentro sulle (linguaggio) aspetti a monte dell'errore, piuttosto che analisi guasti di più a valle alle sorgenti stesse.

Avanti veloce e il parser funziona improvvisamente sul originale output XML. Ho confermato che c'era un po 'di lavoro in più è stato fatto lato server (solo una coincidenza pazzesca?). Non ho neanche XML in precedenza, ma il sospetto che è collegato con gli identificativi del documento venga modificato.

Ora, il parser funziona bene sull'interfaccia riposo, a qualsiasi XML ben formattato posso buttare a questo. Fallisce anche su tutti XHTML DTD ho provato (ad esempio www.w3.org). Questo è al contrario di quanto si aspetta @SeanReilly, ma sembra jive con ciò che il W3 stati .

Sono ancora nuovo a Scala, quindi non è possibile determinare se ho un caso speciale, o tipici. Né posso essere sicuro che questo problema non si ri-verificarsi per me in un'altra forma su tutta la linea. Sembra che tirando XHTML continuerà a causare questo errore a meno che non si utilizza una soluzione simile a quelle suggerite dal @GClaramunt $ @ J-16 SDiZ hanno utilizzato. Io non sono davvero qualificato per sapere se questo è un problema con la lingua, o la mia implementazione di una soluzione di (probabilmente il più tardi)

Per il periodo di tempo immediato, ho il sospetto che la soluzione migliore sarebbe stato per me per garantire che era possibile per analizzare che XML sorgente-- piuttosto che vedere che altri hanno avuto lo stesso errore ed assumere c'era un problema funzionale con la lingua.

Spero che questo aiuta gli altri.

Altri suggerimenti

Ho urtato la questione STESSO, e non ho trovato una soluzione elegante (sto pensando nella pubblicazione della domanda alla mailing list Scala) Nel frattempo, ho trovato una soluzione: implementare il proprio SAXParserFactoryImpl in modo da poter impostare il f.setFeature ( " http://apache.org/xml/features/disallow -doctype-decl ", true); proprietà. La cosa buona è che non richiede alcuna modifica del codice alla base di codice Scala (sono d'accordo che dovrebbe essere risolto, però). In primo luogo Sto estendendo la fabbrica di default parser:

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

Niente di speciale, voglio solo la possibilità di impostare la proprietà.

(Nota: che si tratta di codice Java pianura, molto probabilmente è possibile scrivere la stessa a Scala troppo)

E nel codice Scala, è necessario configurare la JVM di utilizzare il nuovo stabilimento:

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

Poi si può chiamare XML.load senza convalida

Senza affrontare, per il momento, il problema, cosa vi aspettate che accada se la richiesta di funzione return false sotto?

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

Cosa accadere è che un'eccezione verrà generata. Si potrebbe riscrivere in questo modo, però:

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

Ora, per risolvere il problema parsing XML, noi disattiviamo DTD carico nel parser, come suggerito da altri:

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"
}

Ora, ho messo quella roba myXML all'interno fetchAndParseURL solo per mantenere la struttura dell'esempio immodificato possibile. Per l'uso effettivo, mi separo in un oggetto di livello superiore, e fare "parser" in un def invece di val, per evitare problemi con i parser mutevoli:

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

Importa il pacchetto si è definito in, e siete a posto.

La soluzione di GClaramunt lavorato meraviglie per me. La mia conversione Scala è la seguente:

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

Come già detto la sua il post originale, è necessario inserire la seguente riga nel codice da qualche parte:

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

Questo è un problema scala. Native Java ha un'opzione per disabilitare il caricamento del DTD:

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

Non ci sono equivalenti a Scala.

Se si vuole un po 'di risolvere da soli, controllare scala/xml/parsing/FactoryAdapter.scala e mettere la linea in

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

<- inserire qui

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

Ci sono due problemi con ciò che stai cercando di fare:

  • Il parser xml di Scala sta tentando di recuperare fisicamente la DTD quando non dovrebbe.J-16 SDiZ sembra avere qualche consiglio per questo problema.
  • La pagina Stack Overflow che stai tentando di analizzare non è XML.È rigoroso Html4.

Il secondo problema non è realmente possibile risolverlo nel codice scala.Anche una volta risolto il problema del dtd, scoprirai che l'origine semplicemente non è un XML valido (i tag vuoti non vengono chiusi correttamente, ad esempio).

Devi analizzare la pagina con qualcosa oltre a un parser XML o investigare utilizzando un'utilità come tidy per convertire l'html in xml.

La mia conoscenza della Scala è piuttosto scarsa, ma non ha potuto si utilizza ConstructingParser invece?

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

Per Scala 2.7.7 sono riuscito a farlo con scala.xml.parsing.XhtmlParser

Impostazione Xerces interruttori funziona solo se si sta utilizzando Xerces. Un resolver entità funziona per qualsiasi parser JAXP.

Ci sono entità più generalizzata resolver là fuori, ma questa implementazione fa il trucco, quando tutto quello che sto cercando di fare è analizzare XHTML valido.

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

Mostra come banale è quello di memorizzare nella cache i DTD e rinunciare al traffico di rete.

In ogni caso, questo è come posso risolvere il problema . Mi dimentico sempre. Ho sempre trovato l'errore. Ho sempre andare a prendere questa entità resolver. Poi sono tornato in attività.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top