XML编程(CRUD)
XML解析技术概述
XML解析方式分为两种:dom和sax
dom:(Document Object Model, 即文档对象模型) 是 W3C 组织推荐的处理 XML 的一种方式。
sax: (Simple API for XML) 不是官方标准,但它是 XML 社区事实上的标准,几乎所有的 XML 解析器都支持它。
XML解析器
Crimson、Xerces 、Aelfred2
XML解析开发包
Jaxp、Jdom、dom4j
JAXP
JAXP 开发包是J2SE的一部分,它由javax.xml、org.w3c.dom 、org.xml.sax 包及其子包组成
在 javax.xml.parsers 包中,定义了几个工厂类,程序员调用这些工厂类,可以得到对xml文档进行解析的 DOM 或 SAX 的解析器对象。
使用JAXP进行DOM解析
javax.xml.parsers 包中的DocumentBuilderFactory用于创建DOM模式的解析器对象 , DocumentBuilderFactory是一个抽象工厂类,它不能直接实例化,但该类提供了一个newInstance方法 ,这个方法会根据本地平台默认安装的解析器,自动创建一个工厂的对象并返回。
获得JAXP中的DOM解析器
调用 DocumentBuilderFactory.newInstance() 方法得到创建 DOM 解析器的工厂。
调用工厂对象的 newDocumentBuilder方法得到 DOM 解析器对象。
调用 DOM 解析器对象的 parse() 方法解析 XML 文档,得到代表整个文档的 Document 对象,进行可以利用DOM特性对整个XML文档进行操作了。
DOM编程
• DOM解析器在解析XML文档时,会把文档中的所有元素,按照其出现的层次关系,解析成一个个Node对象(节点)。
• 在dom中,节点之间关系如下:
• 位于一个节点之上的节点是该节点的父节点(parent)
• 一个节点之下的节点是该节点的子节点(children)
• 同一层次,具有相同父节点的节点是兄弟节点(sibling)
• 一个节点的下一个层次的节点集合是节点后代(descendant)
• 父、祖父节点及所有位于节点上面的,都是节点的祖先(ancestor)
Node对象
l Node对象提供了一系列常量来代表结点的类型,当开发人员获得某个Node类型后,就可以把Node节点转换成相应的节点对象(Node的子类对象),以便于调用其特有的方法。(查看API文档)
l Node对象提供了相应的方法去获得它的父结点或子结点。编程人员通过这些方法就可以读取整个XML文档的内容、或添加、修改、删除XML文档的内容了。
/**
* 使用jaxp对xml文档进行dom解析
* @param args
* @throws Exception
*/
1、以如下格式的exam.xml文件为例
<?xml version="1.0" encoding="UTF-8"?>
<书架>
<书>
<书名 name="bbb" password="123">Java就业培训教程</书名>
<作者>黎活明</作者>
<售价>59元</售价>
<售价>39.00元</售价>
</书>
<书>
<书名>JavaScript网页开发</书名>
<作者>张孝祥</作者>
<售价>28.00元</售价>
</书>
</书架>
public static void main(String[] args) throws Exception {
//1.得到创建解析器的工厂
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
//2.得到解析器
DocumentBuilder builder = factory.newDocumentBuilder();
//解析xml文档
Document document = builder.parse(new File("src/book.xml"));
//find(document);
list(document);
}
//读取数据
public static void find(Document document){
NodeList list = document.getElementsByTagName("书名");
Node node = list.item(0);
String content = node.getTextContent();
System.out.println(content);
}
//写入数据
public static void add(Document document) throws TransformerException{
//1.创建节点
Node price = document.createElement("售价");
price.setTextContent("59元");
//2.找到要插入到哪个父亲下面
Node book = document.getElementsByTagName("书").item(0);
//3.调用父亲的方法进行插入
book.appendChild(price);
//4.要把更新后的内存重新写入到xml
TransformerFactory factory = TransformerFactory.newInstance();
Transformer former = factory.newTransformer();
former.transform(new DOMSource(document),new StreamResult(new File("src/book.xml")));
System.out.println("插入成功");
}
//写入数据2
public static void add2(Document document) throws TransformerException{
//1.创建节点
Node price = document.createElement("售价");
price.setTextContent("59元");
//2.找到要插入到哪个父亲下面
Node book = document.getElementsByTagName("书").item(0);
//3.找到参照节点
Node refNode = document.getElementsByTagName("售价").item(0);
//3.调用父亲的方法进行插入
book.insertBefore(price, refNode);
//4.要把更新后的内存重新写入到xml
TransformerFactory factory = TransformerFactory.newInstance();
Transformer former = factory.newTransformer();
former.transform(new DOMSource(document),new StreamResult(new File("src/book.xml")));
System.out.println("插入成功");
}
//修改:把第一本书的作者修改为黎活明
public static void update(Document document) throws Exception{
document.getElementsByTagName("作者").item(0).setTextContent("黎活明");
TransformerFactory factory = TransformerFactory.newInstance();
Transformer former = factory.newTransformer();
former.transform(new DOMSource(document),new StreamResult(new File("src/book.xml")));
}
//删除:把第二本书删掉
public static void delete(Document document) throws Exception{
/*Node root = document.getElementsByTagName("书架").item(0);
Node book = document.getElementsByTagName("书").item(1);
root.removeChild(book);*/
Node book = document.getElementsByTagName("书").item(1);
book.getParentNode().removeChild(book);
TransformerFactory factory = TransformerFactory.newInstance();
Transformer former = factory.newTransformer();
former.transform(new DOMSource(document),new StreamResult(new File("src/book.xml")));
}
//遍历xml文档所有节点
public static void list(Document document){
Node root = document.getElementsByTagName("书架").item(0);
listNode(root);
}
public static void listNode(Node node){
System.out.println(node.getNodeName());
NamedNodeMap map = node.getAttributes();
for(int i=0;map!=null && i<map.getLength();i++){ //null
Attr attr = (Attr) map.item(i);
String name = attr.getName();
String value = attr.getValue();
System.out.println(name + "=" + value);
}
NodeList list = node.getChildNodes();
for(int i=0;i<list.getLength();i++){
Node child = list.item(i);
listNode(child);
}
}
//xml文档属性的增删改查
//获取<书名 name="aaa"> name属性值
@Test
public void test1() throws Exception{
Document document =DocumentBuilderFactory.newInstance()
.newDocumentBuilder().parse(new File("src/book.xml"));
Element e = (Element) document.getElementsByTagName("书名").item(0);
String value = e.getAttribute("name");
System.out.println(value);
}
//向书名节点中添加一个password属性
@Test
public void test2() throws Exception{
Document document = DocumentBuilderFactory.newInstance()
.newDocumentBuilder().parse(new File("src/book.xml"));
Element node = (Element) document.getElementsByTagName("书名").item(0);
//创建要添加的属性
/*
Attr attr = document.createAttribute("password");
attr.setValue("123");
node.setAttributeNode(attr);
*/
node.setAttribute("email", "aa@sina.com");
TransformerFactory factory = TransformerFactory.newInstance();
Transformer former = factory.newTransformer();
former.transform(new DOMSource(document),new StreamResult(new File("src/book.xml")));
}
//删除属性
@Test
public void test3() throws Exception{
Document document = DocumentBuilderFactory.newInstance()
.newDocumentBuilder().parse(new File("src/book.xml"));
Element e = (Element) document.getElementsByTagName("书名").item(0);
e.removeAttribute("email");
TransformerFactory factory = TransformerFactory.newInstance();
Transformer former = factory.newTransformer();
former.transform(new DOMSource(document),new StreamResult(new File("src/book.xml")));
}
更新XML文档
javax.xml.transform包中的Transformer类用于把代表XML文件的Document对象转换为某种格式后进行输出,例如把xml文件应用样式表后转成一个html文档。利用这个对象,当然也可以把Document对象又重新写入到一个XML文件中。
Transformer类通过transform方法完成转换操作,该方法接收一个源和一个目的地。我们可以通过:
javax.xml.transform.dom.DOMSource类来关联要转换的document对象,
用javax.xml.transform.stream.StreamResult 对象来表示数据的目的地。
Transformer对象通过TransformerFactory获得。
SAX解析
在使用 DOM 解析 XML 文档时,需要读取整个 XML 文档,在内存中构架代表整个 DOM 树的Doucment对象,从而再对XML文档进行操作。此种情况下,如果 XML 文档特别大,就会消耗计算机的大量内存,并且容易导致内存溢出。
SAX解析允许在读取文档的时候,即对文档进行处理,而不必等到整个文档装载完才会文档进行操作。
SAX采用事件处理的方式解析XML文件,利用 SAX 解析 XML 文档,涉及两个部分:解析器和事件处理器:
• 解析器可以使用JAXP的API创建,创建出SAX解析器后,就可以指定解析器去解析某个XML文档。
• 解析器采用SAX方式在解析某个XML文档时,它只要解析到XML文档的一个组成部分,都会去调用事件处理器的一个方法,解析器在调用事件处理器的方法时,会把当前解析到的xml文件内容作为方法的参数传递给事件处理器。
• 事件处理器由程序员编写,程序员通过事件处理器中方法的参数,就可以很轻松地得到sax解析器解析到的数据,从而可以决定如何对数据进行处理。
SAX方式解析XML文档
使用SAXParserFactory创建SAX解析工厂
SAXParserFactory spf = SAXParserFactory.newInstance();
通过SAX解析工厂得到解析器对象
SAXParser sp = spf.newSAXParser();
通过解析器对象得到一个XML的读取器
XMLReader xmlReader = sp.getXMLReader();
设置读取器的事件处理器
xmlReader.setContentHandler(new BookParserHandler());
解析xml文件
xmlReader.parse("book.xml");
/**sax解析入门
* @param args
* @throws SAXException
* @throws Exception
*/
public static void main(String[] args) throws Exception, SAXException {
//1.得到工厂
SAXParserFactory factory = SAXParserFactory.newInstance();
//2.创建解析器
SAXParser sp = factory.newSAXParser();
//3.获得读取器
XMLReader reader = sp.getXMLReader();
//4.设置内容处理器
reader.setContentHandler(new NameHandler());
//5.读取xml文档
reader.parse("src/book.xml");
}
}
class NameHandler extends DefaultHandler{
private String currentNode = null;
private int index = 1; //记住想获取第几个作者的值
private int count = 0; //记住当前解析到的是第几个作者
public void startElement(String uri, String localName, String name,
Attributes atts) throws SAXException {
if(name.equals("作者")){
currentNode = "作者";
count++;
}
}
public void characters(char[] ch, int start, int length)
throws SAXException {
if(currentNode!=null && currentNode.equals("作者") && count==index){
String content = new String(ch,start,length);
System.out.println(content);
}
}
public void endElement(String uri, String localName, String name)
throws SAXException {
currentNode = null;
}
DOM4J解析XML文档
Dom4j是一个简单、灵活的开放源代码的库。Dom4j是由早期开发JDOM的人分离出来而后独立开发的。与JDOM不同的是,dom4j使用接口和抽象基类,虽然Dom4j的API相对要复杂一些,但它提供了比JDOM更好的灵活性。
Dom4j是一个非常优秀的Java XML API,具有性能优异、功能强大和极易使用的特点。现在很多软件采用的Dom4j,例如Hibernate,包括sun公司自己的JAXM也用了Dom4j。
使用Dom4j开发,需下载dom4j相应的jar文件。
DOM4j中,获得Document对象的方式有三种:
1.读取XML文件,获得document对象
SAXReader reader = new SAXReader(); Document document = reader.read(new File("input.xml"));
2.解析XML形式的文本,得到document对象.
String text = "<members></members>"; Document document = DocumentHelper.parseText(text);
3.主动创建document对象.
Document document = DocumentHelper.createDocument(); //创建根节点
Element root = document.addElement("members");
节点对象
1.获取文档的根节点.
Element root = document.getRootElement();
2.取得某个节点的子节点.
Element element=node.element(“书名");
3.取得节点的文字
String text=node.getText();
4.取得某节点下所有名为“member”的子节点,并进行遍历. List nodes = rootElm.elements("member"); for (Iterator it = nodes.iterator(); it.hasNext();) { Element elm = (Element) it.next(); // do something }
5.对某节点下的所有子节点进行遍历. for(Iterator it=root.elementIterator();it.hasNext();){ Element element = (Element) it.next(); // do something }
6.在某节点下添加子节点.Element ageElm = newMemberElm.addElement("age");
7.设置节点文字. element.setText("29");
8.删除某节点.//childElm是待删除的节点,parentElm是其父节点
parentElm.remove(childElm);
9.添加一个CDATA节点.Element contentElm = infoElm.addElement("content");contentElm.addCDATA(diary.getContent());
节点对象属性
1.取得某节点下的某属性 Element root=document.getRootElement(); //属性名name
Attribute attribute=root.attribute("size");
2.取得属性的文字 String text=attribute.getText();
3.删除某属性 Attribute attribute=root.attribute("size"); root.remove(attribute);
3.遍历某节点的所有属性 Element root=document.getRootElement(); for(Iterator it=root.attributeIterator();it.hasNext();){ Attribute attribute = (Attribute) it.next(); String text=attribute.getText(); System.out.println(text); }
4.设置某节点的属性和文字. newMemberElm.addAttribute("name", "sitinspring");
5.设置属性的文字 Attribute attribute=root.attribute("name"); attribute.setText("sitinspring");
将文档写入XML文件
1.文档中全为英文,不设置编码,直接写入的形式. XMLWriter writer = new XMLWriter(new FileWriter("output.xml")); writer.write(document); writer.close();
2.文档中含有中文,设置编码格式写入的形式.OutputFormat format = OutputFormat.createPrettyPrint();// 指定XML编码
format.setEncoding("GBK"); XMLWriter writer = new XMLWriter(newFileWriter("output.xml"),format);writer.write(document);writer.close();
Dom4j在指定位置插入节点
1.得到插入位置的节点列表(list)
2.调用list.add(index,elemnent),由index决定element的插入位置。
Element元素可以通过DocumentHelper对象得到。示例代码:
Element aaa = DocumentHelper.createElement("aaa");
aaa.setText("aaa");
List list = root.element("书").elements();
list.add(1, aaa);
//更新document
字符串与XML的转换
1.将字符串转化为XML
String text = "<members> <member>sitinspring</member></members>";Document document = DocumentHelper.parseText(text);
2.将文档或节点的XML转化为字符串.
SAXReader reader = new SAXReader();Document document = reader.read(new File("input.xml")); Element root=document.getRootElement();
String docXmlText=document.asXML();
String rootXmlText=root.asXML();Element memberElm=root.element("member");String memberXmlText=memberElm.asXML();
//dom4j的crud
public class Demo1 {
//遍历xml文档
@Test
public void test1() throws Exception{
SAXReader reader = new SAXReader();
Document document = reader.read(new File("src/book.xml"));
list(document.getRootElement());
}
public void list(Element node){
System.out.println(node.getName());
List<Node> list = node.elements();
for(Node child : list){
if(child instanceof Element){
list((Element)child);
}
}
}
//读取售价的值
@Test
public void read() throws Exception{
SAXReader reader = new SAXReader();
Document document = reader.read(new File("src/book.xml"));
Element root = document.getRootElement();
String content = root.element("书").element("售价").getText();
System.out.println(content);
}
//向xml文档中添加一个:<售价>39元</售价>
@Test
public void write() throws Exception{
SAXReader reader = new SAXReader();
Document document = reader.read(new File("src/book.xml"));
Element price = DocumentHelper.createElement("售价");
price.setText("39元");
Element root = document.getRootElement();
root.element("书").add(price);
OutputFormat format = OutputFormat.createPrettyPrint();
format.setEncoding("gb2312");
XMLWriter writer = new XMLWriter(new FileOutputStream("src/book.xml"),format);
writer.write(document);
writer.close();
/*OutputFormat format = OutputFormat.createPrettyPrint();
format.setEncoding("gb2312");
//document-->utf-8
FileWriter fw = new FileWriter("src/book.xml");
XMLWriter writer = new XMLWriter(fw,format);
writer.write(document);
writer.close();*/
/*
XMLWriter writer = new XMLWriter(
new OutputStreamWriter(new FileOutputStream("src/book.xml"),"UTF-8"),format);
writer.write(document);
writer.close();*/
}
//向指定位置插入:<售价>39元</售价>
@Test
public void write2() throws Exception{
SAXReader reader = new SAXReader();
Document document = reader.read(new File("src/book.xml"));
Element price = DocumentHelper.createElement("售价");
price.setText("39元");
Element book = document.getRootElement().element("书");
List list = book.elements(); //
list.add(2, price); //向指定位置插入
OutputFormat format = OutputFormat.createPrettyPrint();
format.setEncoding("gb2312");
XMLWriter writer = new XMLWriter(new FileOutputStream("src/book.xml"),format);
writer.write(document);
writer.close();
}
//删除售价节点:
@Test
public void delete() throws Exception{
SAXReader reader = new SAXReader();
Document document = reader.read(new File("src/book.xml"));
Element price = document.getRootElement().element("书").element("售价");
price.getParent().remove(price);
OutputFormat format = OutputFormat.createPrettyPrint();
format.setEncoding("gb2312");
XMLWriter writer = new XMLWriter(new FileOutputStream("src/book.xml"),format);
writer.write(document);
writer.close();
}