为什么JDOM的SAXBuilder会导致java.net.SocketException?

时间:2015-09-03 12:28:44

标签: sockets xhtml jdom

我有一个JDOM 1.1的问题,我找不到解决方案,更不用说原因(我已经搜索了很长一段时间......)。我有一个很小的测试程序,设置非常简单:

  1. 创建一个新的File对象,该对象已存在且我打算解析。这是一个XHTML文件。
  2. 创建一个新的SAXBuilder,其中validate设置为false
  3. 创建一个新的Document对象,该对象应由SAXBuilder
  4. 填充

    问题&我的问题

    不知何故,builder.build(file)会导致java.net.SocketException邮件Permission denied: connect。我不明白为什么它甚至需要套接字连接,除了验证,我在SAXBuilder的cosntructor中设置为false。所以,我的问题是:谁能告诉我这个例外的原因是什么?更具体地说,它试图连接到哪里以及如何防止它?

    谢谢!

    JAVA代码

    public static void main(String[] args) {
    File file = new File("C:\\Users\\ABC\\Desktop\\test.xhtml");
    SAXBuilder builder = new SAXBuilder(false);
    try {
      Document document = builder.build(file);
      XMLOutputter outputter = new XMLOutputter(Format.getPrettyFormat());
      outputter.output(document, System.out);
    } catch (JDOMException e) {
      e.printStackTrace();
    } catch (IOException e) {
      e.printStackTrace();
    }
    }
    

    XHTML文件

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    
    <head>
      <title>Title of document</title>
    </head>
    
    <body>
      some content
    </body>
    
    </html>

    堆栈跟踪

    java.net.SocketException: Permission denied: connect
    at java.net.DualStackPlainSocketImpl.connect0(Native Method)
    at java.net.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketImpl.java:79)
    at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:339)
    at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:200)
    at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:182)
    at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:172)
    at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
    at java.net.Socket.connect(Socket.java:579)
    at java.net.Socket.connect(Socket.java:528)
    at sun.net.NetworkClient.doConnect(NetworkClient.java:180)
    at sun.net.www.http.HttpClient.openServer(HttpClient.java:432)
    at sun.net.www.http.HttpClient.openServer(HttpClient.java:527)
    at sun.net.www.http.HttpClient.<init>(HttpClient.java:211)
    at sun.net.www.http.HttpClient.New(HttpClient.java:308)
    at sun.net.www.http.HttpClient.New(HttpClient.java:326)
    at sun.net.www.protocol.http.HttpURLConnection.getNewHttpClient(HttpURLConnection.java:996)
    at sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:932)
    at sun.net.www.protocol.http.HttpURLConnection.connect(HttpURLConnection.java:850)
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1300)
    at com.sun.org.apache.xerces.internal.impl.XMLEntityManager.setupCurrentEntity(XMLEntityManager.java:637)
    at com.sun.org.apache.xerces.internal.impl.XMLEntityManager.startEntity(XMLEntityManager.java:1290)
    at com.sun.org.apache.xerces.internal.impl.XMLEntityManager.startDTDEntity(XMLEntityManager.java:1257)
    at com.sun.org.apache.xerces.internal.impl.XMLDTDScannerImpl.setInputSource(XMLDTDScannerImpl.java:263)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$DTDDriver.dispatch(XMLDocumentScannerImpl.java:1164)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$DTDDriver.next(XMLDocumentScannerImpl.java:1050)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$PrologDriver.next(XMLDocumentScannerImpl.java:964)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:606)
    at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:117)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:510)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:848)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:777)
    at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:141)
    at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1213)
    at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:649)
    at org.jdom.input.SAXBuilder.build(SAXBuilder.java:489)
    at org.jdom.input.SAXBuilder.build(SAXBuilder.java:847)
    at org.jdom.input.SAXBuilder.build(SAXBuilder.java:826)
    at test.xmlparser.Main.main(Main.java:51)
    

1 个答案:

答案 0 :(得分:0)

问题是DTD用于验证XHTML文档。正如您在评论中发现的那样。

在XML中,DTD不仅用于验证XHTML文档结构,还用于提供需要扩展的任何实体引用(想想nbsp;等)。

我在回答这个问题的同时知道你已经有了答案的原因是因为你的答案是部分答案,而且这不是一个好的解决方案。删除XHTML文档的doctype将在以后引起其他问题。

不幸的是,正确的解决方案是让DTD文档可用于您的解析器。对于标准的XML解析,典型的方法是从URL中提取DTD(这是JDOM在这里尝试做的事情 - 实际上xerces试图在JDOM要求它解析文档时这样做)。如果您没有网络连接,那可能真的很难,正如您所发现的那样。但是,即使您确实有网络连接,如果XML是XHTML,那么您就会遇到双重问题 - W3C用户故意破坏您的代码!

您应该看到一些参考文献:

  1. W3C's excessive DTD block
  2. How to bypass the request to the internet for DTD以及IBM Developerworks
  3. 上的一些说明
  4. 使用目录:XML-Catalog
  5. 我开始的一个小项目“表现良好”并缓存文档:Resolver&lt; - 这对你没有用,因为你没有网络,但它有一些关于问题。
  6. 如果您对如何解析DTD有所了解,则可以使用以下内容将JDOM SAXBuilder提供给EntityResolver:setEntityResolver()