xml解析小工具(java)
对于java来解析xml文件在许许多多的工具之中都有涉及,比如hibernate就需要用户通过xml来建立表和java对象之间的映射关系,这确实很常用。我们常常把键值对用properties来处理,而有层次结构的往往可以使用xml来进行记录。
下面看一下jdk自带的api是如何解析xml的吧:
这是Student.xml文件在src目录下
<hzy>
<student Sid="1" Isgood="yes">
<property name="hzy"></property>
<property age="15"></property>
<property tail="185"></property>
</student>
<student Sid="2" Isgood="no">
<property name="ya"></property>
<property age="16"></property>
<property tail="156"></property>
</student>
</hzy>
这是传统的xml解析
package test;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.io.InputStream;
public class XMLReader {
public static void main(String[] args) {
//获得xml文件的输入流
InputStream is = XMLReader.class.getResourceAsStream("/student.xml");
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder = null;
Document document = null;
//不变三连,document是xml的根节点抽象对象
try {
documentBuilder = documentBuilderFactory.newDocumentBuilder();
document = documentBuilder.parse(is);
//根据输入流把根节点找出来
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
NodeList student = document.getElementsByTagName("student");
//遍历根节点下的所有student子节点
for(int i=0;i<student.getLength();i++) {
Element element = (Element) student.item(i);
String Sid = element.getAttribute("Sid");
String Isgood = element.getAttribute("Isgood");
System.out.println(Sid);
System.out.println(Isgood);
NodeList properties = element.getElementsByTagName("property");
//遍历student节点下的所有property节点
for(int j=0;j<properties.getLength();j++){
Element pelement = (Element) properties.item(j);
String name = pelement.getAttribute("name");
String age = pelement.getAttribute("age");
String tail = pelement.getAttribute("tail");
System.out.println(name+" "+age+" "+tail);
}
}
}
}
我们发现代码的重复性太高了,这还只是一个两层的xml,如果层次很多的话,是要遍历很多次的,就是会有许许多多的循环,这非常容易出错,令我们逻辑产生混乱。
java自然是要把硬性的,重复的代码打成工具,让以后更加简单的使用。
如何做,如下:
1.我们发现documentBuilder是不变的,所以用单例模式写一个就行啦!
2.每次循环是一样,但循环里头的是要在具体应用时才能确定的,这个时候给个抽象方法,让用户自己去实现才显得合理,当然也可以用接口。
3.xml文件名不一样,所以提供方法加载xml得到根节点就好啦!
package test;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.io.InputStream;
public abstract class XMLReader {
private static DocumentBuilder documentBuilder;
//给documentBuilder单例一下
private static void init(){
if(documentBuilder==null) {
try {
documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
} catch (ParserConfigurationException e) {
System.out.println("documentBuilder出错");
e.printStackTrace();
}
}
}
//不管怎么抽取,总是要给一个获取Document的方法
protected static Document getDocument(String xmlpath) {
init();
InputStream is = XMLReader.class.getResourceAsStream(xmlpath);
return getDocument(is);
}
//上边的重载,符合更多人的习惯
protected static Document getDocument(InputStream is) {
init();
try {
return documentBuilder.parse(is);
} catch (SAXException e) {
System.out.println("xml文件打开出错,检查路径:");
e.printStackTrace();
} catch (IOException e) {
System.out.println("xml文件打开出错,检查路径:");
e.printStackTrace();
}
return null;
}
//抽象方法,具体的实现交给用户吧
protected abstract void dealReaderProperty(Element element,int item);
//循环读取子节点并且调用抽象方法
protected XMLReader XMLReader(Document document,String tagName) {
NodeList student = document.getElementsByTagName(tagName);
for (int i = 0; i < student.getLength(); i++) {
Element element = (Element) student.item(i);
dealReaderProperty(element,i);
}
return this;
}
//和上面的一样根节点变成标记节点而已
protected XMLReader XMLReader(Element element,String tagName) {
NodeList student = element.getElementsByTagName(tagName);
for (int i = 0; i < student.getLength(); i++) {
Element element1 = (Element) student.item(i);
dealReaderProperty(element1,i);
}
return this;
}
}
下面来一个测试!
package test;
import org.w3c.dom.Element;
import javax.sql.rowset.WebRowSet;
import javax.sql.rowset.spi.XmlReader;
import java.io.InputStream;
import java.io.Reader;
import java.sql.SQLException;
public class Test {
public static void main(String[] args) {
InputStream is = Test.class.getResourceAsStream("/student.xml");
new XMLReader() {
@Override
protected void dealReaderProperty(Element element, int item) {
String Sid = element.getAttribute("Sid");
String Isgood = element.getAttribute("Isgood");
System.out.println(Sid+" "+Isgood);
new XMLReader() {
@Override
protected void dealReaderProperty(Element element, int item) {
String name = element.getAttribute("name");
String age = element.getAttribute("age");
String tail= element.getAttribute("tail");
System.out.println(name+" "+age+" "+tail);
}
}.XMLReader(element,"property");
}
}.XMLReader(XMLReader.getDocument(is),"student");
}
}
这里小编说一下你自己写的抽象方法dealReaderProperty为啥被调用了,首先创建了匿名对象,调用了XMLReader方法,看我们的工具类,在XMLReader方法里头调用了dealReaderProperty方法。事实上就是一个实现了抽象类的新对象调用了XMLReader而已,然后就循环输出啦!,
这是输出情况
1 yes
hzy
15
185
2 no
ya
16
没有问题呀!这一下子省了好多好多代码,我们只要给个Document根节点,自己写dealReaderProperty(Element element, int item)方法就可以完成读取啦。