dom和sax解析

一、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);
  }
 
 }
 
 

 
 

 

 

你可能感兴趣的:(dom和sax解析)