解析XML
什么是XML
可扩展标记语言,标准通用标记语言的子集,是一种用于标记电子文件使其具有结构性的标记语言。
在电子计算机中,标记指计算机所能理解的信息符号,通过此种标记,计算机之间可以处理包含各种的信息比如文章等。它可以用来标记数据、定义数据类型,是一种允许用户对自己的标记语言进行定义的源语言。 它非常适合万维网传输,提供统一的方法来描述和交换独立于应用程序或供应商的结构化数据。是Internet环境中跨平台的、依赖于内容的技术,也是当今处理分布式结构信息的有效工具。早在1998年,W3C就发布了XML1.0规范,使用它来简化Internet的文档信息传输。
XML成为可扩展标记语言,它的文件格式必须是以.xml作为结尾。在程序中通常使用XML来存储数据、配置信息、传输数据。 (如:web.xml)
上图说明两个不同语言编写的程序,如果要传递数据xml将是一个不错的选择
XML的语法和约束
XML文档(文件)的树形结构
Xml标签任何限制(在没有加入约束之前),及标签没有任何限制。Xml中得信息是通过标签嵌套来完成的
每日一菜
张三
30.5
2015
Learing XML
Jack
55.0
2016
再如:
<shop
>
<goods>
<name>可口可乐</name>
<price>2.5</price>
<type>饮料</type>
</goods>
<goods>
<name>九三豆油</name>
<price>50</price>
<type>粮油</type>
</goods>
</shop>
XML文档的语法
文档声明:
文档声明通常声明文档版本和编码格式
<?xml version="1.0" encoding="UTF-8"?>
<菜单>
<菜>
<菜名>锅包肉</菜名>
<菜价 单位="人民币">28</菜价>
</菜>
<菜>
<菜名>西冷牛排</菜名>
<菜价 单位="欧元">16</菜价>
</菜>
</菜单>
**通过属性单位,说
明 菜价的计价单位**
注意:属性的值必须用引号引起来
Xml中的注释:
CDATA区:
如果我现在要在一个元素中设置内容为 “ AAA”如果直接写在元素内容 就会被解析为注释不被显示如下:
<?xml version="1.0" encoding="UTF-8"?>
<a>
<b><!-注释内容-->AA</b>
</a>
由
于浏览器会将 解析成注释符号,而注释符号不能再元素标签之间出现。所以解析会出错
如果要声明
<?xml version="1.0" encoding="UTF-8"?>
<a>
<b><![CDATA[<!-注释内容-->AA]]></b>
</a>
如果
使用
<?xml version="1.0" encoding="UTF-8"?>
<!--元素-->
<!ELEMENT books (book+)>
<!ELEMENT book (name,price)>
<!ELEMENT name (#PCDATA)>
<!ELEMENT price (#PCDATA)>
<!--属性:给 book加上id属性(类型:ID 约束:必填)
wz(文字)属性(类型:枚举 约束:默认值为"CN")
cs(册数)属性(类型:文本 约束:默认值为"1")
pid(所属图书id)属性(类型:父ID 约束:可以忽略(#IMPLIED))
-->
<!ATTLIST book
id ID #REQUIRED
wz (EN|CN|JP|TW) "CN"
cs CDATA "1"
pid IDREF #IMPLIED
>
book5.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE books SYSTEM "book5.dtd">
<books>
<book id="b01" wz="CN" cs="4" ><!-- id值不能以数字开头,wz如果不被写默认值就是EN -->
<name>四大名著合集</name>
<price>120</price>
</book>
<book id="b02" wz="CN" cs="1" pid="b01" ><!-- pid必须指明父元素ID -->
<name>西游记</name>
<price>30</price>
</book>
</books>
在DTD文件中定义实体(了解即可):
实体就是在D
TD定义的变量,可以在XML和DTD文件实现对变量内容的快速引用
这就是将 part.xml中你的内容直接在XML中使用 如 &bookName; 通常使用的元素的内容类型设置为ANY(即放啥都行,因为引入的XML中可能是文本也可能是XML标签)
XML的解析方式
XML解析方式分为两种:dom和sax
dom:(Document Object Model, 即文档对象模型) 是 W3C 组织推荐的解析XML 的一种方式。
sax: (Simple API for XML) 不是官方标准,但它是 XML 社区事实上的标准,几乎所有的 XML 解析器都支持它。
XML解析开发包
Jaxp(sun)、Jdom、dom4j、pull(android的sdk自带)
DOM和SAX解析XML的区别
利用JDK自动的类和接口解析XML(CRUD)
如果使用JDK自带的类来解析XML,那么这所有的类都是JDK自身实现的。用到的DOM对应的接口都是由W3C组成来定义的。
之前设计好POJO用于保存Book信息,编写的类如下:
public class Book {
private String id;
private String name;
private String price;
private String author;
/**
* @return the id
*/
public String getId() {
return id;
}
/**
* @param id the id to set
*/
public void setId(String id) {
this.id = id;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the price
*/
public String getPrice() {
return price;
}
/**
* @param price the price to set
*/
public void setPrice(String price) {
this.price = price;
}
/**
* @return the author
*/
public String getAuthor() {
return author;
}
/**
* @param author the author to set
*/
public void setAuthor(String author) {
this.author = author;
}
/**
* @param id
* @param name
* @param price
* @param author
*/
public Book(String id, String name, String price, String author) {
super();
this.id = id;
this.name = name;
this.price = price;
this.author = author;
}
public Book()
{
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "Book [id=" + id + ", name=" + name + ", price=" + price + ", author=" + author + "]";
}
}
读取XML和生成XML
根据制定的XML文件生成对应Document对象
/**
* 将xmlFilePath对应的XML文件转为对应的Document
- @param xmlFilePath:xml文件的位置
- @return xml对应的Document对象
- @throws Exception
*/
private Document readXML(String xmlFilePath) throws Exception
{
//得到XML解析器(Document生成器)工厂
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
//得到XML解析器
DocumentBuilder builder = factory.newDocumentBuilder();
//利用XML解析器 根据指定的XML文件生成对应的Document对象
Document document = builder.parse(xmlFilePath);
//返回document对象
return document;
}
根据指定的Document对象生成对应的XML文件
/**
* 根据Document中的信息,生成对应的XML
* @param srcDocument:数据源Document
* @param targetXmlFilePath:目标XML所在的路径
* @throws Exception
*/
private void createXML(Document srcDocument,String targetXmlFilePath) throws Exception
{
//1、得到转换器工厂
TransformerFactory factory = TransformerFactory.newInstance();
//2、得到转换器
Transformer transFormer = factory.newTransformer();
//3、根据指定的Document生成对应的XML文件
//根据document生成对应的Source
Source xmlSource = new DOMSource(srcDocument);
//根据targetXmlFilePath生成对应的Result
Result outputTarget =new StreamResult(targetXmlFilePath);
//根据制定的Document生成对应的XML
transFormer.transform(xmlSource, outputTarget);
}
读操作(READ)
基本思路:
1、将指定的XML文件转为对应的Document对象。
2、在Document对象中查找对应的节点得到相应的属性和节点的文本内容。
3、放入对应的Java对象并返回
/**
* 查询xml中的所有book信息,将每个book信息放入Book对象中
* 并将所有的Book对象放入List<Book>对象中返回
* @return
*/
public List<Book> queryBook()
{
//声明List<Book>对象,用于装xml中的全部book信息
List<Book> bookList = new ArrayList<Book>();
try {
//1、得到XML对应的Document对象
Document document = readXML("xml/bookstore.xml");
//2、在Document中找到所有book信息
//读取到所有标签名为book的节点
NodeList bookNodeList = document.getElementsByTagName("book");
//遍历bookNodeList中的每个节点
for(int i=0;i<bookNodeList.getLength();i++)
{
//声明变量保存该书的 id,name,price,author
String id="";
String name="";
String price="";
String author="";
//得到对应节点
Node bookNode = bookNodeList.item(i);
//将bookNode转为对应的Element对象
Element bookElement = (Element)bookNode;
//得到元素的id属性
id = bookElement.getAttribute("id");
//得到bookElement下的子节点(注意如果xml存在换行,那么一段空白文本也是一个节点)
NodeList childNodeList = bookElement.getChildNodes();
//遍历childNodeList中的每个节点,找到指定的节点
for(int j=0;j<childNodeList.getLength();j++)
{
Node childNode = childNodeList.item(j);
//根据节点名判断是否为对应的节点
if("name".equals(childNode.getNodeName()))
{
name = childNode.getTextContent();
}
if("price".equals(childNode.getNodeName()))
{
price = childNode.getTextContent();
}
if("author".equals(childNode.getNodeName()))
{
author = childNode.getTextContent();
}
}
//将读取到的信息放入对应的Book对象中
Book book = new Book(id,name,price,author);
//将放好值的book放入List对象
bookList.add(book);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//返回所有的Book信息
return bookList;
}
生成操作(Create)
基本思路如下:
1、将源XML中的信息生成对应Document
2、在Docume
nt中创建信息的元素,设置内容和属性
3、将新创建元素,找到相应的父节点(放入Dom树中)
4、根据插入完数据的Document生成对应的XML文件
/**
* 将book中的信息在对应的XML文件中生成信息
* @param book
*/
public void insertBook(Book book)
{
try {
//1、根据xml文件得到对应的Document对象
Document document = readXML("xml/bookstore.xml");
//2、生成相应元素
//生成book元素
Element bookElement = document.createElement("book");
//放入id属性
bookElement.setAttribute("id", book.getId());
//生成name属性
Element nameElement = document.createElement("name");
//给元素中设置文字(标签之间的文字)
nameElement.setTextContent(book.getName());
//设置price元素
Element priceElement = document.createElement("price");
//给price元素中设置文本
priceElement.setTextContent(book.getPrice());
//设置author元素
Element authorElement = document.createElement("author");
authorElement.setTextContent(book.getAuthor());
//3、将新元素放入父节点下(document中的节点添加只能父生子)
//将name,price,author元素放入book元素下
bookElement.appendChild(nameElement);
bookElement.appendChild(priceElement);
bookElement.appendChild(authorElement);
//bookElement放在根元素下
//得到根节点
Element rootElement = document.getDocumentElement();
//将bookElement放入根节点下
rootElement.appendChild(bookElement);
//4、根据Document(插入新节点之后的)对象生成对应的xml文件
createXML(document, "xml/bookstore.xml");//将xml文件重新生成
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
删除操作(Delete)
思路:
1、将要操作的xml转为对应的document
对象
2、在document中找到对应的元素
3、从该元素的父节点中将当前节点删除
4、根据删除该节点之后的document重新生成XML文件
/**
* 根据bookid将对应的book元素删除
* @param id
*/
public void deleteBook(String id)
{
try {
//1、得到xml对应的document对象
Document document = readXML("xml/bookstore.xml");
//2、在document中找到对应的book元素
NodeList bookNodeList = document.getElementsByTagName("book");
Element deleteBookElement = null;//声明一个Element对象用于保存要删除的book元素
for(int i=0;i<bookNodeList.getLength();i++)
{
Node bookNode = bookNodeList.item(i);
Element bookElement = (Element)bookNode;
if(id.equals(bookElement.getAttribute("id")))
{
//如果条件成立表示bookElement就是要删除的元素
deleteBookElement = bookElement;
break;//结束循环
}
}
//3、在document中删除这个元素
if(deleteBookElement != null)
{
//找到deleteBookElement的父节点
Node parentNode = deleteBookElement.getParentNode();
//在父节点中删除掉这个节点
parentNode.removeChild(deleteBookElement);
}
//根据document(删除book元素之后的document)生成
createXML(document, "xml/bookstore.xml");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
修改操作(Update)
思路:
1、将要修改的xml转为对应的doc
ument
2、在document中找到要修改的元素
3、重新设置该元素中的信息
4、根据document(修改完元素)对象重新生成XML
/**
* 根据book对象中的信息生成相应的XML信息
* @param book
*/
public void updateBook(Book book)
{
try {
//1、将要修改的xml转为document对象
Document document = readXML("xml/bookstore.xml");
//2、找到要修改的book元素
NodeList bookNodeList = document.getElementsByTagName("book");
//遍历所有book节点
for(int i=0;i<bookNodeList.getLength();i++)
{
Node bookNode = bookNodeList.item(i);
//将bookNode转为对应的Element
Element bookElement = (Element)bookNode;
//判断bookElement是否是要修改的节点
if(book.getId().equals(bookElement.getAttribute("id")))
{
//3、修改相应信息
//找到该book下的name节点(就一个)
NodeList nameNodeList = bookElement.getElementsByTagName("name");
Node nameNode = nameNodeList.item(0);
//设置节点间的文本
nameNode.setTextContent(book.getName());
//找到该book下的price节点(就一个)
NodeList priceNodeList = bookElement.getElementsByTagName("price");
Node priceNode = priceNodeList.item(0);
//设置节点间的文本
priceNode.setTextContent(book.getPrice());
//找到该book下的author节点(就一个)
NodeList authorNodeList = bookElement.getElementsByTagName("author");
Node authorNode = authorNodeList.item(0);
//设置节点间的文本
authorNode.setTextContent(book.getAuthor());
//结束循环
break;
}
}
//4、根据修改完的document生成xml
createXML(document, "xml/bookstore.xml");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
简介SAX解析
SAX和DOM解析方法的不同
1. DOM是基于内存的,不管文
件有多大,都会将所有的内容预先装载到内存中。从而消耗很大的内存空间。而SAX是基于事件的。当某个事件被触发时,才获取相应的XML的部分数据,从而不管XML文件有多大,都只占用了少量的内存空间。
2. DOM可以读取XML也可以向XML文件中插入数据,而SAX却只能对XML进行读取,而不能在文件中插入数据。这也是SAX的一个缺点。(即DOM可以修改XML文档,SAX只能读XML文档)
3.SAX的另一个缺点:DOM我们可以指定要访问的元素进行随机访问,而SAX则不行。SAX是从文档开始执行遍历的。并且只能遍历一次。也就是说我们不能随机的访问XML文件,只能从头到尾的将XML文件遍历一次(当然也可以中间截断遍历)。
SAX解析XML时的主要事件介绍
通过SAX方式对XML进行读取
public class 通过SAX读取XML文件
{
public static void main(String[] args) throws Exception
{
//得到Sax解析器工厂
SAXParserFactory factory = SAXParserFactory.newInstance();
//通过SAX解析器工厂得到SAX解析器
SAXParser saxParser = factory.newSAXParser();
/*
利用parse(InputStream is, DefaultHandler dh)
使用指定的 DefaultHandler 将给定的 InputStream 实例的内容解析为 XML。
这里的DefaultHandler 就是需要自己写的XML解析标准,即通过SAX解析器,每个时间要怎么办
*/
InputStream is = new FileInputStream(“xml/bookstore.xml”);
//得到DefaultHandler对象,该对象为我们自己写的XML解析器
DefaultHandler dh =new BookSaxHandler();
saxParser.parse(is, dh)编写SAX解析准则类接DefaultHanr对象
`public class BookSaxHandler extends DefaultHandler
{
/**
* 开始读取文档时触发
*/
@Override
public void startDocument() throws SAXException {
System.out.println(“
/**
* 将指定的xml文件读取到Document对象中并返回
* @param xmlFilePath
* @return
* @throws DocumentException
*/
private Document readXML(String xmlFilePath) throws DocumentException
{
Document document = null;
//创建XML文档解析器
SAXReader reader = new SAXReader();
//对制定的XML文件进行解析得到对应的Document 对象
document = reader.read(xmlFilePath);
return document;
}
/**
将指定的Document对象写入指定的XML中
* @param document:数据源对应的document对象
* @param targetXmlFielPath :目标xml文件的位置
* @throws IOException
*/
private void writeXML(Document document,String targetXmlFielPath) throws IOException
{
//为制定的XML文件创建输出流
FileOutputStream fos = new FileOutputStream(targetXmlFielPath);
//创建XMLWriter对象,并与输出流绑定
XMLWriter writer = new XMLWriter(fos);
//利用XMLWriter对象将指定的document写入指定的流中
writer.write(document);//即完成将document中的信息写入指定的xml文件中。
}
读操作(Read)
基本思路:
1、将xml文件生成对应的 dom4j的Document对象。(生成的方法可以在Dom4j API中的快速入门得到例子代码)
2、利用Xpath在Document中找到所有标签名为book的元素列表
3、遍历book列表,得到每个提取book的所有信息并装入对应的Book对象中并将装好值得Book对象放入List中并返回(即返回List对象)
代码如下:
/**
* 将XML中的图书信息读取到List<Book>对象并返回
* @return
* @throws DocumentException
*/
public List<Book> queryBook()
{
List<Book> bookList = new ArrayList<Book>();
//读取到bookstore.xml对应的Document对象
try {
Document document = readXML("xml/bookstore.xml");
//利用XPath在Document对象中找到所有元素名叫book节点(元素)
List<Element> bookElementList =document.selectNodes("//book");
//遍历每个book节点
for(Element bookElement:bookElementList)
{
//创建Book对象准备装该元素的属性和子标签
Book book = new Book();
//得到ID
String id = bookElement.attributeValue("id");
//得到bookElement下的name的元素
Element nameElement = (Element)bookElement.selectSingleNode("name");
//得到nameElement标签的内容
String name = nameElement.getText();
//得到bookElement下的price的元素
Element priceElement = (Element)bookElement.selectSingleNode("price");
//得到priceElement标签的内容
String price = priceElement.getText();
//得到bookElement下的author的元素
Element authorElement = (Element)bookElement.selectSingleNode("author");
//得到nameElement标签的内容
String author = authorElement.getText();
//将当前书的信息放入Book对象
book.setId(id);
book.setName(name);
book.setPrice(price);
book.setAuthor(author);
//将装好值的book放入bookList中
bookList.add(book);
}
} catch (DocumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return bookList;
}
写操作(Create)
基本思路1:
1、将要操作的XML转为对应的Document
2、得到Document的根对象。然后在之后添加元素
3、一次添加book元素和book中的子元素。(注意dom4j的生成特点是先有父元素再有子元素)
4、根据添加完节点之后的Document对象 生成新的XML文件(再重新生成一次操作的文档)
/**
* 将book对象中的信息写入XML文件
* @param book
*/
public void addBook(Book book)
{
try
{
//得到XML对应的Document对象
Document document = readXML("xml/bookstore.xml");
//得到根元素
Element rootElement = document.getRootElement();
//在Root元素下创建新元素
Element bookElement = rootElement.addElement("book");
//给bookElement添加属性值
bookElement.addAttribute("id", book.getId());
//给bookElement添加子元素并指定标签的值
bookElement.addElement("name").setText(book.getName());
bookElement.addElement("author").setText(book.getAuthor());
bookElement.addElement("price").setText(book.getPrice());
//根据添加完节点Document重新生成XML
writeXML(document, "xml/bookstore.xml");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
修改操作(Update)
基本思路:
1、得到xml对应的Document对象
2、利用XPath定为到要修改的book元素
3、根据参数重新修改book元素下得信息
4、根据修改过后的Document重新生成XML文件
代码如下:
/**
* 根据book中的内容对指定XML中的信息进行修改
* @param book
*/
public void updateBook(Book book )
{
try {
//得到对应的Dcoument对象
Document document = readXML("xml/bookstore.xml");
//找到要修改的book元素.document.selectSingleNode方法是在文档直接抓取一个节点(元素),始终是在Document层面上抓取
Element bookElement = (Element)document.selectSingleNode("//book[@id='"+book.getId()+"']");
//修改bookElement下的相应信息
/* 给子标签name设置内容, element方法是在指定元素下是抓取子元素.
如果使用bookElement.selectSingleNode方法还是在Document层抓取,不能 在指定父元素下抓取*/
bookElement.element("name").setText(book.getName());
//给子标签price设置内容
bookElement.element("price").setText(book.getPrice());
//给子标签author设置内容
bookElement.element("author").setText(book.getAuthor());
//根据修改完毕的Document生成XML
writeXML(document, "xml/bookstore.xml");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
删除操作(Delete)
基本思路:
1、得到XML对应的Document对象
2、利用XPath在Document中直接抓取到要删除的Book元素
3、将该元素从父元素中删除掉
4、根据删除完的Document重新生成XML
代码如下:
/**
* 根据book的id属性值删除掉对应的book的对象
* @param bookid
*/
public void deleteBook(String bookid)
{
try {
//生成XML对应的Document对象
Document document = readXML("xml/bookstore.xml");
//根据id找到要删除的book对象,利用xpath找到要删除book元素
Element bookElement = (Element)document.selectSingleNode("//book[@id='"+bookid+"']");
//删除bookElement元素
//找到bookElement的父对象
Element parentElement = bookElement.getParent();
//删除指定对象
parentElement.remove(bookElement);
//根据删除完信息Document生成xml
writeXML(document, "xml/bookstore.xml");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}