HTML转XML

一个学术搜索的项目,需要用到学者信息的XML数据。之前项目中从dblp网站爬到了各个学者的主页(html格式),比如http://www.informatik.uni-trier.de/~ley/pers/hd/m/Meersman:Robert.html。现在要从这些HTML文件中提取出每个作者的姓名,论文等信息,如下DTD格式的XML文档。

<!DOCTYPE authors [ 
<!ELEMENT authors (author+)>
<!ELEMENT author (name,papers)>
<!ATTLIST author key ID #REQUIED >
<!ELEMENT name (#PCDATA)>
<!ELEMENT papers (paper+)>
<!ELEMENT paper (title,year,proceeding,authors?,page?)>
<!ELEMENT title (#PCDATA)>
<!ELEMENT year (#PCDATA)>
<!ELEMENT proceeding (#PCDATA)>
<!ELEMENT page (#PCDATA)>
<!ELEMENT authors (author+)>
<!ELEMENT author (name)>
<!ELEMENT name (#PCDATA)>
]>

出于惯性,选择用java;为了方便调试和操作,没有选用现有的htmlparser之类的工具,而是采用正则表达式来匹配html源文件来提取作者的各种信息,然后用jdom生成符合DTD格式的XML文件。下面是几个tip:

(1)正则表达式

做这个工作最大的体会就是正则表达式这个看似简单的工具,功能还是很强大的。在提取信息的过程中,由于文章的标题,甚至是学者的名字中有可能包含匹配信息所依赖的标志符号。这样就会导致得到的不是想要的信息,甚至有时候会想是不是正则表达式的描述能力有限,没办法将两种情况区分开。但是,事实上,正则表达式的描述能力还是非常强悍的,只要将正则表达式写得复杂些,总能将想要的和不想要的信息区分开。正则语言表达能力强的理论依据是其与NFA(非确定性有限自动机一一对应)blablabla...

  • 正则表达式匹配换行的时候,要使用选项DOTALL、MULTILINE之类的。具体地如何匹配一个换行要自己实验摸索,可以试试$\r\n^匹配一行结束到新行开始,也可以用[^.]+(.表示出新行之外的任意字符,这样正好可以匹配一行结束到一行开始)。
  • 正则表达式匹配不回滚:正则表达式匹配的时候,匹配到一个内容,就从匹配内容结束字符的下一个字符开始寻找下一个匹配,而不是从匹配内容开始的下一个字符开始寻找下一个功能。简单的说,用aa去匹配aaaa,之后输出两个匹配,而不是三个。
    • int i=0;
      Pattern pt=null;
      Matcher mc=null;
      String str="aaaa";
      String reg="aa";
      pt = Pattern.compile(reg);
      mc = pt.matcher(str);
      while (mc.find()) {
      	++i;
          System.out.println(i+": "+mc.group(0));
      }
      输出:
      1: aa
      2: aa
  • 正则表达式符号“|”的优先级比较低,(AB)C|CDE相当于((AB)C)|(CDE)。

(2)JVM内存相关

java不像C/C++,没有提供显示的动态分配内存的方法。所有的GC(垃圾回收机制)由jvm来实现。Java虚拟机默认分配64M内存,如果你的应用比较大,超出64M内存,Java虚拟机就会抛出outOfMemoryError,并停止运行。不过可以在eclipse中设置和jvm内存分配相关的参数:Window->Preference->Java->Installed JREs->选中要修改的一行,点Edit,在Default JVM Arguments中添加参数:-Xmx256M (也可以添加其他参数如-Xms128M -XX:PermSize=64M -XX:MaxPermSize=128M)。各参数意义如下:

JVM主要管理两种类型的内存:堆和非堆。堆是运行时数据区域,所有类实例和数组的内存均从此处分配。堆是在 Java 虚拟机启动时创建的。在JVM中堆之外的内存称为非堆内存(Non-heap memory)。简单来说堆就是Java代码可及的内存,是留给开发人员使用的;非堆就是JVM留给自己用的,所有方法区、JVM内部处理或优化所需的内存(如JIT编译后的代码缓存)、每个类结构(如运行时常数池、字段和方法数据)以及方法和构造方法的代码都在非堆内存中。

  • 堆内存分配
JVM初始分配的堆内存由-Xms指定,默认是物理内存的1/64;JVM最大分配的内存由-Xmx指定,默认是物理内存的1/4。默认空余堆内存小于 40%时,JVM就会增大堆直到-Xmx的最大限制;空余堆内存大于70%时,JVM会减少堆直到-Xms的最小限制。因此服务器一般设置-Xms、 -Xmx相等以避免在每次GC后调整堆的大小。
  • 非堆内存分配
JVM使用-XX:PermSize设置非堆内存初始值,默认是物理内存的1/64;由XX:MaxPermSize设置最大非堆内存的大小,默认是物理内存的1/4。


JVM的参数设置不能超过JVM内存的最大限制

因此,对以上参数进行设置时必须注意以下两点,否则可能导致程序无法启动: 参数中-Xms的值不能大于-Xmx,或者-XX:PermSize的值不能大于-XX:MaxPermSize;-Xmx的值和-XX:MaxPermSize的总和不能超过JVM内存的最大限制。(首先JVM内存限制于实际的最大物理内存,假设物理内存无限大的话,JVM内存的最大值跟操作系统有很大的关系。简单的说就32位处理器虽然可控内存空间有4GB,但是具体的操作系统会给一个限制,这个限制一般是2GB-3GB(一般来说Windows系统下为1.5G-2G,Linux系统下为2G-3G),而64bit以上的处理器就不会有限制了。)

(3)将文件转化为大字符串

用正则表达式把HTML文件内容当做大字符串匹配,用下面的函数可以将一个文件转换为字符串。

//放在一个类的内部作为静态方法实现的
//将文件内容转为一个长字符串
public static String getContent(String fileName) throws Exception {
	InputStream in = new FileInputStream(fileName);
	byte[] aa = new byte[in.available()];
	in.read(aa);
	return new String(aa);
}

参考资料:

JVM内存相关:http://www.cnblogs.com/yyyyy5101/articles/1898737.html


文章浅显,欢迎交流。



你可能感兴趣的:(java,html,xml,正则表达式,jvm内存)