15

私は 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 に関するStack Overflow スレッドと、Web 経由でこの DTD にアクセスしようとしないことに関するW3C のシステム チーム ブログ エントリを見てきました。また、私が知る限り、Scala ライブラリ メソッドである XML.load() メソッドにエラーを分離しました。

私の質問: どうすればこれを修正できますか? これは、私のコードの副産物 ( Raphael Ferreira の投稿から引用)、前のスレッドのように対処する必要がある Java 固有の副産物、または Scala 固有の副産物ですか? この呼び出しはどこで行われていますか? また、バグまたは機能ですか? (「私ですか?彼女ですよね?」

4

9 に答える 9

11

私は同じ問題にぶつかりましたが、洗練された解決策は見つかりませんでした (質問を Scala メーリング リストに投稿することを考えています) 一方、回避策を見つけました: 独自の SAXParserFactoryImpl を実装して、f .setFeature(" http://apache.org/xml/features/disallow-doctype-decl ", true); 財産。良いことは、Scala コード ベースのコードを変更する必要がないことです (ただし、修正する必要があることには同意します)。まず、デフォルトのパーサー ファクトリを拡張します。

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 コードであり、おそらく Scala でも同じように記述できます)

また、Scala コードでは、新しいファクトリを使用するように JVM を構成する必要があります。

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

次に、検証なしで XML.load を呼び出すことができます

于 2009-07-08T15:39:07.973 に答える
3

GClaramunt のソリューションは、私にとって驚くほど効果的でした。私のScala変換は次のとおりです。

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")
于 2011-05-01T02:00:48.403 に答える
2

これはスカラの問題です。ネイティブ Java には、DTD のロードを無効にするオプションがあります。

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

scala には同等のものはありません。

自分で修正したい場合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     }
于 2009-07-08T05:59:01.347 に答える
1

あなたがやろうとしていることには2つの問題があります:

  • Scala の xml パーサーは、DTD を取得すべきではないときに、物理的に取得しようとしています。J-16 SDiZ は、この問題についていくつかのアドバイスを持っているようです。
  • 解析しようとしているスタック オーバーフロー ページは XML ではありません。Html4 厳密です。

2 番目の問題は、実際には scala コードで修正することはできません。dtd の問題を回避したとしても、ソースが有効な XML ではないことがわかります (たとえば、空のタグが適切に閉じられていません)。

XML パーサー以外でページを解析するか、tidy などのユーティリティを使用して調査し、html を xml に変換する必要があります。

于 2009-07-08T05:58:14.173 に答える
0

scala 2.7.7 の場合、私は scala.xml.parsing.XhtmlParser でこれを行うことができました

于 2009-12-15T12:35:33.607 に答える
0

Xerces スイッチの設定は、Xerces を使用している場合にのみ機能します。エンティティーリゾルバーは、あらゆる JAXP パーサーで機能します。

もっと一般化されたエンティティ リゾルバがありますが、この実装は、有効な XHTML を解析するだけの場合にうまく機能します。

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

DTD をキャッシュしてネットワーク トラフィックを無視することがいかに簡単かを示します。

いずれにせよ、これは私がそれを修正する方法です。私はいつも忘れます。私はいつもエラーが発生します。私はいつもこのエンティティ リゾルバーをフェッチします。その後、私はビジネスに戻ります。

于 2010-01-02T22:57:39.833 に答える
0

私の Scala の知識はかなり貧弱ですが、代わりにConstructingParserを使用できませんか?

  val xml = new java.io.File("xmlWithDtd.xml")
  val parser = scala.xml.parsing.ConstructingParser.fromFile(xml, true)
  val doc = parser.document()
  println(doc.docElem)
于 2009-07-08T12:39:06.267 に答える