XML文件解析工具化基础篇

在今后的Java学习过程中,我们会遇到很多使用XML文件等来存储必要信息的情况,每次都要进行解析,这样岂不是很繁琐。在学习Java的过程中,我们必须要有一种思想–工具化。将所有重复动作工具化,使其解决具有普遍性的情况。下面就将之前所讲的《XML文件解析》进行工具化,使其适用于大多数解析情况。
如果看不懂这篇文章,可以先看看前面提到的,了解一下XML解析的基本过程。

在此强调一下,本次编写的工具,只是根据“标签名”进行解析。

一、思路

为了使解析过程工具化,首先,我们必须找到解析文件的共同点;其次,因为每个文件需要解析出来的内容不一样,该如何处理这部分也是一个问题。

1.文件读取方式

无论解析任何一个文件,先要找到这个文件,并对文件进行读取。为了适应大多数情况,给出两种读取文件的方式。

1)以输入流形式读取
private static Document getDocument(InputStream is) {
		Document document = null;
		try {
			document =db.parse(is);
		} catch (SAXException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return document;
	}
2)以字符串形式读取

本质上,以字符串形式读取还是调用了输入流形式读取的方法,不过,一般在确定读取的文件时,我们是以字符串形式传入,而不是输入流形式。

public static Document  getDocument(String xmlPath) {
		InputStream is = XMLParser.class.getResourceAsStream(xmlPath);
		if(is == null) {
			 System.out.println("xmlPath["+xmlPath+"]不存在!");
			 return null;
		}
		return getDocument(is);
	}
2.不同类型节点解析

在制作工具的过程中,我们针对XML文件结构将其分为两种,文档节点解析和元素节点解析。

1)文档节点(Document)解析
/*
 * @param document	解析的文件节点
 * @param tagName 	需要解析的标签
 */
public void parseTag(Document document,String tagName) {
		NodeList nodeList = document.getElementsByTagName(tagName);
		for(int index = 0; index<nodeList.getLength(); index++) {
			Element ele = (Element) nodeList.item(index);
			//后面对ele的进一步解析:取属性、取textContent或者进一步取Element,都是使用工具的人做的事,
			//所以此处使用抽象方法,有使用该工具的人进行具体实现
			dealElement(ele, index);		
		}
	}
2)元素(Element)节点解析
/**
 * @param element 需要解析的元素节点
 * @param tagName 需要解析的标签
 */
public void parseTag(Element element,String tagName) {
		NodeList nodeList = element.getElementsByTagName(tagName);
		for(int index = 0; index<nodeList.getLength(); index++) {
			Element ele =(Element)nodeList.item(index);
			dealElement(ele, index);
		}
	}

其实文档节点解析和元素节点解析,都是差不多,仔细观察就会发现两者除了第一句里调用getElementsByTagName()方法的对象不同以外,其他过程都是一样的。

3.具体解析过程

由于每个文件内容不一样,所以无法将这部分进行工具化,故使用抽象方法,将来这部分由使用该工具的人来进行具体实现。

public abstract void dealElement(Element element,int index) ;

二、工具的具体实现

看了之前文章的人必然知道,在解析时有四句固定搭配,不过在上面的思路中已经解决了其中两句,还有两句将会在代码中给出具体处理。

import java.io.IOException;
import java.io.InputStream;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

public abstract class XMLParser {
	private static final DocumentBuilderFactory dbf;
	private static DocumentBuilder db;
	
	//单例模式,只在该程序第一次运行时执行一次,之后再运行不再执行
	static {
		dbf = DocumentBuilderFactory.newInstance();
		try {
			db = dbf.newDocumentBuilder();
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		}
	}
	
	public XMLParser() {
	}
	
