XML 一种通用的数据交换格式,平台无关性、语言无关性、系统无关性、给数据集成与交互带来了极大的便捷。
XML 在不同的语言环境,解析方式都是一样的,只是实现的语法不同。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <?xml version="1.0" encoding="UTF-8"> <bookstore> <book id="1"> <name>冰与火之歌</name> <author>乔治马丁</author> <year>2014</year> <price>89</price> </book> <book id="2"> <name>安徒生童话</name> <year>2014</year> <price>77</price> <language>English</language> </book> </bookstore>
|
DOM Document Object Model
参考java基础语法中最后一个知识点
SAX解析 Simple APIs for XML
XML 简单应用程序接口,SAX 童工的访问模式是一种顺序模式,这是一种快速读写 XML 数据的方法,当 SAX分析器 对 XML 文档进行分析时,会触发一系列事件,并激活响应的事件处理函数,应用程序通过这些事件处理函数实现对 XML 文档的访问,所以 SAX接口 也成为事件驱动接口。
优点:
- 不需要等待所有数据都被处理,分析就能立即开始
- 只在读取数据时检查数据,不需要保存在内存中
- 可以在某个条件得到满足时停止解析,不必解析整个文档
缺点:
- 需要应用程序自己负责 TAG 的处理逻辑(维护父子关系等),文档越复杂就越复杂
- 单向导航,无法定位文档层次,很难同时访问文档的不同部分的数据。不支持XPath。

xml 文件被 Sax解析器载入,由于 Sax解析器 是按照 xml 文件的顺序分析,
- 当读入
<?xml...>
时,调用 startDocument()
方法
- 读入
<bookstore>
的时候,由于它是 ElementNode
会调用 startElement(String uri, String localName, String qName, Attributes attributes)
方法,localName/qName 为节点的名称。attributes 是这个节点的属性。
- 找到
<bookstore>
,不需要它,接着往下找,从<book>
节点开始,读入时,调用方法,可以通过 attributes.getValue(0)
来得到。
- 接着往下找,图中标明[2]的地方,会调用
characters(char[] ch, int start, int length)
方法,不要以为是空白,Sax解析器会把它认为是一个 TextNode。
- 接着是
<name>
标签,会调用 startDocument() 此时需要记录下每个节点的标签名 TagName,然后再调用 characters() 方法遍历后面的 TestNode,当TagName 是我们需要的标签名时,将 characters() 中的数据读出即可。
注意:由于环境原因,调用startElement(String uri, String localName, String qName, Attributes attributes)
方法时第二个参数有可能为空,可以使用第三个参数,因此在解析前,先调用一下看哪个参数能用。
SAX 不需要将数据存储到内存中,只是在读取数据时检查数据。
以下是代码和打印:
xml 文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <?xml version="1.0" encoding="UTF-8"?> <bookstore> <book id="1"> <name>冰与火之歌</name> <author>乔治马丁</author> <year>2014</year> <price>89</price> </book> <book id="2"> <name>安徒生童话</name> <year>2014</year> <price>77</price> <language>English</language> </book> </bookstore>
|
Book 类
1 2 3 4 5 6 7 8
| public class Book { private String id; private String name; private String author; private String year; private String price; private String language; }
|
Sax 工具类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
|
@SuppressWarnings("all") public class Sax { private static Sax instance = new Sax(); private Sax() {}; public static Sax getInstance() { return instance; } public <T> List<T> parse(String url, Class<T> type) { SAXParserFactory sf = SAXParserFactory.newInstance(); SAXParser sp = null; try { sp = sf.newSAXParser(); AMHander<T> hd = new AMHander(type); sp.parse(url, hd); return hd.getList(); } catch (Exception e) { e.printStackTrace(); return null; } } }
|
接下来是最终要的 Sax实现解析 xml文档的 实现类 继承 DefaultHandler
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
| package cn.lizhaoloveit.day02._SAX;
import java.beans.BeanInfo; import java.beans.IntrospectionException; import java.beans.Introspector; import java.beans.PropertyDescriptor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set;
import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler;
public class AMHander<T> extends DefaultHandler { private List<T> list = new ArrayList<>(); private Map<String, Object> map; private final Set<String> keySet = new HashSet<String>(); private Class<T> type; private int Index; private String context; public List<T> getList() { return list; } public AMHander (Class<T> type) { this.type = type; try { BeanInfo info = Introspector.getBeanInfo(type, Object.class); PropertyDescriptor[] ps = info.getPropertyDescriptors(); for (PropertyDescriptor p : ps) { keySet.add(p.getName()); } } catch (IntrospectionException e) { e.printStackTrace(); } } @Override public void startDocument() throws SAXException { super.startDocument(); System.out.println("SAX 文档解析开始"); }
@Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { super.startElement(uri, localName, qName, attributes); if (type.getSimpleName().equalsIgnoreCase(qName)) { Index++; map = new HashMap<String, Object>(); System.out.println("=============开始遍历某一个对象============="); for (int i = 0; i < attributes.getLength(); i++) { if (keySet.contains(attributes.getQName(i))) { System.out.println("属性名" + attributes.getQName(i) + "属性值" + attributes.getValue(i)); map.put(attributes.getQName(i), attributes.getValue(i)); } } } else { System.out.println("字段名:" + qName); } }
@Override public void characters(char[] ch, int start, int length) throws SAXException { super.characters(ch, start, length); context = new String(ch, start, length); if (!context.trim().equals("")) { System.out.println("节点值是:" + context); } } @Override public void endElement(String uri, String localName, String qName) throws SAXException { super.endElement(uri, localName, qName); if (type.getSimpleName().equalsIgnoreCase(qName)) { try { BeanInfo info = Introspector.getBeanInfo(type, Object.class); PropertyDescriptor[] ps = info.getPropertyDescriptors(); T instance = type.newInstance(); for (PropertyDescriptor p : ps) { Object value = map.get(p.getName()); Method m = p.getWriteMethod(); m.invoke(instance, value); } list.add(instance); } catch (IntrospectionException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } System.out.println("=====================结束遍历一本书的内容=============="); } else if (keySet.contains(qName)) { map.put(qName, context); System.out.println("赋值字段" + qName + "成功"); } } @Override public void endDocument() throws SAXException { super.endDocument(); System.out.println("SAX 文档解析结束"); } }
|

