Scala/Java不尊重w3"多余的dtd流量"规范吗?

Joh*_*tta 15 java xml w3c dtd scala

我是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"
   }
}
Run Code Online (Sandbox Code Playgroud)

运行哪个(URL无关紧要,这是一个笑话示例):

scala> HTTPParse.fetchAndParseURL("http://stackoverflow.com")
Run Code Online (Sandbox Code Playgroud)

结果总是:

   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...
Run Code Online (Sandbox Code Playgroud)

我已经看到了关于Java 的Stack Overflow线程,以及W3C的System Team Blog条目,关于不尝试通过Web访问这个DTD.我还将错误隔离到XML.load()方法,据我所知,这是一个Scala库方法.

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

GCl*_*unt 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); 
      } 
    }
Run Code Online (Sandbox Code Playgroud)

没什么特别的,我只是想有机会设置房产.

(注意:这是普通的Java代码,很可能你也可以在Scala中编写相同的代码)

在Scala代码中,您需要配置JVM以使用新工厂:

System.setProperty("javax.xml.parsers.SAXParserFactory", "mypackage.MyXMLParserFactory");
Run Code Online (Sandbox Code Playgroud)

然后你可以调用XML.load而无需验证


Dan*_*ral 7

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

def fetchAndParseURL(URL:String) = {      
  val (true, body) = Http request(URL)
Run Code Online (Sandbox Code Playgroud)

发生什么是抛出异常.你可以用这种方式重写它,但是:

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

现在,为了修复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"
}
Run Code Online (Sandbox Code Playgroud)

现在,我将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()
  }
}
Run Code Online (Sandbox Code Playgroud)

导入它定义的包,你很高兴.


Joh*_*tta 2

有用。经过一些侦探工作,我能弄清楚的最好细节是:

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

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

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

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

我对 Scala 还很陌生,所以无法确定我是否有特殊或典型的情况。我也不能保证这个问题不会以另一种形式再次出现在我身上。似乎拉动 XHTML 会继续导致此错误,除非使用类似于 @GClaramunt $ @J-16 SDiZ 所建议的解决方案。我真的没有资格知道这是否是语言的问题,或者是我的解决方案的实现(可能是后者)

对于当前的时间范围,我怀疑最好的解决方案是确保可以解析该 XML 源,而不是看到其他人也有同样的错误并假设该语言存在功能问题。

希望这对其他人有帮助。