Frage

Ich bin neu in Scala, so kann ich außerhalb der Basis auf das sein, ich möchte wissen, ob das Problem ist mein Code. Angesichts der Scala-Datei httpparse, vereinfacht:

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

, die mit ausgeführt wird (URL spielt keine Rolle, das ist ein Witz Beispiel):

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

Das Ergebnis immer:

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

Ich habe die Stack-Überlauf-Thread auf diesem in Bezug auf Java sowie das System-Team Blog der W3C Eintrag über nicht diese DTD über das Web zuzugreifen versuchen. Ich habe isoliert auch den Fehler an den XML.load () -Methode, die eine Scala Bibliothek Methode ist, soweit ich das beurteilen kann.

Meine Frage: Wie kann ich dieses Problem beheben Ist das etwas, das ein Nebenprodukt meines Codes (cribbed von Raphael Ferreira Post ), ein Nebenprodukt von etwas Java spezifisch, dass ich wie in , die der vorherige Thread , oder etwas ist Scala spezifisch? Wo geschieht dieser Aufruf, und ist es ein Bug oder ein Feature? ( "Bin ich es? Es ist ihr, nicht wahr?" )

War es hilfreich?

Lösung 5

Es funktioniert. Nach einiger Detektivarbeit, ich die Details, so gut kann sie Figur:

Der Versuch, eine Entwicklungs RESTful-Schnittstelle zu analysieren, baue ich den Parser und erhalten Sie die oben (und nicht ein ähnliches) Fehler. Ich versuche, verschiedene Parameter, die die XML-Ausgabe zu ändern, aber den gleichen Fehler. Ich versuche, ein XML-Dokument verbinden ich Peitsche schnell (dummerweise von der Schnittstelle selbst abgeschaut) und den gleichen Fehler. Dann versuche ich, etwas zu verbinden, nur für Kicks, und Sie erhalten die gleiche (wieder, wahrscheinlich nur ähnlich) Fehler.

Ich begann zu fragen, ob es ein Fehler mit den Quellen oder das Programm, so begann ich die Suche um, und es sieht aus wie eine laufende themen- mit vielen Google und SO trifft zum gleichen Thema. Dies ist leider hat mich konzentrieren sich auf den vorgelagerten (Sprache) Aspekte des Fehlers, anstatt zu beheben mehrere Downstream an den Quellen selbst.

Schneller Vorlauf und der Parser arbeitet plötzlich auf der Original XML-Ausgabe. Ich bestätigte, dass es einige zusätzliche Arbeit Serverseite durchgeführt worden (nur einen verrückten Zufall?). Ich glaube nicht, entweder früher XML habe aber den Verdacht, dass es zu dem Dokument Kennungen geändert wird.

Nun arbeitet der Parser auf der RESTful-Schnittstelle sowie feinen jeden gut formatierte XML ich an ihn werfen können. Es schlägt fehl, auch auf allen XHTML DTD Ich habe versucht (z www.w3.org). Dies steht im Gegensatz zu dem, was @SeanReilly erwartet, scheint aber mit Jive, was die W3 Staaten .

Ich bin zu Scala noch neu, so kann nicht feststellen, ob ich einen besonderen oder typischen Fall haben. Auch kann ich sicher sein, dass dieses Problem nicht wieder auftritt für mich in einer anderen Form auf der ganzen Linie. Es scheint, dass XHTML ziehen wird diesen Fehler verursachen, wenn man nicht eine Lösung ähnlich der von @GClaramunt $ @ J-16 SDiZ verwendet hat vorgeschlagen, verwendet. Ich bin nicht wirklich qualifiziert zu wissen, ob dies ein Problem mit der Sprache ist, oder meine Implementierung einer Lösung (wahrscheinlich das später)

Für den unmittelbaren Zeitrahmen, vermute ich, dass die beste Lösung gewesen wäre für mich, um sicherzustellen, dass es möglich , dass die XML zu analysieren source-- nicht, dass andere sehen, hat den gleichen Fehler hatte und annimmt, dass es ein funktionelles Problem mit der Sprache war.

Hope, das hilft anderen.

Andere Tipps