JDOM解析
特点:仅适用具体类,不适用接口。API 大量使用 Conllections 类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
| public class JDOMTest { private static ArrayList<Book> booksList = new ArrayList<Book>();
public static void main(String[] args) { SAXBuilder saxBuilder = new SAXBuilder(); InputStream in; try { in = new FileInputStream("src/res/books.xml"); InputStreamReader isr = new InputStreamReader(in, "UTF-8"); Document document = saxBuilder.build(isr); Element rootElement = document.getRootElement(); List<Element> bookList = rootElement.getChildren(); for (Element book : bookList) { Book bookEntity = new Book(); System.out.println("======开始解析第" + (bookList.indexOf(book) + 1) + "书======"); List<Attribute> attrList = book.getAttributes(); for (Attribute attr : attrList) { String attrName = attr.getName(); String attrValue = attr.getValue(); System.out.println("属性名:" + attrName + "----属性值:" + attrValue); if (attrName.equals("id")) { bookEntity.setId(attrValue); } } List<Element> bookChilds = book.getChildren(); for (Element child : bookChilds) { System.out.println("节点名:" + child.getName() + "----节点值:" + child.getValue()); if (child.getName().equals("name")) { bookEntity.setName(child.getValue()); } else if (child.getName().equals("author")) { bookEntity.setAuthor(child.getValue()); } else if (child.getName().equals("year")) { bookEntity.setYear(child.getValue()); } else if (child.getName().equals("price")) { bookEntity.setPrice(child.getValue()); } else if (child.getName().equals("language")) { bookEntity.setLanguage(child.getValue()); } } System.out.println("======结束解析第" + (bookList.indexOf(book) + 1) + "书======"); booksList.add(bookEntity); bookEntity = null; System.out.println(booksList.size()); System.out.println(booksList.get(0).getId()); System.out.println(booksList.get(0).getName()); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (JDOMException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
|
DOM4J解析
特点:
- JDOM 的一种智能分支,合并了许多超出基本 XML 文档表示的功能。
- 适用接口和抽象基本类方法
- 具有性能优异、灵活性好、功能强大和极端易用的特点。
- 开源
- 支持 XPath
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| private ArrayList<Book> list = new ArrayList<Book>();
@Test public void testDOM4J() throws Exception { SAXReader reader = new SAXReader(); File file = new File("resources/books.xml"); try { Document document = reader.read(file); Element root = document.getRootElement(); Iterator it = root.elementIterator();
while (it.hasNext()) { System.out.println("===========开始遍历谋一本书============"); Element book = (Element) it.next(); List<Attribute> attrs = book.attributes(); for (Attribute attr : attrs) { System.out.println("属性名:" + attr.getName() + "--------属性值:" + attr.getValue()); } Iterator itt = book.elementIterator(); while (itt.hasNext()) { Element bookChild = (Element) itt.next(); System.out.println("节点名:" + bookChild.getName() + "-----节点值:" + bookChild.getStringValue()); } System.out.println("===============结束遍历一本书==============="); } } catch (Exception e) { e.printStackTrace(); } }
|
XML DTD 约束
由于 xml 的标签由用户自己定义, 因此在开发的时候,每个人都根据需求自定义 xml 标签,导致 xml 难以维护,需要规范机制约束 xml