	//读取文件,输入流
	private static Document getDocument(InputStream is) {
		Document document = null;
		try {
			document =db.parse(is);
		} catch (SAXException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return document;
	}
	//读取文件,字符串
	public static Document  getDocument(String xmlPath) {
		InputStream is = XMLParser.class.getResourceAsStream(xmlPath);
		if(is == null) {
			 System.out.println("xmlPath["+xmlPath+"]不存在!");
			 return null;
		}
		return getDocument(is);
	}
	
	public abstract void dealElement(Element element,int index) ;
	
	/*
	 * @param document		解析的文件
	 * @param tagName 		需要解析的标签
	 */
	public void parseTag(Document document,String tagName) {
		NodeList nodeList = document.getElementsByTagName(tagName);
		for(int index = 0; index<nodeList.getLength(); index++) {
			Element ele = (Element) nodeList.item(index);
			//后面对ele的进一步解析:取属性、取textContent或者进一步取Element,都是使用工具人做的事
			//此处该使用抽象方法
			dealElement(ele, index);		
		}
	}
	
	/**
	 * @param element 需要解析的元素
	 * @param tagName 需要解析的标签
	 */
	public void parseTag(Element element,String tagName) {
		NodeList nodeList = element.getElementsByTagName(tagName);
		for(int index = 0; index<nodeList.getLength(); index++) {
			Element ele =(Element)nodeList.item(index);
			dealElement(ele, index);
		}
	}	
}

三、实例–使用工具

要使用工具,需要将之前代码转为jar包,并且导入需要使用该工具的项目中。在这里,我就不进行描述了,需要的直接百度即可。

<?xml version="1.0" encoding="UTF-8"?>
<students>
	<student id="00001" name="张小三" sex="" birtdhday="2002-10-3">
		<hobby>游泳</hobby>
		<hobby>跳绳</hobby>
		<hobby>打游戏</hobby>
		<hobby>跑步</hobby>
		<hobby>睡觉</hobby>
		<introduce>
			活泼开朗的小鲜肉!
		</introduce>
	</student>
	<student id="00002" name="朱子玉" sex="" birtdhday="2008-10-21">
		<hobbies>
			<hobby>游泳</hobby>
			<hobby>画画</hobby>
			<hobby>学习</hobby>
			<hobby>古筝</hobby>
		</hobbies>
		<introduce>
			小仙女一枚!
		</introduce>
	</student>
</students>

在上述xml文件中,student标签为文档节点,hobbies和introduce为元素节点(可能理解有误),如果不理解,可看这篇文章——《解析XML Node与Element的区别》

需要注意的是,由于我们是根据标签名解析,所以在解析过程中,只需要处理有内容的标签即可。比如我们可以不处理 “根标签students” ,因为我们需要解析的全部内容直接通过 "标签student"获取。

package com.mec.gewei.xml_parser.core;

import org.w3c.dom.Element;

import com.mec.util.XMLParser;

public class TestUtil{
	public static void main(String[] args) {
		//使用匿名内部类的方式调用工具
		//此处调用了文档节点解析的方法
		new XMLParser() {

			@Override
			public void dealElement(Element element, int index) {
				Student stu = new Student();
				
				String id = element.getAttribute("id");
				stu.setId(id);
				String name = element.getAttribute("name");
				stu.setName(name);
				String sex = element.getAttribute("sex");
				stu.setSex(sex);
				String birthday = element.getAttribute("birtdhday");
				stu.setBirthday(birthday);
				
				//此处调用元素节点解析
				new XMLParser() {
					@Override
					public void dealElement(Element element, int index) {
						String hobbystr = element.getTextContent();
						stu.addHobbies(hobbystr);
					}
				}.parseTag(element,"hobby");
				
				//此处调用元素节点解析
				new XMLParser() {
					@Override
					public void dealElement(Element element, int index) {
						String introduce = element.getTextContent().trim();
						stu.setIntroduce(introduce);
					}
				}.parseTag(element, "introduce");
				
				System.out.println(stu);
			}
			
		}.parseTag(XMLParser.getDocument("/student.att.xml"), "student");
	}
}

运行结果:
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值