Ich habe in das gleiche Problem gestoßen, und ich habe nicht eine elegante Lösung (ich denke in der Veröffentlichung die Frage an der Scala-Mailingliste) In der Zwischenzeit fand ich eine Abhilfe gefunden: implementieren Sie Ihre eigene SAXParserFactoryImpl so können Sie gesetzt den f.setFeature ( " http://apache.org/xml/features/disallow -doctype-Decl “, true); Eigentum. Die gute Sache ist es keine Codeänderung (Ich bin damit einverstanden, dass es repariert werden soll, wenn auch) an die Scala-Codebasis erfordert. Zuerst bin ich die Standard-Parser Fabrik erstreckt:

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

Nichts Besonderes, ich möchte nur die Möglichkeit, die Eigenschaft festzulegen.

(Beachten Sie, dass diese einfache Java-Code ist, wahrscheinlich können Sie das gleiche in Scala schreiben)

Und in der Scala-Code, müssen Sie die JVM konfigurieren Ihr neues Werk zu verwenden:

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

Dann können Sie XML.load ohne Validierung aufrufen

Ohne Adressierung, denn jetzt, das Problem, was Sie passieren erwarten, wenn die Funktionsanforderung falsch unten zurückkehren?

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

Was wird geschehen ist, dass eine Ausnahme ausgelöst wird. Man könnte es so umschreiben, aber:

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

Nun, um das XML-Parsing-Problem zu beheben, werden wir in den Parser DTD Laden deaktivieren, wie von anderen vorgeschlagen:

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

Nun habe ich, dass myXML Zeug in fetchAndParseURL nur die Struktur des Beispiels zu halten möglichst unverändert. Für die tatsächlichen Einsatz, würde ich es in einem Top-Level-Objekt zu trennen, und mache „Parser“ in ein def statt val, um Probleme mit wandelbaren Parsern zu vermeiden:

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

Importieren Sie das Paket definiert ist, und Sie sind gut zu gehen.

GClaramunt Lösung wirkte Wunder für mich. Meine Scala Umwandlung ist wie folgt:

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

Als sein der Original-Beitrag erwähnte, ist es erforderlich, die folgende Zeile in Ihrem Code zu platzieren irgendwo:

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

Dies ist ein scala Problem. Native Java hat eine Option, die DTD zu deaktivieren Laden:

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

Es gibt kein Äquivalent in scala.

Wenn Sie etwas wollen, es selbst zu beheben, überprüfen Sie scala/xml/parsing/FactoryAdapter.scala und die Zeile in

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

<- hier einfügen

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

Es gibt zwei Probleme mit dem, was Sie zu tun versuchen:

  • Scala XML-Parser versucht, physisch die DTD abrufen, wenn es nicht sollte. J-16 SDiZ scheint für dieses Problem ein paar Ratschläge zu haben.
  • Die Stack-Überlauf Seite, die Sie analysieren möchten, ist nicht XML. Es ist HTML4 streng.

Das zweite Problem ist nicht wirklich möglich, in Ihrem scala Code zu beheben. Selbst wenn Sie rund um das dtd Problem bekommen, werden Sie feststellen, dass die Quelle gerade nicht gültig ist XML (leere Tags sind nicht richtig geschlossen, zum Beispiel).

Sie müssen entweder die Seite mit etwas anderes als einen XML-Parser analysieren oder untersuchen Sie ein Dienstprogramm wie ordentlich mit dem HTML in XML zu konvertieren.

Meine Kenntnisse der Scala ist ziemlich schlecht, konnte aber nicht Sie verwenden ConstructingParser statt?

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

Für scala 2.7.7 konnte ich mit scala.xml.parsing.XhtmlParser dies tun

Einstellung Xerces schaltet funktioniert nur, wenn Sie Xerces verwenden. Ein Unternehmen Resolver arbeitet für jeden JAXP-Parser.

Es gibt mehr verallgemeinert Einheit Resolver gibt, aber diese Implementierung funktioniert der Trick, wenn alles, was ich versuche zu tun ist gültiges XHTML analysieren.

http://code.google.com/p/ java-xhtml-Cache-DTDs-EntityResolver /

Zeigt an, wie trivial es ist, die DTDs zwischenzuspeichern und den Netzwerkverkehr verzichten.

Auf jedem Fall, das ist , wie ich das Problem beheben . Ich vergesse immer. Ich bekomme immer den Fehler. Ich gehe immer diese Einheit Resolver holen. Dann bin ich wieder im Geschäft.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top