SAX是解析XML文档是一种“基于事件的模型”。基于SAX的解析器在处理文档时,会生成名为“事件”的通知信息。软件程序可“侦听”这些事件,以便从文档获取数据。处理大型XML文档时,SAX的解析器通常比基于DOM的解析器更有效,尤其重要的是,基于SAX的解析器不会将整个XML文档载入内存。SAX只解析一次,是顺序解析的。所以SAX速度更快,而且更省内存。
将xml文件转成json格式的,建立二个类,Xml2JsonHandler 用来解析xml文件,SaxJSON用来存放json同时运行。
首先,说明一下SAX工作流程:
第一步建立sax解析工厂:SAXParserFactory spf = SAXParserFactory.newInstance();
第二步建立sax解析对象:SAXParser parser = spf.newSAXParser();
第三部指定解析xml文件,解析:parser.parse(new File("D://1.xml"), new XmlToJson());
当读到第一个xml的“<”符号就会调用public void startDocument() 函数,而且只调用一次,当读到节点时则调用public void startElement(String url, String localName, String qName, Attributes attributes ) 函数,其中localName,qName时节点名称,attributes 时节点属性名称和节点属性的值。attributes.getQName(i)获得节点属性名称 ,attributes.getValue(i)获得节点属性的值。public void characters(char[] ch, int offset, int length)去读节点值,注意是所有的节点。当读到结束节点时调用public void endElement(String url, String localName, String qName),文档解析结束调用public void endDocument()。
类Xml2JsonHandler:
package com.xml.sax;
import java.util.HashMap;
import java.util.Map;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class Xml2JsonHandler extends DefaultHandler{
private SaxJSON saxJson; //存放json的类
private String currentKey = ""; //当前xml的节点路线 如读到<book><y></y></book> <y> 为book.y
//解析完一个文档用来清空
public void clear(){
this.saxJson = null;
this.currentKey = "";
this.saxJson = new SaxJSON();
}
public Xml2JsonHandler(){
this.saxJson = new SaxJSON();
}
public Map getResult(){
return this.saxJson.getResult();
}
//解析文档开始
public void startDocument() {
this.saxJson.startDoc();
}
//当遇到开始节点时调用
public void startElement(String url, String localName, String qName,
Attributes attributes ) throws SAXException {
if (currentKey != null && !currentKey.equals("")) {
currentKey = currentKey + ".";
}
currentKey = currentKey + qName; //记录当前节点路径
for (int i = 0; i < attributes.getLength(); i++) {
if (attributes.getQName(i).equals("scheme")) { // 获取节点属性名称,
Map map = new HashMap();
map.put("@scheme", attributes.getValue(i)); //将节点属性名称前加@
this.saxJson.startEl(currentKey, map); // 调用saxJson的开始建json
}
}
}
public void characters(char[] ch, int offset, int length) {
// this.saxJson.characters("");
String value = new String(ch, offset, length); // 获取节点数据
value = value.replace("\n", ""); //为了去掉空格,制表符,换行等。
value = value.replace("\t", "");
value = value.replace(" ", "");
Map map = new HashMap();
map.put("#text", value);
if (length != 1 && !value.equals("")) {
this.saxJson.characters(currentKey, map); //调用saxJson的存放数据
}
}
public void endElement(String url, String localName, String qName) {
if (currentKey.lastIndexOf(".") != -1) {
currentKey = currentKey.substring(0, currentKey.lastIndexOf(qName)-1); // 去掉当前结束节点名称
}
this.saxJson.endEl();
}
// 文档结束时调用
public void endDocument() {
this.saxJson.endDoc();
Map map = this.saxJson.getResult();
System.out.println("----result----"+map);
this.clear();
}
}
类SaxJSON:
package com.xml.sax;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class SaxJSON {
private Map map; // 存放整个xml的json
// map中存放的当前json的父节点json 如 {"a":{"b":{"#text":"c"}} 当"c"sonMap为{"b":{}}
private Map sonMap;
private String str; //@全路径名
public SaxJSON() {
}
public void startDoc() {
this.map = new HashMap();
this.sonMap = new HashMap();
this.str = "";
}
public void endDoc() {
}
public void startEl(String currentKey, Map value) {
String[] arr = currentKey.split("\\."); // 用来处理节点属性的
this.setMap(arr, value);
str = currentKey;
}
public void endEl() {
}
public void characters(String currentKey, Map value) { // 处理节点的值
String[] arr = currentKey.split("\\.");
this.setMap(arr, value);
str = "";
}
public Map getResult() {
return map;
}
/**
*
* @param arr
* arr 是一个深度的值 所有key的集合, sonMap 记录上次存放map
* @param value
*/
private void setMap(String[] arr, Object value) {
if (str != null && !str.equals("")) { // 判断有没有节点属性
String[] s = str.split("\\.");
Map m = map;
for (int i = 0; i < s.length; i++) { // 获取当前路径下的子map
m = (Map) m.get(s[i]);
}
List list = new ArrayList(); // 将节点属性 和当前的值放在一个数组存放
list.add(value);
list.add(m);
value = list;
for (int i = s.length - 1; i >=0 ; i--) {
value = maps(s[i],value); //从底层向外出建map
}
map.putAll((Map)value); //将当前map放入大map中
return;
}
for (int i = 0; i < arr.length; i++) { // 没有节点属性名称
if (map.get(arr[i]) == null) {
for (int j = arr.length - 1; j > i; j--) {
value = maps(arr[j], value); //从底层向外出建map
}
if (i == 0) { // 当前map 在大map中没有重复key值
map.put(arr[i], value); //直接放入
} else {
Map sonMap = (Map) map.get(arr[i - 1]); // 用,获取最底层sonmap;
sonMap.putAll((Map) value); //将其放入
for (int j = i - 1; j >= 0; j--) {
sonMap = maps(arr[j], sonMap);
if (j == 0) {
map.putAll(sonMap);
}
}
}
return;
}
}
}
private Map maps(Object key, Object ma) {
Map m = new HashMap();
m.put(key, ma);
return m;
}
}
测试类:
package com.xml.sax;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.SAXException;
public class TestMain {
public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser parser = spf.newSAXParser();
parser.parse(new File("D://2.xml"),new Xml2JsonHandler());
}
}
xml 文件:
<?xml version="1.0" encoding="UTF-8"?>
<people>
<person>
<name scheme="213213">zhangsan</name>
<tel>5128</tel>
<email>txq512@sina.com</email>
</person>
</people>
结果为:
----result----{people={person={name=[{#text=zhangsan}, {@scheme=213213}]}, email={#text=txq512@sina.com}, tel={#text=5128}}}