Pergunta

Eu sou novo para Scala, para que eu possa estar fora da base nisso, eu quero saber se o problema é meu código. Dado o arquivo Scala httpparse, simplificada para:

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

Qual é executado com (URL não importa, este é um exemplo piada):

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

O resultado invariavelmente:

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

Eu vi a Stack Overflow fio neste em relação ao Java, bem como a Team System do W3C Blog entrada sobre não tentando acessar este DTD através da web. Eu também isolado o erro para o método XML.load (), que é um método de biblioteca Scala, tanto quanto eu posso dizer.

Minha pergunta: Como posso corrigir esse Isto é algo que é um subproduto do meu código (plagiou pós de Rafael Ferreira), um produto de algo específico Java que eu preciso para o endereço como em segmento anterior, ou algo que é Scala específico? Onde está esta chamada acontecendo, e é um bug ou um recurso? ( "É mim? É ela, certo?" )

Foi útil?

Solução 5

Ele funciona. Depois de algum trabalho de detetive, os detalhes como melhor eu posso entendê-los:

Tentando analisar uma interface RESTful do desenvolvimento, eu construo o analisador e obter a acima erro (sim, um similar). Tento vários parâmetros para alterar a saída XML, mas recebo o mesmo erro. I tentar se conectar a um documento XML Eu rapidamente chicotear acima (cribbed estupidamente a partir da interface em si) e obter o mesmo erro. Então eu tento ligar para qualquer coisa, apenas por diversão, e obter o mesmo erro (novamente, provavelmente, só similar).

Eu comecei a questionar se era um erro com as fontes ou o programa, então comecei a procurar em torno, e parece que um issue- permanente com muitos hits do Google e assim por diante o mesmo tema. Isto, infelizmente, fez-me concentrar nos aspectos a montante (idioma) do erro, em vez de solucionar problemas mais a jusante para as próprias fontes.

Fast forward eo analisador de repente trabalha no ORIGINAL de saída XML. I confirmou que havia algum trabalho adicional foi feito do lado do servidor (apenas uma coincidência louco?). Eu não tenho XML, quer antes, mas suspeito que ela está relacionada com os identificadores de documento que está sendo alterado.

Agora, o analisador funciona bem na interface RESTful, assim qualquer bem formatado XML eu posso jogar nele. Ele também falha em todos XHTML DTD é que eu tentei (por exemplo www.w3.org). Isto é contrário ao que @SeanReilly espera, mas parece jive com o que a W3 afirma .

Eu ainda sou novo para Scala, por isso não pode determinar se eu tenho um especial, ou caso típico. Também não posso ter certeza de que este problema não vai voltar a acontecer para mim de outra forma para baixo da linha. Parece que puxar XHTML continuará a causar este erro, a menos que um utiliza uma solução semelhante à sugerida por @GClaramunt $ @ J-16 SDiZ ter usado. Eu realmente não estou qualificado para saber se este é um problema com a linguagem, ou a minha implementação de uma solução (provavelmente o mais tarde)

Para o período imediato, eu suspeito que a melhor solução teria sido para mim para garantir que ele era possível para analisar esse XML source-- em vez de ver que outros de ter tido o mesmo erro e assumir que havia um problema funcional com o idioma.

Espero que isso ajude os outros.

Outras dicas

Eu esbarrou na questão SAME, e eu não encontrei uma solução elegante (estou pensando em postar a pergunta na lista de discussão Scala) Enquanto isso, eu encontrei uma solução: implementar seu próprio SAXParserFactoryImpl para que você possa definir o f.setFeature ( " http://apache.org/xml/features/disallow -doctype-decl ", true); propriedade. A coisa boa é que ele não requer qualquer alteração de código para a base de código Scala (Concordo que deve ser corrigido, embora). Primeiro eu estou estendendo a fábrica analisador padrão:

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

Nada de especial, eu só quero a chance de definir a propriedade.

(Nota: que este é o código Java simples, muito provavelmente você pode escrever o mesmo em Scala também)

E em seu código Scala, você precisa configurar a JVM para usar sua nova fábrica:

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

Em seguida, você pode chamar XML.load sem validação

Sem abordar, por enquanto, o problema, o que você espera que aconteça se o pedido de retorno de função falsa abaixo?

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

O irá acontecer é que uma exceção será lançada. Você poderia reescrevê-lo desta forma, no entanto:

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

Agora, para corrigir o problema de análise XML, vamos desativar DTD carregamento no analisador, como sugerido por outros:

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

Agora, eu coloquei esse material MyXML dentro fetchAndParseURL apenas para manter a estrutura do exemplo sob a forma inalterada possível. Pelo uso real, eu separá-lo em um objeto de nível superior, e fazer "parser" em um def vez de val, a problemas evitar com analisadores mutáveis:

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 o pacote é definido, e você é bom para ir.

A solução da GClaramunt trabalhou maravilhas para mim. Minha conversão Scala é o seguinte:

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 mencionado seu post original, é necessário colocar a seguinte linha em seu lugar código:

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

Este é um problema scala. Native Java tem uma opção para desabilitar o carregamento da DTD:

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

Não existe são equivalentes em scala.

Se você um pouco querer corrigi-lo sozinho, verificação scala/xml/parsing/FactoryAdapter.scala e colocar a linha em

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

<- inserção aqui

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

Há dois problemas com o que você está tentando fazer:

  • parser XML do Scala está tentando recuperar fisicamente o DTD quando não deveria. J-16 SDiZ parece ter algum conselho para este problema.
  • A página de estouro de pilha que você está tentando analisar não é XML. É de HTML4 rigorosa.

O segundo problema não é realmente possível fixar no seu código Scala. Mesmo depois de contornar o problema DTD, você verá que a fonte não é apenas XML válido (tags vazias não estão fechadas corretamente, por exemplo).

Você tem que quer analisar a página com algo além de um analisador XML, ou investigar usando um utilitário como arrumado para converter o HTML para XML.

Meu conhecimento da Scala é muito pobre, mas você não pode usar ConstructingParser vez?

  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 eu consegui fazer isso com scala.xml.parsing.XhtmlParser

Configuração Xerces muda só funciona se você estiver usando Xerces. Um resolvedor entidade funciona para qualquer parser JAXP.

Há mais generalizada resolvedores entidade lá fora, mas esta implementação faz o truque quando tudo que eu estou tentando fazer é parse XHTML válido.

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

mostra como trivial é para armazenar em cache os DTDs e renunciar o tráfego de rede.

Em qualquer caso, este é como eu corrigi-lo . Eu sempre esqueço. Eu sempre obter o erro. Eu sempre ir buscar esse resolvedor entidade. Então eu estou de volta no negócio.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top