jdom 或 dom4j读取xml文件时如何让dtd验证使用本地dtd文件或者不生效

一、写在所有之前:
因为dom4j和jdom在这个问题上处理的方法是一模一样的,只是一个是SAXBuilder 一个SAXReader,这里以jdom距离,至于dom4j只需要同理替换一下就可以了。
二、问题发生的情况
当你用jdom读取一个有dtd验证的xml文件,同时你的网络是不通的情况下。会出现以下错误:
1,代码如下

None.gif package dom;
None.gif
None.gif
import java.io.File;
None.gif
None.gif
import org.jdom.Document;
None.gif
import org.jdom.input.SAXBuilder;
None.gif
ExpandedBlockStart.gifContractedBlock.gif
public class TestJdom dot.gif {
ExpandedSubBlockStart.gifContractedSubBlock.gif
publicstaticvoidmain(String[]args)dot.gif{
InBlock.gifFilefile
=newFile("./src/dom/aiwf_aiService.xml");
ExpandedSubBlockStart.gifContractedSubBlock.gif
if(file.exists())dot.gif{
InBlock.gifSAXBuilderbuilder
=newSAXBuilder();
ExpandedSubBlockStart.gifContractedSubBlock.gif
trydot.gif{
InBlock.gifDocumentdoc
=builder.build(file);
InBlock.gifSystem.out.println(doc);
ExpandedSubBlockStart.gifContractedSubBlock.gif}
catch(Exceptione)dot.gif{
InBlock.gife.printStackTrace();
ExpandedSubBlockEnd.gif}

ExpandedSubBlockStart.gifContractedSubBlock.gif}
elsedot.gif{
InBlock.gifSystem.out.println(
"cannotfindxmlfile:"
InBlock.gif
+file.getAbsolutePath());
ExpandedSubBlockEnd.gif}

ExpandedSubBlockEnd.gif}

ExpandedBlockEnd.gif}

None.gif

2,xml文件

None.gif <? xmlversion="1.0"encoding="GBK" ?>
None.gif
<! DOCTYPEworkflowPUBLIC"-//OpenSymphonyGroup//DTDOSWorkflow2.8//EN""http://www.opensymphony.com/osworkflow/workflow_2_8.dtd" >
None.gif
< workflow >
...............
None.gif
</ workflow >


3,错误如下

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

三、分析原因
当执行build的时候jdom分析到
DOCTYPEworkflowPUBLIC"-/OpenSymphonyGroup//DTDOSWorkflow2.8//EN""http://www.opensymphony.com/osworkflow/workflow_2_8.dtd
就会去读取http://www.opensymphony.com/osworkflow/workflow_2_8.dtd这里的dtd文件来验证,但是因为网络是不通的所以就会报socket错误。

四、解决办法
1,最开始查看jdom api发现了这样一个方法
builder.setValidation(false);
这样可以让jdom不做验证,但是结果依然出问题,查了一下原因,说虽然不验证但是还是会下载
2,参照jdom网站的FAQ http://www.jdom.org/docs/faq.html#a0100
这是原文内容
None.gif HowdoIkeeptheDTDfromloading?EvenwhenIturnoffvalidationtheparsertriestoloadtheDTDfile.
None.gif
None.gifEvenwhenvalidationisturnedoff,anXMLparserwillbydefaultloadtheexternalDTDfileinordertoparsetheDTDforexternalentitydeclarations.Xerceshasafeaturetoturnoffthisbehaviornamed"http://apache.org/xml/features/nonvalidating/load-external-dtd"andifyouknowyou'reusingXercesyoucansetthisfeatureonthebuilder.
None.gif
None.gifbuilder.setFeature(
None.gif"http://apache.org/xml/features/nonvalidating/load-external-dtd",false);
None.gif
None.gifIfyou'reusinganotherparserlikeCrimson,yourbestbetistosetupanEntityResolverthatresolvestheDTDwithoutactuallyreadingtheseparatefile.
None.gif
None.gifimportorg.xml.sax.*;
None.gifimportjava.io.*;
None.gif
None.gifpublicclassNoOpEntityResolverimplementsEntityResolver{
None.gifpublicInputSourceresolveEntity(StringpublicId,StringsystemId){
None.gifreturnnewInputSource(newStringBufferInputStream(""));
None.gif}
None.gif}
None.gif
None.gifTheninthebuilderdot.gif
None.gif
None.gif
None.gifbuilder.setEntityResolver(newNoOpEntityResolver());
None.gif
None.gifThereisadownsidetothisapproach.Anyentitiesinthedocumentwillberesolvedtotheemptystring,andwilleffectivelydisappear.Ifyourdocumenthasentities,youneedtosetExpandEntities(false)codeandensuretheEntityResolveronlysuppressestheDocType.
None.gif
里边教我们定义个类
ExpandedBlockStart.gif ContractedBlock.gif public class NoOpEntityResolver implements EntityResolver dot.gif {
ExpandedSubBlockStart.gifContractedSubBlock.gif
publicInputSourceresolveEntity(StringpublicId,StringsystemId)dot.gif{
InBlock.gif
returnnewInputSource(newStringBufferInputStream(""));
ExpandedSubBlockEnd.gif}

ExpandedBlockEnd.gif}

