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的Stack Overflow线程 ,以及W3C的System Team Blog条目,关于不尝试通过Web访问这个DTD。 我还将错误隔离到XML.load()方法,就我所知,这是一个Scala库方法。

我的问题:我该如何解决这个问题? 这是我的代码的副产品(来自Raphael Ferreira的post ),我需要解决的Java特定产品的副产品,如前一个post ,或Scala特定的东西? 这个电话在哪里发生,它是一个错误还是一个function? ( “是我吗?是她,对吧?”

我遇到了相同的问题,我没有找到一个优雅的解决方案(我正在考虑将问题发布到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而无需validation

暂时没有解决问题,如果函数请求在下面返回false,你会发生什么?

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

发生什么是抛出exception。 不过你可以用这种方式重写它:

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

现在,我将myXML内容放在fetchAndParseURL中只是为了保持示例的结构尽可能不变。 对于实际使用,我将它分隔在顶级对象中,并将“解析器”变为def而不是val,以避免可变解析器出现问题:

 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问题。 Native 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 } 

有用。 在做了一些侦探工作之后,最好的细节我能算出来:

尝试解析开发RESTful接口,我构建解析器并获得上述(相当类似)错误。 我尝试各种参数来更改XML输出,但得到相同的错误。 我尝试连接到一个XML文档,我快速鞭打(从界面本身愚蠢地抄袭)并得到相同的错误。 然后我尝试连接到任何东西,只是为了踢,并得到相同(再次,可能只是类似)错误。

我开始质疑它是否是源代码或程序的错误,所以我开始搜索,它看起来像一个持续的问题 – 许多谷歌和SO点击同一主题。 遗憾的是,这使我专注于错误的上游(语言)方面,而不是在源自身的下游进行故障排除。

快进,解析器突然在原始 XML输出上工作。 我确认服务器方面已经完成了一些额外的工作(只是一个疯狂的巧合?)。 我没有早期的XML,但怀疑它与正在更改的文档标识符有关。

现在,解析器在RESTful接口上运行良好,以及我可以抛出的任何格式良好的XML。 它也在我尝试的所有XHTML DTD上都失败了(例如www.w3.org)。 这与@SeanReilly所期望的相反,但似乎与W3所说的一致 。

我还是Scala的新手,因此无法确定我是否有特殊或典型案例。 我也无法确定这个问题不会以另一种forms再次发生在我身上。 看起来拉XHTML会继续导致此错误,除非使用类似于@GClaramunt $ @ J-16 SDiZ建议使用的解决方案。 我真的没有资格知道这是语言的问题,还是我的解决方案的实现(可能是后来的)

在紧接着的时间范围内,我怀疑最好的解决方案是让我确保可以解析该XML源 – 而不是看到其他人有相同的错误并假设该语言存在function问题。

希望这有助于其他人。

你要做的事情有两个问题:

  • Scala的xml解析器试图在不应该的情况下物理检索DTD。 J-16 SDiZ似乎对这个问题有一些建议。
  • 您尝试解析的堆栈溢出页面不是XML。 这是严格的Html4。

第二个问题实际上无法修复您的scala代码。 即使你解决了dtd问题,你也会发现源只是无效的XML(例如,空标签没有正确关闭)。

您必须使用除XML解析器之外的内容来解析页面,或者使用像tidy这样的实用程序来调查将html转换为xml。

我对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) 

对于scala 2.7.7,我设法使用scala.xml.parsing.XhtmlParser执行此操作

设置Xerces开关仅在使用Xerces时有效。 实体解析器适用于任何JAXP解析器。

那里有更多的通用实体解析器,但是当我尝试做的就是解析有效的XHTML时,这个实现就可以了。

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

显示缓存DTD和放弃网络流量是多么的微不足道。

无论如何,这就是我修复它的方法 。 我总是忘记。 我总是得到错误。 我总是去取这个实体解析器。 然后我又回来了。