DANCE WITH JAVA

          開(kāi)發(fā)出高質(zhì)量的系統(tǒng)

          常用鏈接

          統(tǒng)計(jì)

          積分與排名

          好友之家

          最新評(píng)論

          jdom 或 dom4j讀取xml文件時(shí)如何讓dtd驗(yàn)證使用本地dtd文件或者不生效

          一、寫(xiě)在所有之前:
          因?yàn)閐om4j和jdom在這個(gè)問(wèn)題上處理的方法是一模一樣的,只是一個(gè)是SAXBuilder 一個(gè)SAXReader,這里以jdom距離,至于dom4j只需要同理替換一下就可以了。
          二、問(wèn)題發(fā)生的情況
          當(dāng)你用jdom讀取一個(gè)有dtd驗(yàn)證的xml文件,同時(shí)你的網(wǎng)絡(luò)是不通的情況下。會(huì)出現(xiàn)以下錯(cuò)誤:
          1,代碼如下

          package dom;

          import java.io.File;

          import org.jdom.Document;
          import org.jdom.input.SAXBuilder;

          public class TestJdom {
              
          public static void main(String[] args) {
                  File file 
          = new File("./src/dom/aiwf_aiService.xml");
                  
          if (file.exists()) {
                      SAXBuilder builder 
          = new SAXBuilder();
                      
          try {
                          Document doc 
          = builder.build(file);
                          System.out.println(doc);
                      }
           catch (Exception e) {
                          e.printStackTrace();
                      }

                  }
           else {
                      System.out.println(
          "can not find xml file:"
                              
          + file.getAbsolutePath());
                  }

              }

          }

          2,xml文件

          <?xml version="1.0" encoding="GBK"?>
          <!DOCTYPE workflow PUBLIC "-//OpenSymphony Group//DTD OSWorkflow 2.8//EN" "http://www.opensymphony.com/osworkflow/workflow_2_8.dtd">
          <workflow>
                          ...............
          </workflow>


          3,錯(cuò)誤如下

          java.net.SocketException: Permission denied: connect
              at java.net.PlainSocketImpl.socketConnect(Native Method)
              at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:
          333)
              at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:
          195)
              at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:
          182)
              at java.net.Socket.connect(Socket.java:
          507)
              at java.net.Socket.connect(Socket.java:
          457)
              at sun.net.NetworkClient.doConnect(NetworkClient.java:
          157)
              at sun.net.www.http.HttpClient.openServer(HttpClient.java:
          365)
              at sun.net.www.http.HttpClient.openServer(HttpClient.java:
          477)
              at sun.net.www.http.HttpClient.
          <init>(HttpClient.java:214)
              at sun.net.www.http.HttpClient.New(HttpClient.java:
          287)
              at sun.net.www.http.HttpClient.New(HttpClient.java:
          299)
              at sun.net.www.protocol.http.HttpURLConnection.getNewHttpClient(HttpURLConnection.java:
          792)
              at sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:
          744)
              at sun.net.www.protocol.http.HttpURLConnection.connect(HttpURLConnection.java:
          669)
              at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:
          913)
              at com.sun.org.apache.xerces.internal.impl.XMLEntityManager.setupCurrentEntity(XMLEntityManager.java:
          973)
              at com.sun.org.apache.xerces.internal.impl.XMLEntityManager.startEntity(XMLEntityManager.java:
          905)
              at com.sun.org.apache.xerces.internal.impl.XMLEntityManager.startDTDEntity(XMLEntityManager.java:
          872)
              at com.sun.org.apache.xerces.internal.impl.XMLDTDScannerImpl.setInputSource(XMLDTDScannerImpl.java:
          282)
              at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$DTDDispatcher.dispatch(XMLDocumentScannerImpl.java:
          1021)
              at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:
          368)
              at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:
          834)
              at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:
          764)
              at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:
          148)
              at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:
          1242)
              at org.jdom.input.SAXBuilder.build(SAXBuilder.java:
          453)
              at org.jdom.input.SAXBuilder.build(SAXBuilder.java:
          810)
              at org.jdom.input.SAXBuilder.build(SAXBuilder.java:
          789)
              at dom.TestJdom.main(TestJdom.java:
          26)

          三、分析原因
          當(dāng)執(zhí)行build的時(shí)候jdom分析到
          DOCTYPE workflow PUBLIC "-/OpenSymphony Group//DTD OSWorkflow 2.8//EN" "http://www.opensymphony.com/osworkflow/workflow_2_8.dtd
          就會(huì)去讀取http://www.opensymphony.com/osworkflow/workflow_2_8.dtd 這里的dtd文件來(lái)驗(yàn)證,但是因?yàn)榫W(wǎng)絡(luò)是不通的所以就會(huì)報(bào)socket錯(cuò)誤。

          四、解決辦法
          1,最開(kāi)始查看jdom api發(fā)現(xiàn)了這樣一個(gè)方法
          builder.setValidation(false);
          這樣可以讓jdom不做驗(yàn)證,但是結(jié)果依然出問(wèn)題,查了一下原因,說(shuō)雖然不驗(yàn)證但是還是會(huì)下載
          2,參照jdom網(wǎng)站的FAQ  http://www.jdom.org/docs/faq.html#a0100
          這是原文內(nèi)容
          How do I keep the DTD from loading? Even when I turn off validation the parser tries to load the DTD file.

          Even when validation is turned off, an XML parser will by default load the external DTD file in order to parse the DTD for external entity declarations. Xerces has a feature to turn off this behavior named "http://apache.org/xml/features/nonvalidating/load-external-dtd" and if you know you're using Xerces you can set this feature on the builder.

          builder.setFeature(
            "http://apache.org/xml/features/nonvalidating/load-external-dtd", false);

          If you're using another parser like Crimson, your best bet is to set up an EntityResolver that resolves the DTD without actually reading the separate file.

          import org.xml.sax.*;
          import java.io.*;

          public class NoOpEntityResolver implements EntityResolver {
            public InputSource resolveEntity(String publicId, String systemId) {
              return new InputSource(new StringBufferInputStream(""));
            }
          }

          Then in the builder


          builder.setEntityResolver(new NoOpEntityResolver());

          There is a downside to this approach. Any entities in the document will be resolved to the empty string, and will effectively disappear. If your document has entities, you need to setExpandEntities(false) code and ensure the EntityResolver only suppresses the DocType.
          里邊教我們定義個(gè)類
          public class NoOpEntityResolver implements EntityResolver {
            
          public InputSource resolveEntity(String publicId, String systemId) {
                      
          return new InputSource(new StringBufferInputStream(""));
            }

          }

          通過(guò)builder.setEntityResolver(new NoOpEntityResolver())方法來(lái)隱蔽起dtd驗(yàn)證器。這樣就不會(huì)出錯(cuò)了。試了一下確實(shí)沒(méi)問(wèn)題了。但要知道xml沒(méi)有dtd驗(yàn)證是不好的,我們是否能讓它使用本地dtd驗(yàn)證呢。例如本文的oswork
          我把驗(yàn)證文件workflow_2_8.dtd拷貝到本地,能否驗(yàn)證的時(shí)候用本地的呢?
          3,用本地dtd驗(yàn)證
          方法有兩種
          方法一、更改xml中的doctype聲明,但是一般情況下更改這個(gè)是不好的。更改后就不是標(biāo)準(zhǔn)的了。
          方法二、驗(yàn)證期替換
          看到上邊FAQ講的方法你是否有什么靈感呢?
          看看下邊這段代碼

          package dom;

          import java.io.File;
          import java.io.IOException;

          import org.jdom.Document;
          import org.jdom.input.SAXBuilder;
          import org.xml.sax.EntityResolver;
          import org.xml.sax.InputSource;
          import org.xml.sax.SAXException;

          public class TestJdom {
              
          public static void main(String[] args) {
                  File file 
          = new File("./src/dom/aiwf_aiService.xml");
                  
          if (file.exists()) {
                      SAXBuilder builder 
          = new SAXBuilder();
                      builder.setValidation(
          false);
                      builder.setEntityResolver(
          new EntityResolver() {
                          
          public InputSource resolveEntity(String publicId,
                                  String systemId) 
          throws SAXException, IOException {
                              
          return new InputSource("./workflow_2_8.dtd");
                          }

                      }
          );
                      
          try {
                          Document doc 
          = builder.build(file);
                          System.out.println(doc);
                      }
           catch (Exception e) {
                          e.printStackTrace();
                      }

                  }
           else {
                      System.out.println(
          "can not find xml file:"
                              
          + file.getAbsolutePath());
                  }

              }

          }

          對(duì)了,同樣是自己實(shí)現(xiàn)一個(gè)EntityResolver(這里用了匿名類),不同的是在里邊使用本地的dtd驗(yàn)證
          另外,匿名類內(nèi)部,似乎這樣寫(xiě)起來(lái)更順眼些

          InputStream stream = new FileInputStream( "your dtd file path" );
                              InputSource is 
          = new InputSource(stream);
                              is.setPublicId(publicId);
                              is.setSystemId(systemId);
                              
          return is;

          posted on 2007-08-29 17:05 dreamstone 閱讀(8351) 評(píng)論(6)  編輯  收藏 所屬分類: 利器 、其它開(kāi)源框架

          評(píng)論

          # re: jdom 或 dom4j讀取xml文件時(shí)如何讓dtd驗(yàn)證使用本地dtd文件或者不生效 2007-09-07 17:19 楊愛(ài)友

          終于被我找到了。原來(lái)deeamstone就是你,慚愧啊。  回復(fù)  更多評(píng)論   

          # re: jdom 或 dom4j讀取xml文件時(shí)如何讓dtd驗(yàn)證使用本地dtd文件或者不生效 2007-09-07 21:25 dreamstone

          你是 ?  回復(fù)  更多評(píng)論   

          # re: jdom 或 dom4j讀取xml文件時(shí)如何讓dtd驗(yàn)證使用本地dtd文件或者不生效[未登錄](méi) 2008-03-11 22:15 java初學(xué)者

          要的就是你1!
          謝謝了樓主!!  回復(fù)  更多評(píng)論   

          # re: jdom 或 dom4j讀取xml文件時(shí)如何讓dtd驗(yàn)證使用本地dtd文件或者不生效 2008-03-18 11:14 thx

          thanks a lot.  回復(fù)  更多評(píng)論   

          # re: jdom 或 dom4j讀取xml文件時(shí)如何讓dtd驗(yàn)證使用本地dtd文件或者不生效 2008-07-05 21:17 Velar

          Wow, that rocks!
          really appreciated it!  回復(fù)  更多評(píng)論   

          # re: jdom 或 dom4j讀取xml文件時(shí)如何讓dtd驗(yàn)證使用本地dtd文件或者不生效[未登錄](méi) 2010-06-03 18:27 gongmingwind

          真是豁然開(kāi)朗啊  回復(fù)  更多評(píng)論   

          主站蜘蛛池模板: 内黄县| 康马县| 江门市| 疏勒县| 丁青县| 泰兴市| 娄底市| 延边| 卫辉市| 庄浪县| 苗栗县| 阿瓦提县| 天台县| 罗源县| 新蔡县| 徐闻县| 长寿区| 日照市| 都昌县| 莲花县| 辽阳县| 内丘县| 康定县| 祁东县| 龙海市| 南投市| 全南县| 北辰区| 临沂市| 岗巴县| 定远县| 丰都县| 临江市| 南宁市| 本溪市| 贵溪市| 封丘县| 南郑县| 张家川| 苏尼特右旗| 岳池县|