Question

Je suis nouveau à Scala, donc je peux être hors de la base à ce sujet, je veux savoir si le problème est mon code. Compte tenu du fichier Scala httpparse, simplifié à:

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

Ce qui est exécuté avec (URL n'a pas d'importance, c'est un exemple de blague):

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

Le résultat invariablement:

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

Je l'ai vu Stack Overflow fil ce par rapport à Java, ainsi que le System Team Blog du W3C entrée de ne pas essayer d'accéder à cette DTD via le web. J'ai aussi isolé l'erreur à la méthode XML.load (), qui est une méthode de bibliothèque Scala pour autant que je peux dire.

Ma question: Comment puis-je résoudre ce problème Est-ce quelque chose qui est un sous-produit de mon code (cribbed après Raphaël Ferreira de ), un sous-produit de quelque chose Java spécifique que je dois aborder comme dans le fil précédent , ou quelque chose qui est Scala spécifique? Où est cet appel se passe, et est-ce un bug ou une fonctionnalité? ( "Est-ce moi? Il lui est, non?" )

Était-ce utile?

La solution 5

Il fonctionne. Après un travail de détective, les détails mieux que je peux les comprendre:

Essayer d'analyser une interface RESTful de développement, je construis l'analyseur et obtenir le plus haut (plutôt un similaire) erreur. J'essaie divers paramètres pour modifier la sortie XML, mais obtenir la même erreur. J'essaie de se connecter à un document XML je fouette rapidement (bêtement chipé de l'interface elle-même) et obtenir la même erreur. Ensuite, j'essaie de se connecter à quoi que ce soit, juste pour le plaisir, et obtenir la même erreur (encore une fois, probablement seulement similaire).

J'ai commencé à demander si c'était une erreur avec les sources ou le programme, donc je commencé à chercher autour, et il ressemble à un issue- en cours avec beaucoup Google et frappe SO sur le même sujet. Cela, malheureusement, m'a fait mettre l'accent sur les aspects en amont (langue) de l'erreur, plutôt que dépanne plus en aval aux sources elles-mêmes.

Avance rapide et l'analyseur fonctionne soudainement sur la d'origine sortie XML. Je confirme qu'il y avait un travail supplémentaire a été fait côté serveur (juste une coïncidence folle?). Je n'ai pas soit XML plus tôt, mais pense qu'il est lié aux identifiants de document en cours de modification.

Maintenant, l'analyseur fonctionne très bien sur l'interface RESTful, ainsi tout XML bien formaté, je peux jeter. Elle ne tient pas sur tous les documents XHTML DTD J'ai essayé (par exemple www.w3.org). Ceci est contraire à ce que @SeanReilly attend, mais semble jive avec ce que le États W3 .

Je suis encore nouveau à Scala, ne peut donc pas déterminer si j'ai un cas particulier ou typique. Je ne peux pas être assuré que ce problème ne se reproduira pas pour moi sous une autre forme la ligne. Il ne semble que la traction XHTML continuera à provoquer cette erreur, sauf si l'on utilise une solution similaire à celles proposées par @GClaramunt $ @ J-16 SDiZ ont utilisé. Je ne suis pas vraiment qualifié pour savoir si cela est un problème avec la langue, ou ma mise en œuvre d'une solution (probablement le plus tard)

Pour la période immédiate, je pense que la meilleure solution aurait été pour moi pour vous assurer qu'il était possible pour analyser que XML source-- plutôt que de voir que d'autres ont eu de la même erreur et supposons qu'il y avait un problème fonctionnel avec la langue.

Espérons que cela aide les autres.

Autres conseils

Je suis tombé dans le même numéro, et je ne l'ai pas trouvé une solution élégante (je pense en affichant la question à la liste de diffusion Scala) Pendant ce temps, j'ai trouvé une solution: mettre en œuvre votre propre SAXParserFactoryImpl afin que vous puissiez définir le f.setFeature ( " http://apache.org/xml/features/disallow -doctype-décl », true); propriété. La bonne chose est qu'il ne nécessite pas de changement de code à la base de code Scala (je suis d'accord qu'il devrait être fixé, cependant). D'abord, je suis extension de l'usine de l'analyseur par défaut:

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

Rien de spécial, je veux juste la chance de définir la propriété.

(Note: que ce code Java simple, très probablement, vous pouvez écrire la même chose dans Scala aussi)

Et dans votre code Scala, vous devez configurer la machine virtuelle Java pour utiliser votre nouvelle usine:

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

Ensuite, vous pouvez appeler XML.load sans validation

Sans aborder, pour l'instant, le problème, qu'est-ce que vous attendez de se produire si la demande de retour de la fonction faux ci-dessous?

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

Qu'est-ce que arriver est qu'une exception sera levée. Vous pouvez réécrire cette façon, si:

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

Maintenant, pour résoudre le problème de parsing XML, nous allons désactiver le chargement DTD dans l'analyseur, comme suggéré par d'autres:

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

Maintenant, je mets ce genre de choses à l'intérieur myXML fetchAndParseURL juste pour garder la structure de l'exemple sous forme inchangée que possible. Pour une utilisation effective, je fait séparer dans un objet de haut niveau, et faire « analyseur » dans une définition au lieu de val, pour éviter les problèmes avec parseurs 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()
  }
}

Importer le package qu'il est défini dans, et vous êtes bon pour aller.

La solution de GClaramunt a fait des merveilles pour moi. Ma conversion Scala se présente comme suit:

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

Comme mentionné son poste d'origine, il est nécessaire de placer la ligne suivante dans votre code quelque part:

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

Ceci est un problème de scala. Java natif a une option pour désactiver le chargement de la DTD:

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

Il n'y a pas d'équivalent dans scala.

Si vous voulez un peu de fixer vous-même, vérifiez scala/xml/parsing/FactoryAdapter.scala et mettre la ligne

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

<- insérer ici

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

Il y a deux problèmes avec ce que vous essayez de faire:

  • XML Parser Scala tente de récupérer physiquement la DTD quand il ne devrait pas. J-16 SDiZ semble avoir quelques conseils pour ce problème.
  • La page de débordement de pile que vous essayez d'analyser n'est pas XML. Il est HTML4 stricte.

Le deuxième problème est pas vraiment possible de fixer dans votre code scala. Même une fois que vous contourner le problème dtd, vous trouverez que la source XML n'est pas valide (balises vides ne sont pas fermées correctement, par exemple).

Vous devez soit analyser la page avec quelque chose en plus d'un analyseur XML, ou d'enquêter sur l'aide d'un utilitaire comme bien rangé pour convertir le HTML en XML.

Ma connaissance de Scala est assez pauvre, mais ne pouvait pas vous utiliser ConstructingParser à la place?

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

Pour scala 2.7.7 j'ai réussi à le faire avec scala.xml.parsing.XhtmlParser

Réglage Xerces commutateurs ne fonctionne que si vous utilisez Xerces. Un résolveur entité fonctionne pour tout analyseur de JAXP.

Il y a une entité plus générale résolveurs là-bas, mais cette mise en œuvre fait l'affaire quand tout ce que je suis en train de faire est d'analyser XHTML valide.

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

Indique comment il est trivial de mettre en cache les DTD et renoncer à le trafic réseau.

Dans tous les cas, cela est comment je résoudre ce problème . J'oublie toujours. Je reçois toujours l'erreur. Je vais toujours chercher ce résolveur entité. Ensuite, je suis de retour dans les affaires.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top