Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/xml/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala/Java不尊重w3吗;过多的dtd流量“;规格?_Java_Xml_Scala_W3c_Dtd - Fatal编程技术网

Scala/Java不尊重w3吗;过多的dtd流量“;规格?

Scala/Java不尊重w3吗;过多的dtd流量“;规格?,java,xml,scala,w3c,dtd,Java,Xml,Scala,W3c,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)

我是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"
   }
}
结果总是:

   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的讨论,以及关于不尝试通过web访问此DTD的讨论。我还将错误隔离到XML.load()方法,据我所知,这是一个Scala库方法


我的问题:如何解决这个问题?这是我的代码(抄袭而来)的副产品,是我需要解决的特定于Java的问题(如中所述)的副产品,还是特定于Scala的问题?这个调用发生在哪里,它是一个bug还是一个特性?(“是我吗?是她,对吗?”)

您试图做的有两个问题:

  • Scala的xml解析器正在尝试物理检索DTD,而实际上它不应该检索DTD。J-16 SDiZ似乎对这个问题有一些建议
  • 您试图解析的堆栈溢出页不是XML。它是严格的Html4
第二个问题实际上不可能在scala代码中修复。即使解决了dtd问题,您也会发现源代码不是有效的XML(例如,空标记没有正确关闭)


您必须使用XML解析器以外的工具解析页面,或者研究使用tidy之类的实用程序将html转换为XML。

这是scala的问题。本机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)

我对Scala的了解很差,但你不能改用它吗


我遇到了同样的问题,我还没有找到一个优雅的解决方案(我正在考虑将这个问题发布到Scala邮件列表中),同时,我找到了一个解决方法:实现您自己的SAXParserFactoryImpl,这样您就可以设置f.setFeature(“,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而无需验证

而无需解决问题,目前,如果下面的函数请求返回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"
}
现在,我将MyXML内容放在fetchAndParseURL中只是为了尽可能保持示例的结构不变。对于实际使用,我会将其分离到顶级对象中,并将“parser”转换为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()
  }
}

导入在中定义的包,就可以开始了。

它可以正常工作。经过一些侦查工作后,我尽可能地了解了细节:

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

我开始质疑这是源代码错误还是程序错误,所以我开始四处搜索,这看起来像是一个持续的问题——谷歌和其他网站在同一主题上点击了很多次。不幸的是,这使我将注意力集中在错误的上游(语言)方面,而不是在源代码本身的下游进行故障排除

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

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

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

就目前的时间范围而言,我认为最好的解决方案是确保能够解析该XML源,而不是看到其他人也有同样的错误,并假设该语言存在功能问题


希望这对其他人有所帮助。

对于scala 2.7.7,我使用scala.xml.parsing.XhtmlParser实现了这一点。

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

还有更多的通用实体解析器,但是当我只想解析有效的XHTML时,这个实现就起到了作用

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


无论如何,这就是我修复它的方法。我总是忘记。我总是犯错误。我总是去拿这个实体解析器。然后我又开始做生意了。

格拉拉姆特的解决方案为我创造了奇迹。我的斯卡拉骗局
def fetchAndParseURL(URL:String) = (Http request(URL)) match {      
  case (true, body) =>      
    val xml = XML.load(body)
    "True"
  case _ => "False"
}
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"
}
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()
  }
}
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")