一、XML的解析方式基本上分为三类:
第一类是基于XML文档树结构的解析,例如DOM(Document Object Model);
第二类是基于流式的解析,例如SAX(Simple API for XML)、StAX(Stream API for XML)和XPP(XML Pull Parser);
第三类是基于非提取式的解析,例如VTD-XML(Virtual Token Description for XML)。
二、jaxp和dom和sax的关系(JAXP支持DOM、SAX、XSLT等标准。)
1、sax、dom是两种对xml文档进行分析的方法(没有具体的实现,只有接口)
所以不是解释器,如果光有他们,你是完成不了对xml文档的处理的。
sax的包是org.xml.sax
dom的包是org.w3c.dom
包的名称很重要,它有助于你理解他们之间的关系。
2、jaxp是api,他封装了sax\dom两种接口。并在sax\dom的基础之上,作了一套比较简单的api以供开发
人员使用。
jaxp的包是javax.xml.parsers
可以看看jaxp的源文件,它的文件中包含了对sax或者dom的引用(import)
jaxp也不是具体的实现,他只是一套api。如果你仅仅有jaxp那是无法工作的
(其实jaxp只是完成对sax、dom的包装,生成了DocumentBuilderFactory\DocumentBuilder
和SAXParserFactory SAXParser。也就是设计模式中的工厂模式,他的好处就是具体的对象( 解释器)
三、dom解析
dom解析是将整个XML文档当做一个树形结构来进行处理,标签、属性、文本、文档都看着节点,可以随意的访问和修改、删除节点。
注意:下面的代码,遍历所有标签和他的属性
package com.lmj;
import java.util.ArrayList;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public class TestDom {
/**
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
ArrayList<Student> td = (new TestDom()).parseXML("d:/myxml.xml");
Student student = new Student();
for(int i =0;i<td.size();i++){
student=td.get(i);
System.out.println(student.name+" "+student.num+" "+student.sex);
}
}
public static ArrayList<Student> parseXML(String path) throws Exception{
//产生一个队列,用来装解析到的学生对象
ArrayList<Student> alstu = new ArrayList<Student>();
//解析器工厂
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
//解析器对象
DocumentBuilder builder = factory.newDocumentBuilder();
//解析xml文件
Document document = builder.parse(path);
//得到所有stu节点
NodeList nl = document.getElementsByTagName("stu");
//遍历stu
for(int i=0;i<nl.getLength();i++){
//创建一个学生对象
Student student = new Student();
//得到每一个stu节点
Node n = nl.item(i);
//遍历该stu节点的属性
NamedNodeMap nnm = n.getAttributes();
//遍历属性
for(int j=0;j<nnm.getLength();j++){
//得到每一个属性,将node转成attr
Attr at=(Attr) nnm.item(j);
//得到属性的名字,和值
String aname = at.getName();
String avalue = at.getValue();
if(aname.equals("num")){
student.num=Integer.parseInt(avalue);
}
}
//遍历stu的所有子节点
NodeList nlist= n.getChildNodes();
for(int k=0;k<nlist.getLength();k++){
//得到所有元素节点
Node ni = nlist.item(k);
if(ni instanceof Element){
String sname = ni.getNodeName();
//得到该节点下的文本值
String svalve = ni.getTextContent();
if(sname.equals("name")){
student.name=svalve;
}else if(sname.equals("sex")){
student.sex=svalve;
}
}
}
2、xml的反向解析
package com.lmj;
import java.io.File;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public class Fanjiexi {
/**
* 将Dom对象,动态修改,然后反向解析为XML 文件
* @throws Exception
*/
public static void main(String[] args) throws Exception {
//**先将Dom 对象修改********************************
File f = new File("d:/myxml.xml");
//解析器工厂
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
//解析器对象
DocumentBuilder builder = factory.newDocumentBuilder();
//解析xml文件 得到dom对象
Document document = builder.parse(f);
//在跟节点下添加一个子节点,先得到跟节点 getfisrtchild不一定是跟节点
//得到跟节点getfisrtchild不一定是跟节点
NodeList nlist = document.getElementsByTagName("student");
//根元素只有一个,所以就是队列第一个元素
Node nfist = nlist.item(0);
//解析器对象创建一个元素添加到根节点
Element el= document.createElement("stu");
System.out.println(el.getNodeName());
//新节点添加到根节点下
nfist.appendChild(el);
//给新节点,添加属性
el.setAttribute("num", "121212");
//在新的子节点下,添加节点
//创建name节点
Element ename = document.createElement("name");
//设置name节点的文本属性值
ename.setTextContent("老大爷");
el.appendChild(ename);
//创建sex节点
Element esex = document.createElement("sex");
//设置sex节点的文本属性值
esex.setTextContent("男");
el.appendChild(esex);
//**************************************************
//将Dom反向解析为xml文件
//转换工厂
TransformerFactory tff = TransformerFactory.newInstance();
//转换对象
Transformer former = tff.newTransformer();
//将源转到结果,源可以是对象,结果可以是xml文件
//Source对象,这里是domSource,,将dom对象转成xml,所以源头是dom
//这里需要传入dom的节点,如果是根节点,这源头就是这个树,如果不是根节点,那么就是树枝(子树)
DOMSource domsource = new DOMSource(nfist);
//结果,结果是转成xml,
//StreamResult 充当转换结果的持有者,可以为 XML、纯文本、HTML 或某些其他格式的标记。
File file = new File("D:/myxml2.xml");
StreamResult sr = new StreamResult(file);
former.transform(domsource, sr);
System.out.println("反向解析完成》》》》》");
}
}
alstu.add(student);
}
return alstu;
}
}
********************************************************************************************************
sax解析
注意:1、sax解析是事件驱动,开始解析元素开始和元素结束,文档开始和结束等都会触发相映的方法,
2、得到元素文本的原理:
解析到文本触发的方法public void characters(char[] ch, int start, int length)
所以所有的文本都会读到ch这个字符数组里面
当一个元素结束的时候,就刚刚读取了元素前面的文本,这个时候ch里面的start位置到length位置的字符就是元素的文本字符,这个时候就以利用new String(ch,start,length);将字符数组转成字符串来得到
3、得到标签的属性值
当一个标签开始的时候,我们可以得到他的标签名称,和该标签所有的属性数组,可以根据标签名字和属性名字来给获取相对应的数据
package com.lmj;
import java.util.ArrayList;
import org.xml.sax.Attributes;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class MyDefaultHandler extends DefaultHandler {
/*
* 当读到一个元素结束的时候,该元素的文本已经被读取,所以这个时候文本数组里面刚读进去的就是元素的文本
*/
//学生队列,用于存放遍历的学生对象
ArrayList<Student> slist = new ArrayList<Student>();
String svalue;
private Student student;
//文档开始时候调用
@Override
public void startDocument() throws SAXException {
}
//元素开始时候调用
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
//开始读取stu标签的时候,表示开始读取一个学生对象,这个时候开始创建一个学生对象
if("stu".equals(qName)){
student = new Student();
//属性赋值
for(int i=0;i<attributes.getLength();i++){
student.num=Integer.parseInt(attributes.getValue(i));
}
}
}
//元素结束时候调用
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
if("name".equals(qName)){
student.name=svalue;
}
if("sex".endsWith(qName)){
student.sex=svalue;
}
if("stu".equals(qName)){
//向队列添加
slist.add(student);
}
}
//遇到文本就会调用,所有的文本都会读到这里
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
svalue=new String(ch,start,length);
}
//文档结束时候调用
@Override
public void endDocument() throws SAXException {
//遍历队列输出
for(Student s : slist){
System.out.println(s);
}
}