英文全称为Extensible Markup Language,翻译过来为可扩展标记语言。现实生活中存在着大量的数据,在这些数据之间往往存在一定的关系,我们希望能在计算机中保存和处理这些数据的同时能够保存和处理他们之间的关系。XML就是为了解决这样的需求而产生的数据存储格式。
在XML语言中,它允许用户自定义标签。每一个标签用于描述一段数据。一个标签可以分为开始标签和结束标签,在开始标签和结束标签之间又可以嵌套其它标签,利用标签间的嵌套关系来保存数据之间的上下级关系;由于XML实质上是一段字符串,计算机可以十分方便的对他进行操作,开发人员也可以方便的阅读,因此可以说这是一种对人、对计算机都友好的数据存储格式,所以XML迅速普及,成为了一种非常常见的数据存储格式,在许多应用场景中得到应用。
1、传输数据
XML本质上是一段字符串,具有跨平台性的特性,因此XML常被用来在不同系统之间进行数据交换。一个典型的android应用是由服务器发送信息给android客户端后,由android客户端负责展示。此时,android客户端是java+android开发环境的。而服务器端很可能是C#+windows开发环境。如何在不同的语言、不同操作系统之间传输数据呢?XML就是一个很好的选择。
2、配置文件
XML可以在保存数据的同时保存数据之间的关系。利用这一特点,它还经常用作应用程序配置文件来使用。
浏览器除了内置HTML解析器外还内置了XML解析器,因此我们可以使用浏览器对XML进行校验。
(一)语法要求不同
(二)标记不同
1、HTML使用固有的标记;而XML没有固有的标记。
2、HTML标签是预定义的;XML标签是免费的、自定义的、可扩展的。
(三)作用不同
xml的语法:文档声明、元素、属性、注释、CDATA区(转义字符)、处理指令
(一)文档声明
用来声明XML 的基本属性,用来指挥解析引擎如何去解析当前XML 。通常一个XML 都要包含并且只能包含一个文档声明。XML 的文档声明必须在整个XML 的最前面,在文档声明之前不能有任何内容。
version是必须存在的属性,表明当前xml所遵循规范的版本,目前位置都写1.0就可以了。
一定要保证xml格式的数据在保存时使用的编码和解析时使用的编码必须一致,才不会有乱码问题
standalone属性用来指明当前xml是否是一个独立的xml,默认值是yes表明当前文档不需要依赖于其他文档,
如果当前文档依赖其他文档而存在则需要将此值设置为no
(二)元素
元素的语法
元素的命名
和
是两个不同的标记。(三)属性
(四)注释
(五)CDATA区/转义字符
当XML中一段内容不希望被解析器解析时可以使用CDATA区将其包住。当解析器遇到CDATA区时会将其内容当作文本对待,不会进行解析
语法:
转义字符:
& --> &
< --> <
> --> >
" --> "
' --> '
( 六)处理指令
处理指令,简称PI (processing instruction)。处理指令用来指挥解析引擎如何解析XML文档内容。
XML编程: 利用java程序去增删改查(CRUD) XML 中的数据。
解析思想: DOM解析和SAX解析
1、DOM解析
DOM(Document Object Model) 它是 W3C 组织推荐的处理 XML 的一种方式。它会将整个XML使用类似树的结构保存在内存中,再对其进行操作,所以它需要等到XML完全加载进内存才可以进行操作。它的缺点是耗费内存,当解析超大的XML时慎用。优点是可以方便的对XML 进行增删改查的操作。
在java SE的api提供了org.w3c.dom包里面有Node接口,此接口中提供了很多增删改查节点的方法,而所有文档树的对象都实现这个接口。
2、SAX解析
这种解析方式会逐行地去扫描XML文档,当遇到标签时会触发解析处理器,采用事件处理的方式解析XML (Simple API for XML) ,不是官方标准,但它是 XML 社区事实上的标准,几乎所有的 XML 解析器都支持它。优点是:在读取文档的同时即可对XML进行处理,不必等到文档加载结束,相对快捷。不需要加载进内存,因此不存在占用内存的问题,可以解析超大XML。缺点是:只能用来读取XML中数据,无法进行增删改。
它需要解析器和事件处理器,其中事件处理器里面的操作需要开发人员实现,注册到解析器中,解析器逐行扫描XML文件会调用事件处理器中的方法。
基于这两种解析思想市面上就有了很多的解析api
SAX解析的步骤:
//1、使用SAXParserFactory创建SAX解析工厂
SAXParserFactory spf = SAXParserFactory.newInstance();
//2、通过SAX解析工厂得到解析器对象
SAXParser sp = spf.newSAXParser();
//3、通过解析器对象得到一个XML的读取器
XMLReader xmlReader = sp.getXMLReader();
//4、设置读取器的事件处理器
xmlReader.setContentHandler(new MyContentHandler());
//5、解析xml文件
xmlReader.parse("book.xml");
已知xml文件book.xml如下:
<书架>
<书>
<书名>Java编程书名>
<作者>张三作者>
<售价>20.00元售价>
书>
<书>
<书名>Java设计模式书名>
<作者>李四作者>
<售价>30.00元售价>
书>
书架>
SAX实现输出第二本书的书名的功能源码:
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
public class SaxDemo{
public static void main(String[] args) throws Exception {
//1.获取解析器工厂
SAXParserFactory factory = SAXParserFactory.newInstance();
//2.通过工厂获取sax解析器
SAXParser parser = factory.newSAXParser();
//3.获取读取器
XMLReader reader = parser.getXMLReader();
//4.注册事件处理器
reader.setContentHandler(new MyContentHandler2() );
//5.解析xml
reader.parse("book.xml");
}
}
//适配器设计模式
class MyContentHandler2 extends DefaultHandler{
private String eleName = null;
private int count = 0;
public void startElement(String uri, String localName, String name,
Attributes attributes) throws SAXException {
this.eleName = name;
}
public void characters(char[] ch, int start, int length)
throws SAXException {
if("书名".equals(eleName) && ++count==2){
System.out.println(new String(ch,start,length));
}
}
public void endElement(String uri, String localName, String name)
throws SAXException {
eleName = null;
}
}
4、DOM4J解析XML文档
Dom4j是一个简单、灵活的开放源代码的库。Dom4j是由早期开发JDOM的人分离出来而后独立开发的。与JDOM不同的是,dom4j使用接口和抽象基类,虽然Dom4j的API相对要复杂一些,但它提供了比JDOM更好的灵活性。
Dom4j是一个非常优秀的Java XML API,具有性能优异、功能强大和极易使 用的特点。现在很多软件采用的Dom4j,例如Hibernate,包括sun公司自己的JAXM也用了Dom4j。
使用Dom4j开发,需下载dom4j相应的jar文件。
(一)DOM4j解析xml文件
//创建解析器:
SAXReader reader = new SAXReader();
//利用解析器读入xml文档:
Document document = reader.read(new File("input.xml"));
//获取文档的根节点:
Element root = document.getRootElement();
(二)DOM4j节点操作
//1.取得某个节点的子节点.
Element element =ele.element(“书名");
List elementList =ele.elements(“书名");
List elementList =ele.elements();
//2.获取节点的名字
node.getName();
//3.设置节点的名字
node.setName(String newName);
//4.取得节点的文字(标签体)
String text=node.getText()
//5.设置节点的文字(标签体)
node.setText("aaa");
//6.添加子节点.
ele.add(Element e);ele.addElement("age");
//7.删除子节点节点.
parentElm.remove(childElm);
//8.获取节点类型
node.getNodeType() ;
//9.获取父节点
node.getParent();
//10.取得某节点对象的某属性
Attribute attr= ele.attribute("aaa");
Attribute attr= ele.attribute(0);
List list = ele.attributes();
String value = ele.attributeValue("aaa");
Iterator it = ele.attributeIterator();
//11.设置某节点的属性
ele.add(Attribute attr);
ele.addAttribute(name, value);
ele.setAttributes(List attrs);
//12.删除某属性
ele.remove(attribute);
/*13.在指定位置插入节点
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);
(三)DOM4j属性
//1.取得属性的名、值
String name = attribute.getName();
String value = attribute.getValue();
//2.设置某属性的名、值
attribute.setName();
attribute.setValue();
(四)DOM4j字符串和XML的转换
//1.将字符串转化为XML
String text = " sitinspring ";Document document = DocumentHelper.parseText(text);
//2.将文档或节点的XML转化为字符串.
String xmlStr = node.asXML();
(五)DOM4j将文档写入XML文件
方式一:
调用Node提供的write(Writer writer) 方法,使用默认方式将节点输出到流中:
node.write(new FileWriter("book.xml"));
乱码问题:Dom4j在将文档载入内存时使用的是文档声明中encoding属性声明的编码集进行编码,如果在此时使用的writer的内部编码集与最初载入内存时使用的编码集不同则会出现乱码问题。FileWriter默认使用操作系统本地码表即gb2312编码,并且无法更改。此时可以使用如下的方式自己封装一个指定码表的Writer使用,从而解决乱码问题。
OutputStreamWriter(FileOutputStream("filePath"),"utf-8");
方式二:
利用XMLWriter写出Node:
XMLWriter writer = new XMLWriter(new FileWriter("output.xml"));
writer.write(node); writer.close();
注意:使用这种方式输出时,XMLWriter首先会将内存中的docuemnt翻译成UTF-8格式的document再进行输出,这时有可能出现乱码问题。可以使用OutputFormat 指定XMLWriter转换的编码为其他编码。
OutputFormat format = OutputFormat.createPrettyPrint();
format.setEncoding("GBK");
XMLWriter writer = new XMLWriter(newFileWriter("output.xml"),format);
Writer使用的编码集与文档载入内存时使用的编码集不同导致乱码,使用字节流或自己封装指定编码的字符流即可。
(六)DOM4j–DocumentHelper
createDocument();
createDocument(Element rootEle
createAttribute(Element owner, String name, String value));
createElement(String name);
Docuemnt parseText(String text);
5. DOM4J编码示例
入门示例:针对上面的book.xml打印第一本书的名字:
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
public class Dom4jDemo1 {
public static void main(String[] args) throws Exception {
//1.获取解析器
SAXReader reader = new SAXReader();
//2.解析xml获取代表整个文档的dom对象
Document dom = reader.read("book.xml");
//3.获取根节点
Element root = dom.getRootElement();
//4.获取书名进行打印
String bookName = root.element("书").element("书名").getText();
System.out.println(bookName);
}
}
示例2:对dom元素和属性进行增删改查的操作
import java.io.FileOutputStream;
import java.util.List;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import org.junit.Test;
public class Demo4jDemo2 {
@Test
public void attr() throws Exception{
SAXReader reader = new SAXReader();
Document dom = reader.read("book.xml");
Element root = dom.getRootElement();
Element bookEle = root.element("书");
//bookEle.addAttribute("出版社", "传智出版社");
// String str = bookEle.attributeValue("出版社");
// System.out.println(str);
Attribute attr = bookEle.attribute("出版社");
attr.getParent().remove(attr);
XMLWriter writer = new XMLWriter(new FileOutputStream("book.xml"),OutputFormat.createPrettyPrint());
writer.write(dom);
writer.close();
}
@Test
public void del() throws Exception{
SAXReader reader = new SAXReader();
Document dom = reader.read("book.xml");
Element root = dom.getRootElement();
Element price2Ele = root.element("书").element("特价");
price2Ele.getParent().remove(price2Ele);
XMLWriter writer = new XMLWriter(new FileOutputStream("book.xml"),OutputFormat.createPrettyPrint());
writer.write(dom);
writer.close();
}
@Test
public void update()throws Exception{
SAXReader reader = new SAXReader();
Document dom = reader.read("book.xml");
Element root = dom.getRootElement();
root.element("书").element("特价").setText("4.0元");
XMLWriter writer = new XMLWriter(new FileOutputStream("book.xml"),OutputFormat.createPrettyPrint());
writer.write(dom);
writer.close();
}
@Test
public void add()throws Exception{
SAXReader reader = new SAXReader();
Document dom = reader.read("book.xml");
Element root = dom.getRootElement();
//凭空创建<特价>节点,设置标签体
Element price2Ele = DocumentHelper.createElement("特价");
price2Ele.setText("40.0元");
//获取父标签<书>将特价节点挂载上去
Element bookEle = root.element("书");
bookEle.add(price2Ele);
//将内存中的dom树会写到xml文件中,从而使xml中的数据进行更新
// FileWriter writer = new FileWriter("book.xml");
// dom.write(writer);
// writer.flush();
// writer.close();
XMLWriter writer = new XMLWriter(new FileOutputStream("book.xml"),OutputFormat.createPrettyPrint());
writer.write(dom);
writer.close();
}
@Test
public void find() throws Exception{
SAXReader reader = new SAXReader();
Document dom = reader.read("book.xml");
Element root = dom.getRootElement();
List list = root.elements();
Element book2Ele = list.get(1);
System.out.println(book2Ele.element("书名").getText());
}
}