dom4j 自定义 dom4j 自定义解析 dom4j 自定义解析规则 取消dom4j的dtd验证

dom4j 自定义  dom4j 自定义解析  dom4j 自定义解析规则

这几天做xml解析,用的是dom4j,网上说dom4j可能会出现OUTOF MEMORY 异常,但是还是坚持用了。

懒得去研究别的包了,就这个了,内存问题可以通过设置jvm的运行内存就可以解决,不是什么大问题。

jvm内存设置:

-Xms500M -Xmx1000M

eclipse 里要运行的java文件,右键,run->run configuration

run configuration window 里arguments tab里有vm arguments 输入框,输入以上参数即可。

找了半天没有找到能自定义解析的方法,还是动手研究了dom4j的API了,后来还是找到了。

SaxReader有两个方法

setDefaultHandler(ElementHandler handler) 

addHandler(String path, ElementHandler handler) 

第一个是每个节点都用指定的handler,下面那个是对于指定的路径使用指定handler。

具体的原理说明的就不细说了,我是懒得看这些细节,不是自己实现的就会用就行,能达到目标就O了。

嫌看不懂dom4j就自己实现一个,这是最好的办法。但是我是没那能力了。

参考的说一下,dom4j也是用的apache foundation的 Xerces jar包,

具体的参考http://xerces.apache.org/

下面给个例子。

<word><c>sobre<sup>1</sup></c></word>

我的要求是<word>以内的标签都当做字符串来存储,但是dom4j很笨,非得建立如下dom树

–word

—-c 

——–sobre

——–sup

————1

这只是个层次结构,我要word以内的内容都变成字符串

 

import java.util.List;

 

import org.dom4j.Attribute;

import org.dom4j.Element;

import org.dom4j.ElementHandler;

import org.dom4j.ElementPath;

import org.dom4j.Node;

import org.dom4j.tree.DefaultAttribute;

import org.dom4j.tree.DefaultCDATA;

import org.dom4j.tree.DefaultElement;

 

/**

 * (Description about the type)

 * 

 * @date 2011-9-14

 * @author jongsuny

 */

 

public class MyHandler implements ElementHandler {

 

@Override

public void onStart( ElementPath elementPath ) {

 

}

 

private Element cloneElement( String name, String value,Element e ) {

Element em = new DefaultElement( name );

List<Attribute> attrs = e.attributes();

for ( Attribute at : attrs ) {

Attribute a = new DefaultAttribute( at.getName(), at.getValue() );

em.add( a );

}

em.add( new DefaultCDATA( value ) );

return em;

}

@Override

public void onEnd( ElementPath elementPath ) {

Element e = elementPath.getCurrent();

System.out.println( e.getName() + " content=" + e.content().size() );

System.out.println( e.asXML() );

e = getString( e );

}

private Element getString( Element e ) {

System.out.println("xml: "+ e.asXML() );

StringBuffer sb = new StringBuffer();

List<Node> list = (List<Node>) e.content();

String ignore = "b;i;sup;sub;c;img;ht;lk";

String sp="word";

if (sp.indexOf( e.getName() ) != -1 ) {

String str = e.asXML();

System.out.println(" "+str.indexOf( ">" )+" "+str.lastIndexOf( "<" ));

if(str.indexOf( ">" )>-1&&str.lastIndexOf( "<" )>-1&&str.lastIndexOf( "<" )>str.indexOf( ">" ))

str=str.substring( str.indexOf( ">" )+1,str.lastIndexOf( "<" ) );

Element parent = e.getParent();

System.out.println( "orgin parent=" + parent.asXML() );

e.detach();

Element em = cloneElement( e.getName(), str ,e);

parent.add( em );

System.out.println( "after parent=" + parent.asXML() );

return em;

}

return e;

}

}

说明:1:。getString方法通过一个element把word标签下的所有标签变成字符串,2。cloneElement里用到DefaultCDATA ,他是不把 > 这样的字符 变成 &gt; 这样的字符串。dom4j的 具体element的实现查看org.dom4j.tree 包
取消dom4j的dtd验证顺便说一下dom4j的SaxReader不管你设不设置setValidation(false),他都会去验证dtd,

我就很纳闷,为false你还要去验证,你提供这么个办法干嘛。你会有很多理由说我不懂瞎说。

可以肯定的是你的api里没有相关的说明。

不管你是什么理由这么设计的,但是不好用才是你的事实。

解决方案

1.最简单的,把doctype那一行删除掉

2.可以实现自己的EntityResolver 

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

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

reader.setEntityResolver(new NoOpEntityResolver());

参考资料:

http://www.blogjava.net/dreamstone/archive/2007/08/29/140993.html

发表评论

电子邮件地址不会被公开。 必填项已用 * 标注

您可以使用这些 HTML 标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>