解析xml时遇到的一些问题

1.使用Dom4j解析大文件时内存溢出的问题

问题是这样的,当我用dom4j去解析一个几十M的xml时,就出现out of memory.当然了,这也是根据你的机器性能而定的,我们都知道dom4j在各种DOM解析器中应该算是性能最好的,连大名鼎鼎的Hibernate都是用dom4j来解析XML配置文件的
问题出在于使用dom4j的SAXReader是会把整个XML文件一次性读入,如果XML文件过大就会抛出out of memory,但即使是使用SAXParser批量读入解析,但它也是一次解析完,假设XML文件有几万条数据,那么解析后就必须在内存放入这几万条对象.

常用的Dom4j文件解析方式:

InputStreamis = new FileInputStream(filePath);
SAXReaderreader
= new SAXReader(); // 将整个XML构建为一个Document
Documentdoc = reader.read(is);
Elementroot
= doc.getRootElement(); // 获得根节点
for (Objectobj:root.elements()){ // 遍历每个节点
Elemente = (Element)obj; // 对当前节点进行操作
}


解决方法:使用ElementHandler解析文件

通过查API可以发现ElementHandler接口,下面是接口的介绍

ElementHandler interface definesahandlerofElementobjects.Itisusedprimarilyineventbasedprocessingmodelssuchas for
processinglargeXMLdocumentsastheyarebeingparsedratherthanwaitinguntilthewholedocumentisparsed.


好了,它就是我们想要的,通过实现以下两个method,就可以达成我们的需求

onEnd(ElementPath elementPath)
Called by an event based processor when an elements closing tag is encountered.
onStart(ElementPath elementPath)
Called by an event based processor when an elements openning tag is encountered.

下面是代码

FileInputStreamfis = new FileInputStream(addPath);
SAXReaderreader
= new SAXReader();
ElementHandleraddHandler
= new MyElementHandler(); // 建立MyElementHandler的实例
reader.addHandler( " /root/test1 " ,addHandler); // 节点
reader.addHandler( " /root/test2 " ,addHandler); // 节点
reader.read(fis);


...

class MyElementHandler implements ElementHandler{
public void onStart(ElementPathep){}

public void onEnd(ElementPathep){
Elemente
= ep.getCurrent(); // 获得当前节点
// 对节点进行操作。。。
e.detach(); // 处理完当前节点后,将其从dom树中剪除
}
}


因为每次处理完一个节点后并没有保存在dom树中,所以不会出现内存溢出的情况
上面的省略了一些业务代码,不知道你是否明白或有更好的方法,可以和我联系QQ:34174409

2.BOM头问题

使用java.io.Reader读取XML文件进行解析时出现异常
org.dom4j.DocumentException: Error on line 1 of document : Content is not allowed in prolog.
Nested exception:
org.xml.sax.SAXParseException: Content is not allowed in prolog.
原因在于:UTF-8编码文件存在BOM头,Reader类无法正确识别

解决方法:
(1).使用16进制编辑器手动删除BOM头

这个...自行解决

(2).InputStream读取流中前面的字符,看是否有BOM,如果有BOM,干掉BOM头

PushbackInputStreampis = new PushbackInputStream(in);
int ch = pis.read();
if (ch != 0xEF ){
testin.unread(ch);
}
else if ((ch = pis.read()) != 0xBB ){
pis.unread(ch);
pis.unread(
0xef );
}
else if ((ch = pis.read()) != 0xBF ){
throw new IOException( " wrongformat " );
}
else
{
}


(3).InputStream读取完文件,干掉BOM头

FileInputStreamfin = new FileInputStream(fileName);
// 写入临时文件
InputStreamin = getInputStream(fin);
StringtmpFileName
= fileName + " .tmp " ;
FileOutputStreamout
= new FileOutputStream(tmpFileName);
byte b[] = new byte [ 4096 ];

int len = 0 ;
while (in.available() > 0 ){
len
= in.read(b, 0 , 4096 );
out.write(b,
0 ,len);
}
in.close();
fin.close();
out.close();

// 临时文件写完,开始将临时文件写回本文件。
in = new FileInputStream(tmpFileName);
System.out.println(
" [ " + fileName + " ] " );
out
= new FileOutputStream(fileName);

while (in.available() > 0 ){
len
= in.read(b, 0 , 4096 );
out.write(b,
0 ,len);
}
in.close();
out.close();


(3).非法XML字符串

解析XML文件时出现非法字符的Exception(即使该字符位于CDATA段内): org.xml.sax.SAXParseException: An invalid XML character (Unicode: 0xb) was found in the CDATA section.
原因在于:根据W3C标准,有一些字符不能出现在XML文件中:
0x00 - 0x08
0x0b - 0x0c
0x0e - 0x1f
解析XML时遇到这些字符就会出错

解决方法:
对有可能出问题的XML文件,进行字符过滤后再进行解析。

public static StringstripNonValidXMLChars(Stringstr){
if (str == null || "" .equals(str)){
return str;
}
return str.replaceAll( " [\\x00-\\x08\\x0b-\\x0c\\x0e-\\x1f] " , "" );
}



博文来源:http://www.blogjava.net/dongbule/archive/2010/09/28/333262.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值