一、了解XML
- XML 指可扩展标记语言(EXtensible Markup Language)
- XML 是一种标记语言,很类似 HTML
- XML 的设计宗旨是传输数据,而非显示数据
- XML 标签没有被预定义。您需要自行定义标签。
- XML 被设计为具有自我描述性
XML 与 HTML 的主要差异
- XML 被设计为传输和存储数据,其焦点是数据的内容。
- HTML 被设计用来显示数据,其焦点是数据的外观。
- HTML 旨在显示信息,而 XML 旨在传输信息。
二、常用的解析XML的技术
-
A:DOM(Document Object Model):
在内存中构建一颗倒挂的树,通过对内存中的节点进行操作从而解析XML缺点:由于需要根据XML文档构造倒挂的树,所以当XML文档比较大时,非常耗内存。有造成内存溢出的危险。不适合移动设备的开发.
-
B:SAX(Simple API For Xml):
基于事件驱动的方式解析XML(推模式PUSH)
-
C:JDOM:
对DOM模型的简化,专门针对Java语言解析XML而设计的
-
D:DOM4J:
融入了XPath语法等,是目前解析XML功能最强大的一门技术 -
E:PULL:
基于事件驱动的方式解析XML.(拉模式(PULL))
三、使用DOM技术解析Xml
DOM技术是JDK自带的技术,使用时不需要导入第三方jar包
1.实例化DOM解析器工厂对象
DocumentBuilderFactory documentBuilderFactory=DocumentBuilderFactory.newInstance();
2.根据DOM解析器工厂对象得到DOM解析器对象
DocumentBuilder documentBuilder= documentBuilderFactory.newDocumentBuilder();
3.指定要解析的Xml文件在哪里并发放文档对象
Document document= documentBuilder.parse(inputStream);
4.根据文档对象得到根节点对象
Element root= document.getDocumentElement();
5.根据标签名获取指定节点的集合存储到NodeList对象中
NodeList book_nodeList= root.getElementsByTagName("标签名");
int len=book_nodeList.getLength();//获取集合中节点的个数
for(int i=0;i<len;i++){
Node book_node=book_nodeList.item(i);
//为了使用Element特有的方法:String getAttribute(String name)根据属性名获取属性值的功能
Element book_element=(Element) book_node;
String isbn=book_element.getAttribute("isbn");
//getTextContent():获取当前节点的文本内容
String name=book_element.getElementsByTagName("name").item(0).getTextContent();
String author=book_element.getElementsByTagName("author").item(0).getTextContent();
String price=book_element.getElementsByTagName("price").item(0).getTextContent();
String publish=book_element.getElementsByTagName("publish").item(0).getTextContent();
Book book=new Book(isbn,name,author,Double.parseDouble(price),publish);
books.add(book);
}
xml文件:
<?xml version="1.0" encoding="UTF-8"?>
<books>
<book isbn="001">
<name>Java</name>
<author>孙鑫</author>
<price>56.7</price>
<publish>人民出版社</publish>
</book>
<book isbn="002">
<name>Android</name>
<author>安迪鲁宾</author>
<price>76.7</price>
<publish>邮电出版社</publish>
</book>
<book isbn="003">
<name>iOS</name>
<author>乔布斯</author>
<price>56.7</price>
<publish>清华出版社</publish>
</book>
</books>
将给定的Xml文件做相关修改后生成新的Xml文件
public class DOMGenerateXmlDemo02 {
public static void main(String[] args) {
DocumentBuilderFactory documentBuilderFactory=DocumentBuilderFactory.newInstance();
1.实例化转换工厂对象
TransformerFactory transformerFactory=TransformerFactory.newInstance();
DocumentBuilder documentBuilder=documentBuilderFactory.newDocumentBuilder();
InputStream inputStream=Thread.currentThread().getContextClassLoader().getResourceAsStream("books.xml");
Document doc=documentBuilder.parse(inputStream);
Element element_root=doc.getDocumentElement();
2.通过转化工厂对象得到转换器对象
Transformer transformer= transformerFactory.newTransformer();
3.设置输出属性,文档进行缩进
transformer.setOutputProperty("indent","yes");
4.实例化DOMSource对象
DOMSource domSource=new DOMSource();
domSource.setNode(doc);
Element element_book=doc.createElement("book");
element_book.setAttribute("isbn","400");
Element element_name=doc.createElement("name");
element_name.setTextContent("小丽");
element_book.appendChild(element_name);
element_root.appendChild(element_book);
//实例化流结果对象
StreamResult streamResult=new StreamResult();
//指定流结果对象关联的输出流对象
streamResult.setOutputStream(new FileOutputStream("hsj.xml"));
//将内存中的树结构生成指定的文件
transformer.transform(domSource, streamResult);
}
}
根据数据源中的数据生产Xml文档
public class DOMGenerateXmlDemo03 {
public static void main(String[] args) {
List<Book> books=new ArrayList<Book>();
books.add(new Book("100", "Java", "孙鑫", 45.6, "人民出版社"));
books.add(new Book("200", "Android", "安迪鲁宾", 55.6, "邮电出版社"));
books.add(new Book("300", "iOS", "乔布斯", 65.6, "清华出版社"));
//1.得到DOM解析器工厂对象
DocumentBuilderFactory documentBuilderFactory=DocumentBuilderFactory.newInstance();
//2.得到DOM解析器对象
DocumentBuilder documentBuilder=documentBuilderFactory.newDocumentBuilder();
//3.使用解析器对象得到文档对象
Document document=documentBuilder.newDocument();
//4.根据文档对象创建元素对象
Element element_root=document.createElement("books");
//5.将根节点对象挂载到文档对象上
document.appendChild(element_root);
//构建Xml文件
for(Book book:books){
//创建子节点book
Element element_book=document.createElement("book");
element_book.setAttribute("isbn", book.getIsbn());
//将book节点挂载到books节点上
element_root.appendChild(element_book);
//创建子节点name
Element element_name=document.createElement("name");
element_name.setTextContent(book.getName());
//将name节点挂载到book节点上
element_book.appendChild(element_name);
//创建子节点author
Element element_author=document.createElement("author");
element_author.setTextContent(book.getAuthor());
//将author节点挂载到book节点上
element_book.appendChild(element_author);
//创建子节点price
Element element_price=document.createElement("price");
element_price.setTextContent(String.valueOf(book.getPrice()));
//将price节点挂载到book节点上
element_book.appendChild(element_price);
//创建子节点publish
Element element_publish=document.createElement("publish");
element_publish.setTextContent(book.getPublish());
//将publish节点挂载到book节点上
element_book.appendChild(element_publish);
}
//将内存中构建的倒挂的树生成本地的Xml文件
//1.得到转换器工厂对象
TransformerFactory transformerFactory=TransformerFactory.newInstance();
//2.根据转换器工厂对象得到转换器对象
Transformer transformer=transformerFactory.newTransformer();
//3.设置输出属性,文档进行缩进
transformer.setOutputProperty("indent","yes");
//4.准备DOMSouce对象
DOMSource domSource=new DOMSource(document);
//5.准备Result对象
/*StringWriter stringWriter=new StringWriter();
StreamResult streamResult=new StreamResult(stringWriter);*/
File destFile=new File("hsj.xml");
StreamResult streamResult=new StreamResult(destFile);
//6.执行转换操作生成xml字符串
transformer.transform(domSource, streamResult);
//System.out.println(stringWriter);
System.out.println("Xml文件生成成功!");
}
}
四、SAX解析
1.得到SAX解析器工厂对象
SAXParserFactory saxParserFactory=SAXParserFactory.newInstance();
2.通过SAX解析器工厂对象得到SAX解析器对象
SAXParser saxParser= saxParserFactory.newSAXParser();
3.通过解析器对象得到Xml的阅读器对象
XMLReader xmlReader= saxParser.getXMLReader();
4.通过Xml的阅读器对象开启命名空间特性功能
xmlReader.setFeature("http://xml.org/sax/features/namespaces", true);
5.指定要解析的Xml文件在哪里并且指定解析器(解析给定的Xml)对象
InputStream inputStream=Thread.currentThread().getContextClassLoader().getResourceAsStream("books.xml");
saxParser.parse(inputStream, new MyHandler());
5.在解析器中解析Xml即可
自定义SAX处理器是可以继承DefaultHandler类或者实现ContentHandler接口
要想解析Xml文件一般都会重写如下方法:
- startDocument():在开始解析Xml文档前自动调用的方法,做初始化工作,只调用一次
- startElement():遇到Xml的开始标签时自动调用的方法,看遇到多少个开始标签就调用多少次
- characters():遇到文本元素(汉字,空白(空格,tab,回车等))时自动调用的方法,看xml文档中有多少文本元素
- endElement():遇到Xml的结束标签时自动调用的方法,看遇到多少个结束标签就调用多少次
- endDocument():在解析完毕Xml文档后自动调用的方法,做资源释放工作,只调用一次
private final static class MyHandler extends DefaultHandler{
声明存放Book对象的集合
private List<Book> books;
声明书对象,用来存储解析出来的数据
private Book book;
记录当前解析对象的父节点对象
private String parent;
收到开始解析Xml文档的通知时自动调用的方法,只调用一次
@Override
public void startDocument() throws SAXException {
this.books=new ArrayList<Book>();
}
/**
* 收到遇到开始标签的通知时自动调用的方法
*/
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
//记录当前节点的标签名
this.parent=qName;
if("book".equals(qName)){
//根据属性名得到属性值
String isbn=attributes.getValue("isbn");
book=new Book();
book.setIsbn(isbn);
}
}
/**
* 收到遇到元素字符数据时自动调用的方法
*/
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
String data=new String(ch,start,length);
if("name".equals(this.parent)){
this.book.setName(data);
}else if("author".equals(this.parent)){
this.book.setAuthor(data);
}else if("price".equals(this.parent)){
this.book.setPrice(Double.parseDouble(data));
}else if("publish".equals(this.parent)){
this.book.setPublish(data);
}
}
/**
* 收到遇到元素结束标签时自动调用的方法
*/
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
//遇到结束标签将之前的开始标签内容置空
this.parent=null;
if("book".equals(qName)){
this.books.add(book);
}
}
/**
* 收到文档结束完毕的通知后自动调用的方法,只调用一次.
*/
@Override
public void endDocument() throws SAXException {
System.out.println("books="+books);
}
}
五、Pull解析
1.得到Pull解析器工厂对象
XmlPullParserFactory xmlPullParserFactory=XmlPullParserFactory.newInstance();
2.过Pull解析器工厂对象得到Pull解析器对象
XmlPullParser xmlPullParser= xmlPullParserFactory.newPullParser();
3.指定要解析的Xml文件在哪里同时指定编码表
InputStream inputStream=Thread.currentThread().getContextClassLoader().getResourceAsStream("books.xml");
xmlPullParser.setInput(inputStream, "utf-8");
4.得到事件对象值
int eventType=xmlPullParser.getEventType();
5.只要没有解析到Xml的结尾则继续继续
while(eventType!=XmlPullParser.END_DOCUMENT){
switch (eventType) {
//XmlPullParser.START_DOCUMENT=0
case XmlPullParser.START_DOCUMENT://开始解析Xml文档时返回的事件值
break;
//XmlPullParser.START_TAG=2
case XmlPullParser.START_TAG://遇到开始标签时返回的事件值
String startTag=xmlPullParser.getName();//得到当前解析节点的标签名
break;
//XmlPullParser.TEXT=4
case XmlPullParser.TEXT://遇到字符数据时返回的事件值
String text=xmlPullParser.getText();//得到当前的文本内容
break;
//XmlPullParser.END_TAG=3
case XmlPullParser.END_TAG://遇到结束标签时返回的事件值
String endTag=xmlPullParser.getName();//得到当前解析节点的标签名
break;
}
String startTag=xmlPullParser.getName();//得到当前解析节点的标签名
String isbn=xmlPullParser.getAttributeValue(null, "isbn");//根据属性名获取属性值
String publish=xmlPullParser.nextText();//得到当前节点的文本内容
//将事件流继续向下推动
eventType=xmlPullParser.next();
}