None.gif

通过builder.setEntityResolver(newNoOpEntityResolver())方法来隐蔽起dtd验证器。这样就不会出错了。试了一下确实没问题了。但要知道xml没有dtd验证是不好的,我们是否能让它使用本地dtd验证呢。例如本文的oswork
我把验证文件workflow_2_8.dtd拷贝到本地,能否验证的时候用本地的呢?
3,用本地dtd验证
方法有两种
方法一、更改xml中的doctype声明,但是一般情况下更改这个是不好的。更改后就不是标准的了。
方法二、验证期替换
看到上边FAQ讲的方法你是否有什么灵感呢?
看看下边这段代码

None.gif package dom;
None.gif
None.gif
import java.io.File;
None.gif
import java.io.IOException;
None.gif
None.gif
import org.jdom.Document;
None.gif
import org.jdom.input.SAXBuilder;
None.gif
import org.xml.sax.EntityResolver;
None.gif
import org.xml.sax.InputSource;
None.gif
import org.xml.sax.SAXException;
None.gif
ExpandedBlockStart.gifContractedBlock.gif
public class TestJdom dot.gif {
ExpandedSubBlockStart.gifContractedSubBlock.gif
publicstaticvoidmain(String[]args)dot.gif{
InBlock.gifFilefile
=newFile("./src/dom/aiwf_aiService.xml");
ExpandedSubBlockStart.gifContractedSubBlock.gif
if(file.exists())dot.gif{
InBlock.gifSAXBuilderbuilder
=newSAXBuilder();
InBlock.gifbuilder.setValidation(
false);
ExpandedSubBlockStart.gifContractedSubBlock.gifbuilder.setEntityResolver(
newEntityResolver()dot.gif{
InBlock.gif
publicInputSourceresolveEntity(StringpublicId,
ExpandedSubBlockStart.gifContractedSubBlock.gifStringsystemId)
throwsSAXException,IOExceptiondot.gif{
InBlock.gif
returnnewInputSource("./workflow_2_8.dtd");
ExpandedSubBlockEnd.gif}

ExpandedSubBlockEnd.gif}
);
ExpandedSubBlockStart.gifContractedSubBlock.gif
trydot.gif{
InBlock.gifDocumentdoc
=builder.build(file);
InBlock.gifSystem.out.println(doc);
ExpandedSubBlockStart.gifContractedSubBlock.gif}
catch(Exceptione)dot.gif{
InBlock.gife.printStackTrace();
ExpandedSubBlockEnd.gif}

ExpandedSubBlockStart.gifContractedSubBlock.gif}
elsedot.gif{
InBlock.gifSystem.out.println(
"cannotfindxmlfile:"
InBlock.gif
+file.getAbsolutePath());
ExpandedSubBlockEnd.gif}

ExpandedSubBlockEnd.gif}

ExpandedBlockEnd.gif}

None.gif

对了,同样是自己实现一个EntityResolver(这里用了匿名类),不同的是在里边使用本地的dtd验证
另外,匿名类内部,似乎这样写起来更顺眼些

None.gif InputStreamstream = new FileInputStream( " yourdtdfilepath " );
None.gifInputSourceis
= new InputSource(stream);
None.gifis.setPublicId(publicId);
None.gifis.setSystemId(systemId);
None.gif
return is;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值