문제

나는 Scala를 처음 사용하기 때문에 이것에 기반을두고있을 수 있습니다. 문제가 내 코드인지 알고 싶습니다. Scala 파일 httpparse가 주어지면 : 단순화됩니다.

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

(URL은 중요하지 않습니다. 이것은 농담 예입니다) : :

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

결과는 항상 :

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

나는 그것을 보았다 오버플로 스레드 스택 Java뿐만 아니라 W3C의 시스템 팀 블로그 항목 웹을 통해이 DTD에 액세스하지 않으려는 것에 대해. 또한 오류를 xml.load () 메소드로 격리했습니다.이 메소드는 말할 수있는 한 스칼라 라이브러리 메소드입니다.

내 질문 : 어떻게 해결할 수 있습니까? 이것은 내 코드의 제품에 의한 것입니다 ( 라파엘 페레이라의 게시물), a 내가 이전 스레드, 또는 스칼라 특이한 것? 이 호출은 어디에서 일어나고 있으며 버그 또는 기능입니까? ("나야? 그녀 야 맞죠?")

도움이 되었습니까?

해결책 5

효과가있다. 일부 탐정 작업 후에는 최선을 다하면 다음을 알아낼 수 있습니다.

발달 레스트 프론트 인터페이스를 구문 분석하려고 시도하면서 구문 분석기를 만들고 위의 (오히려 유사한) 오류를 얻습니다. XML 출력을 변경하기 위해 다양한 매개 변수를 시도하지만 동일한 오류가 발생합니다. 나는 빠르게 채찍질하고 (인터페이스 자체에서 어리석게 멍청한) XML 문서에 연결하고 동일한 오류를 얻으려고합니다. 그런 다음 킥을 위해 무엇이든 연결하려고 노력하고 동일하게 (다시 비슷한) 오류를 얻습니다.

소스 또는 프로그램의 오류인지에 대해 의문을 가지기 시작했기 때문에 검색을 시작했으며 많은 Google에서 진행중인 문제처럼 보이며 같은 주제에 대해 히트했습니다. 불행히도 이것은 소스 자체에서 더 많은 다운 스트림 문제를 해결하기보다는 오류의 상류 (언어) 측면에 집중했습니다.

빨리 앞으로 나아가고 파서는 갑자기 작동합니다 원래의 XML 출력. 나는 서버 측면이 완료되었음을 확인했다 (단지 미친 우연의 일치?). 이전 XML은 없지만 문서 식별자가 변경되는 것과 관련이 있다고 생각합니다.

이제 파서는 RESTful 인터페이스에서 잘 작동하며, 잘 형식화 된 XML이 던질 수 있습니다. 또한 모든 XHTML DTD의 I ITH 시도 (예 : www.w3.org)에서도 실패합니다. 이것은 @SeanReilly가 기대하는 것과 상반되지만 W3가 말한 것.

나는 여전히 스칼라를 처음 접 했으므로 특별하거나 전형적인 사례가 있는지 확인할 수 없습니다. 또한이 문제가 다른 형태로 줄을 다시 발생시키지 않을 것이라고 확신 할 수 없습니다. @gclaramunt $ @J-16 Sdiz가 사용한 것과 유사한 솔루션을 사용하지 않는 한 XHTML을 당기면이 오류가 계속 발생하는 것으로 보입니다. 나는 이것이 언어에 문제인지 또는 솔루션 구현 (나중에)의 문제인지 알 수있는 자격이 없습니다.

즉각적인 기간 동안, 나는 최상의 솔루션이 내가 가능한 XML 소스를 구문 분석하기 위해 다른 사람이 동일한 오류가 있었으며 언어에 기능적 문제가 있다고 가정합니다.

이것이 다른 사람들을 돕기를 바랍니다.

다른 팁

나는 같은 문제를 겪었고 우아한 솔루션을 찾지 못했습니다 (스칼라 메일 링리스트에 질문을 게시 할 생각을 생각하고 있습니다) 한편, 해결 방법을 찾았습니다. F를 설정할 수 있도록 자신의 saxparserfactoryimpl을 구현합니다. .SetFeature ( "http://apache.org/xml/features/disallow-doctype-decl", true); 속성. 좋은 점은 스칼라 코드 기반으로 코드를 변경할 필요가 없다는 것입니다 (그래도 고정되어야한다는 데 동의합니다). 먼저 기본 파서 공장을 확장하고 있습니다.

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

