Scala/Java は w3 の「過剰な dtd トラフィック」仕様を尊重していませんか?
質問
私は 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 のシステム チームのブログ エントリ Web 経由でこの DTD にアクセスしようとしないことについて。また、エラーを XML.load() メソッドに特定しました。これは、私の知る限り Scala ライブラリ メソッドです。
私の質問:これを修正するにはどうすればよいですか? これは私のコードの副産物ですか(から抜粋) ラファエル・フェレイラの投稿)、Java 固有の副産物であり、次のように対処する必要があります。 前のスレッド, 、それとも Scala 特有のものでしょうか?この呼び出しはどこで行われていますか? それはバグですか、それとも機能ですか?("私ですか?それは彼女ですよね?」)
解決 5
これは動作します。いくつかの探偵の仕事の後、最良などの詳細は、私はそれらを把握することができます:
発達RESTfulなインターフェースを解析しようとすると、私はパーサを構築し、上記(むしろ、類似の)エラーが発生します。私は、XML出力を変更するための各種パラメータを試してみたが、同じエラーを取得します。私はすぐにかき立てる(インターフェース自体から愚かcribbed)と同じエラーを取得したXML文書に接続しよう。その後、私はちょうど蹴りのために、何に接続しよう、と同じ(再び、おそらく唯一の同様の)エラーを取得します。
私はそれがソースまたはプログラムエラーがあったかどうか疑問始めたので、私は周りに探し始め、それは多くのグーグルとの継続的なissue-のように見え、SO同じトピックに当たります。これは、残念ながら、私はエラーの上流(言語)側面に焦点を当て、というよりもソースで自分自身をより下流のトラブルシューティングを作っています。
早送りとパーサが突然、の元のXML出力で動作します。私はいくつかの追加作業はサーバ側で行われていなかったことを確認した(ちょうどクレイジー偶然に?)。私はどちらかそれ以前のXMLを持っていますが、変更されている文書識別子に関連していることを疑うません。
これで、パーサは、私はそれで投げることができ、任意のよくフォーマットされたXMLだけでなく、RESTfulなインターフェース上で正常に動作します。また、すべてのXHTML DTDの私が試した上で失敗した(例えばwww.w3.org)。これは@SeanReillyが期待に反しているが、ものとジャイヴているようですW3の状態がを。
私はまだスカラ座に新たなんだ、私は特別な、または一般的なケースを持っているかどうかを判断することはできません。また私は、この問題はラインの下の別の形で私のために再発生しないことを保証することができます。 1つが使用されてきたJ-16 SDiZ @ @GClaramunt $によって提案されたものと同様のソリューションを使用しない限り、XHTMLを引っ張っすると、このエラーが発生し続けることを思えません。私は本当にこれは言語の問題です、または溶液(おそらくそれ以降)
の私の実装かどうかを知るために資格はありませんよ即時の時間枠のために、私は私はそれがの可能性のsource--そのXMLを解析するのではなく、他の者は、同じエラーがあったことを確認したことを確実にするために最適なソリューションをしてきただろうと思われます言語と機能的に問題があったと仮定します。
が、これは他の人がお役に立てば幸いです。
他のヒント
私も同じ問題に遭遇しましたが、洗練された解決策は見つかりませんでした (Scala メーリング リストに質問を投稿しようと考えています)。一方で、回避策を見つけました。f.setFeature(" を設定できるように、独自の SAXParserFactoryImpl を実装します。http://apache.org/xml/features/disallow-doctype-decl"、 真実);財産。良い点は、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 を呼び出すことができます
のアドレス指定がなければ、今のところ、問題、何が機能要求は、以下の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のソリューションは、私のための驚異を働きました。次のように私の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")
これはScalaの問題があります。ネイティブ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 }
あなたがやろうとしていることには2つの問題があります:
- Scala の XML パーサーは、DTD を取得すべきではないにもかかわらず、物理的に DTD を取得しようとしています。J-16 SDiZ はこの問題に対していくつかのアドバイスを提供しているようです。
- 解析しようとしているスタック オーバーフロー ページは XML ではありません。HTML4 は厳密です。
2 番目の問題は、実際には scala コードで修正することはできません。dtd の問題を回避できたとしても、ソースが有効な XML ではないことがわかります (たとえば、空のタグが適切に閉じられていないなど)。
XML パーサー以外のものを使用してページを解析するか、tidy などのユーティリティを使用して html を xml に変換する必要があります。
スカラ座の私の知識はかなり貧弱ですが、あなたが使用することができませんでし<のhref =「http://www.scala-lang.org/docu/files/api/scala/xml/parsing/ConstructingParser.html」 rel = "nofollowをnoreferrer"> 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)
Scalaの2.7.7のために私は
scala.xml.parsing.XhtmlParserでこれを行うために管理しました設定Xercesのは、あなたがXercesのを使用している場合にのみ動作切り替わります。エンティティリゾルバはどのJAXPパーサーのために働くます。
があり、より一般的な実体がそこにレゾルバですが、私がやろうとしているすべての有効なXHTMLを解析するときに、この実装は、トリックを行います。
http://code.google.com/p/ Javaの-XHTML-キャッシュのDTD-のEntityResolver / の
それはDTDをキャッシュし、ネットワークトラフィックを見送ることがいかに些細表示します。
いずれにせよ、これはの私はそれを修正する方法のです。私はいつも忘れています。私は常にエラーを取得します。私はいつもこのエンティティ・リゾルバをフェッチ行きます。それから私は、ビジネスに戻ってきます。