특별한 것은 없습니다. 나는 단지 부동산을 설정할 기회를 원합니다.

(참고 : 이것은 일반 Java 코드이며 아마도 스칼라에서도 똑같이 쓸 수 있습니다).

또한 스칼라 코드에서는 새 공장을 사용하려면 JVM을 구성해야합니다.

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

그런 다음 유효성 검사없이 xml.load로 전화 할 수 있습니다

문제를 해결하지 않고 함수 요청이 아래에서 false를 반환하면 어떻게 될 것으로 예상됩니까?

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

~ 할 것이다 예외는 예외가 발생하는 것입니다. 하지만 이런 식으로 다시 작성할 수 있습니다.

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

이제 XML 구문 분석 문제를 해결하기 위해 다른 사람들이 제안한대로 파서에서 DTD로드를 비활성화 할 것입니다.

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

이제 나는 그 예제의 구조를 가능한 한 변경되지 않은 것으로 유지하기 위해 Fetchandparseurl 내부에 MyxML 물건을 넣었습니다. 실제 사용을 위해, 나는 그것을 최상위 객체로 분리하고, 돌연변이 가능한 파서의 문제를 피하기 위해 "파서"를 VAL 대신 DEF로 만듭니다.

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

정의 된 패키지를 가져 오면 가면 좋습니다.

Gclaramunt의 솔루션은 저에게 놀라운 일을했습니다. 내 스칼라 변환은 다음과 같습니다.

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

그의 원래 게시물에 언급했듯이, 다음 줄은 코드에 어딘가에 배치해야합니다.

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

이것은 스칼라 문제입니다. 기본 Java는 DTD로드를 비활성화 할 수있는 옵션이 있습니다.

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

스칼라에는 동등한 것이 없습니다.

당신이 그것을 직접 고치고 싶다면, 확인하십시오. scala/xml/parsing/FactoryAdapter.scala 그리고 라인을 넣으십시오

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

<- 여기에 삽입하십시오

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

당신이하려는 일에는 두 가지 문제가 있습니다.

  • Scala의 XML Parser는 DTD를 물리적으로 검색하지 않아야합니다. J-16 SDIZ는이 문제에 대한 조언이있는 것 같습니다.
  • 구문 분석하려는 스택 오버플로 페이지는 XML이 아닙니다. HTML4 엄격합니다.

두 번째 문제는 스칼라 코드에서 실제로 수정할 수 없습니다. DTD 문제를 해결하면 소스가 유효하지 않다는 것을 알 수 있습니다 (예 : 빈 태그가 제대로 닫히지 않음).

XML 파서 이외의 무언가로 페이지를 구문 분석하거나 HTML을 XML로 변환하기 위해 Tidy와 같은 유틸리티를 사용하여 조사해야합니다.

Scala에 대한 나의 지식은 꽤 가난하지만 사용할 수 없었습니다. CROUTTTINGPARSER 대신에?

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

Scala 2.7.7의 경우 Scala.xml.parsing.xhtmlparser 로이 작업을 수행했습니다.

Xerces 스위치 설정은 Xerces를 사용하는 경우에만 작동합니다. Entity Resolver는 JAXP 파서를 위해 작동합니다.

더 일반화 된 엔티티 리전버가 있지만,이 구현은 내가하려는 모든 것이 유효한 XHTML을 구문 분석하는 것만 큼 트릭을 수행합니다.

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

DTD를 캐시하고 네트워크 트래픽을 포기하는 것이 얼마나 사소한지를 보여줍니다.

어쨌든 이것은입니다 내가 그것을 고치는 방법. 나는 항상 잊어 버린다. 나는 항상 오류를 얻습니다. 나는 항상이 엔티티 리졸버를 가져옵니다. 그런 다음 사업으로 돌아 왔습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top