定义:Extensible Markup Language 可扩展标记语言
特点:
- XML与编程语言无关
- 可以实现不同编程语言实现的系统之间的数据转换
用途:
- 数据交换
- 实现项目的配置文件
和json对比:
- json比xml更加的轻量级
- xml比json更可读,结构更清晰
注意事项:
- xml使用的都是双标签
- xml标签名对大小写敏感
- 标签名建议使用字母加数字,不可使用特殊字符,不可使用空格
- 属性节点不建议使用< > " ’ &
- 建议同级标签要缩进对齐
解析的方式:
- DOM解析方式:基于dom数,把文档中的所有元素,按照其出现的层次关系,解析成一个个Node(节点) 对象
- 有点:把XML文件在内存中构建属性结构,可以遍历和修改节点。
- 缺点:如果文件比较大,内存有压力,解析的时间会比较长
- 适用:修改XML数据
- SAX解析方式:事件驱动,逐行扫描文档,一边扫描一边解析。相当于DOM,SAX可以在解析文档的任意时刻停止解析,是一种速度更快,更高效方法。
- 优点:解析可以立即开始,速度快,没有内存压力
- 缺点:不能对节点做修改
- 适用:读取XML文件
- DOM4J解析方式,有着更复杂的api,所以dom4j比jdom有更大的灵活性,DOM4J性能最好,连Sun的JAXM也在用DOM4J,目前许多开源项目中大量采用DOM4J,例如大名鼎鼎的Hibernate也用DOM4J来读取XML配置文件。如果不考虑可移植性,那就采用DOM4J
- 优点: 灵活性高,易用性和功能强大,性能优异
- 缺点:复杂的api,移植性差
- 适用:自行选择
- JDOM解析方式:JDOM是处理xml的纯java api。使用具体类而不是接口,JDOM具有树的的遍历,又有SAX的java规则,JDOM和DOM主要有两个方面不同。首先,JDOM仅使用具体类而不使用,这在某些方面简化了API,但是也限制了灵活性。第二,API大量使用了Collections类,简化了那些已经熟悉这些类的Java开发者的使用。JDOM本身不包含解析器。它通常使用SAX2解析器来解析和验证输入XML文档(尽管它还可以将以前构造的DOM表示作为输入)。它包含一些转换器已将JDOM表示输出成SAX2事件流,DOM模型或XML文本文档。JDOM是在Apache许可证变体下发布的开放源码
- 优点:基于dom树,比dom更简单,速度快
- 缺点:如果文件比较大,内存有压力,不支持DOM中相应的遍历包
- 适用:自行选择
使用:
解析: books.xml
<?xml version="1.0" encoding="UTF-8"?>
<!-- xml文件的声明:xml文件遵循xml1.0版本格式协议,文本编码采用utf-8 -->
<books> <!-- 根节点:只能有一个 -->
<book id="1"> <!-- book是`元素节点`,id是`属性节点` -->
<name>java从入门到放弃</name> <!-- name是元素节点,文本内容是`文本节点` -->
<author>王子玉</author>
<page>10</page>
</book>
<book id="2">
<name>mysql从删库到跑路</name>
<author>张三</author>
<page>20</page>
</book>
</books>
实体类:
public class Book {
private Long id;
private String name;
private String author;
private Integer page;
}
- DOM解析方式(读操作)
public static void main(String[] args){
ArrayList<Book> bookEmptyList = new ArrayList<>();
Book bookEmpty = null;
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
try{
//通过创建documentBuilder对象来对xml文件对象进行解析
DocumentBuilder db = dbf.newDocumentBuilder();
//解析完成之后会返回一个(w3c)document对象
Document document = db.parse("books.xml");
//获取xml文件对象当中的全部book标签对象并以节点集合的形式来进行返回操作
NodeList bookList = document.getElementsByTagName("book");
System.out.println("一共有" + bookList.getLength() + "本书。");
//对book标签节点集合对象进行遍历操作
for (int i = 0; i < bookList.getLength(); i ++){
System.out.println("开始遍历第" + (i + 1) + "本书的内容");
//建一个book的实体类用来存放解析出来的信息
bookEmpty = new Book();
//对集合数组对象当中的元素开始进行遍历操作,获取节点集合当中的节点对象
Node book = bookList.item(i);
//获取当前节点对象当中的全部的属性值对象并将其存放到map集合对象当中去
NamedNodeMap attrs = book.getArrtibutes();
//对当前节点当中的全部属性值进行遍历操作
System.out.println("第" + (i + 1) + "本书共有" + attrs.getLength() + "个属性");
for(int j = 0; j < attrs.getLength(); j++) {
//获取属性集合对象当中的第i个属性节点对象
Node attr = attrs.item(j);
//输出节点的名字
System.out.println("属性名:" + attr.getNodeName());
//输出节点的值
System.out.println("属性值:" + attr.getNodeValue());
}
//得到当前book对象的所有子节点对象,并且以一个节点集合的形式来进行返回操作
NodeList childNode = book.getChildNodes();
//遍历book节点的全部子节点对象
System.out.println("第" + (i + 1) + "本书当中共有" + childNode.getLength() + "个子节点");
//这里会显示有9个子节点,但是在xml文档当中可以看到只有四个子节点,是因为系统会自动的将book标签于子节点,子节点和子节点之间的空格+换行看作是一个节点,对book标签当中的子节点进行遍历输出操作
for (int k = 0; k < childNode.getLength(); k++) {
//对子节点集合当中的第K项子节点的名字进行输出操作
//只对含有标签对象的元素节点进行输出操作,对为空白的文本对象节点(#text)不进行输出操作
System.out.println("第" + (k + 1) + "个节点的节点名" + childNode.item(k).getNodeName());
//获取子节点对象的文本内容
System.out.println("节点的值是" + childNode.item(k).getTextContent());
}
}
}
}
(写操作)
public static void main(String[] args) throws Execption {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document document = db.newDocument();
//创建books根节点
Element books = document.createElement("books");
//创建book节点
Element book1 = document.createElement("book");
//给book节点设置属性名和属性值
book1.setArrribute("id", "1");
//创建name节点
Element name1 = document.createElement("name");
//创建author节点
Elemtent author1 = document.createElement("author");
//创建page节点
Element page1 = document.createElement("page");
//将name author page节点设置为book节点的子节点
book1.appendChild(name1);
book1.appendChild(author1);
book1.appendChild(page1);
//设置name author page的文本节点
name1.setTextContent("java从入门到到放弃");
author1.setTextContent("王子玉");
page1.setTextContent("10");
//将book节点作为book1的节点的子节点
books.appendChild(book1);
Element book2 = document.createElement("book");
book2.setAttribute("id", "2");
Element name2 = document.createElement("name");
Element author2 = document.createElement("author");
Element page2 = document.createElement("page");
book2.appendChild(name2);
book2.appendChild(author2);
book2.appendChild(page2);
name2.setTextContent("mysql从删库到跑路");
author2.setTextContent("韩文龙");
page2.setTextContent("20");
books.appendChild(book2);
//将books节点添加到dom数中
document.appendChild(books);
TransformerFactory tff = TransformerFactory.newInstance();
Transformer tf = tff.newTransformer();
//设置换行
tf.setOutputProperty(OutputKeys.INDENT, "yes");
//设置缩进
tf.setOutputProperty(
"http://xml.apache.org/xslt}indent-amount" , "2");
tf.transform(new DOMSource(document), new StreamResult(new File("book_dom.xml")));
}
- SAX解析:
public static void main(String[] args) throws Exception {
//获取SAX解析工厂对象
SAXParserFactory factory = SAXParserFactory.newInstance();
//调用工厂的newSAXParser方法获取SAXParser解析器对象
SAXParser parser = factory.newSAXParser();
//获取MyHander对象,为了得到XML文件对应的资源
MyHander dh = new MyHander();
//使用SAXParser解析器对象调用parse方法解析XML文件
parser.parse("NewFile.xml", dh);
//用get方法拿到MyHander中的Book型List集合
List<Book> bookList = dh.getBooks();
//打印输出
for(Book book : bookList) {
System.out.println(book);
}
}
//新建一个MyHander,该类需要继承DefaultHander后者实现ContentHander接口,
//这里我们使用继承DefaultHander的方式,该类是SAX解析的核心,需要重写几个方法,如下:
//1. startDocument(): 文档解析开始时调用,该方法只会调用一次
//2. startElements(String uri, String localName, String qName, Attributes attrubutes)
//节点解析式开始时调用
//url:xml文档的命名空间
//localName:节点的名字
//qName: 带命名空间节点的名字
//attributes: 节点的属性集
//3. characters(char[] ch, int start, int length):解析标签的内容的时候调用
//ch:当前读取到的TextNode(文本节点)的字节数组
//start: 字节开始的位置,为0就是从0开始读,全部读取
//length: 当前TextNode的长度
//4. endElements(String uri, String localName, String qName):节点解析结束后调用
//5. endDocument(): 文档解析结束后调用,该方法只会调用一次
public class MyHander extends DefaultHandler {
//初始化一个List数组
private List<Book> books = new ArrayList<>();
//用来记录当前的book
private Book book = null;
//提供一个getBooks()的方法,以便外部湖区List集合books
public List<Book> getBooks() {
return books;
}
boolean bName = false;
boolean bAuthor = false;
boolean bPage = false;
//节点开始解析
@Override
public void startElenment(String url, String localName, String qName, Attributes attributes) throws Exception {
super.startElement(url, localName, qName, attributes);
if(qName.equals("book")) {
String id = attributes.getValue("id");
book = new Book();
book.setId(Long.parseLong(id));
}else if (qName.equals("name")) {
bName = true;
}else if (qName.equals("author")) {
bAuthor = true;
} else if (qName.equals("page")) {
bPage = true;
}
}
//开始解析节点时候调用
@Override
public void characters(char[] ch, int start, int length) throws Exception {
super.character(ch, start, length);
if(bName) {
book.setName(new String(ch, start, length));
bName = false;
} else if (bAuthor) {
book.setAuthor(new String(ch, start, length));
} else if (bPage) {
book.setPage(Integer.parseInt(new String(ch, start, length)));
bPage = false;
}
}
//结束时调用
@Override
public void endElement(String url, String localName, String qName) thorws Exception {
super.endElement(url, localName, qName);
if (qName.equals("book")) {
books.add(book);
}
}
}
- 使用dom4j解析xml(读操作) 需要导入dom4j的jar包
public static void main(String[] args) {
ArrayList<Book> books = new ArrayList<>();
SAXReader read = new SAXReader();
//获取document文件
Document document = null;
try{
document = read.read(new File("books.xml"));
} catch (DocumentExceprion e) {
System.out.pirntln("没有找到文件");
}
//获取根节点
Element root = document.getRootElement();
//迭代器
Iterator rootIt = root.elementIterator();
while (rootIt.hasNext()) {
Book book = new Book();
Element element = (Element) rootIt.next();
//获取属性元素
List<Attribute> attrubytes = element.attributes();
for (Attribute attribute : attributes) {
if (attribute.getName().equals("id")) {
book.setId(Long.valueOf(attribute.getValue()));
}
}
//迭代器
Iterator child = element.elementIterator();
while(child.hasNext()) {
Element child Element = (Element) child.next();
//获取元素名字
String name1 = childElement.getName();
//获取元素的值
String value = childElement.getStringValue();
switch (name1) {
case "name":
book.setName(value);
break;
case "author":
book.setAuthor(value);
break;
case "page":
book.getPage(Integer.valueOf(value));
break;
}
}
books.add(book);
}
books,forEach(System.out::println);
}
(写操作)
public staic void main(String[] args) {
String path = "books_Dom4j.xml"
Document doc = DocumentHelper.createDocumemt();
//创建根对象
Element root = doc.addElement("books");
//创建一个一级子级对象
Element book1 = root.addElement("book");
//给一级子元素添加属性值
book1.setAttribute("id", "1");
//给一级子元素添加二级子元素
Element name1 = book1.addElement("name");
nam1.setText("遮天");
Element author1 = book1.addElement("author");
author1.setText("辰东");
Element page1 = book1.addElement("page");
page1.setText("123");
Element name2 = book2.addElement("name");
name2.setText("莽荒纪");
Element author2 = book2.addElement("author");
author.setText("我吃西红柿");
Element page2 = book2.addElement("page");
page2.setText("567");
//6. 设置输出流来生成一个xml文件
OutputStream os = null;
try {
os = new FileOutputStream(path);
} catch (FileNotFoundException e) {
System.out.println(e.getMessage());
}
//设置输出格式
OutputFormat format = OutputFormat.createPrettyPrint();
//设置xml编码
format.setEncoding("utf-8");
//写:两个参数,第一,输出流的xml文件在哪。第二,表示设置xml的格式
XMLWriter xw = null;
try{
xw = null;
} catch (Exception e) {
e.printStackTrace();
}
try{
xw = new XMLWriter(os, format);
} catch (UnsupportedEncodingExceprion e) {
e.printStackTrace();
}
//将组合好的xml封装到已经创建好的document对象中,写出真是存爱的xml文件中
try {
xw.write(doc);
} catch (IOException e) {
e.printStackTrace();
}
//清空缓存
try {
xw.flush();
xw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
- 使用JDOM解析XML(需要jdom的jar包)
public void readXML() throws Excprion {
//1. 创建一个解析器SAXBuilder
SAXBuilder builder = new SAXBuilder();
//2. 创建一个文件输入流
FileInputStream fis = new FileInputStream("books_jdom.xml");
//3. 将流加载到解析器中
org.jdom2.Document doc = builder.build(fis);
//4. 获取文档的根节点
Element book = doc.getRootElement();
//5. 对根节点进行遍历
getAllElement(book);
}
private void getAllElement(Element node) {
List<Attribute> attributes = node.getAttributes();
System.out.pirntln("节点:" + node.getName() + "内容:" + node.getText().trim());
if(node.hasArributes()) {
for (Attrubute attr : attrubutes) {
System.out.pirntln("属性" + attr.getName() + "值:" + attr.getValue());
}
}
List<Element> children = node.getChildren();
for (Element element : children) {
getAllElement(element);
}
}
写操作:
public void writeXML() throws IOException {
// 创建一个根节点
Element books = new Element("books");
Document doc = new Document(books);
//在根节点下创建第一个子节点
Element book1 = new Element("book");
book1.setAttrubute(new Attribute("id", "001"));
//在第一个子节点下创建第一个子节点
Element name1 = new Element("name");
name1.setText("java从放弃到入门");
Element author1 = new Element("author");
author1.setText("王子玉");
//在第一个子节点下创建第三个子节点
Element page1 = new Element("page");
page1.setText("35");
//在根节点下创建第二个子节点
Element book2 = new Element("book");
book2.setAttribute(new Attribute("id", "002"));
//在第二个子节点下创建第一个子节点
Element name2 = new Element("name");
name2.setText("mysql从删库到跑路");
//在第二个子节点下创建第二个子节点
Element author2 = new Element("author");
author2.setText("韩文龙");
//在第二个子节点下创建第三个子节点
Element page2 = new Element("page");
page2.setText("53");
books.addContent(book1);
books.addContent(book2);
book1.addContent(name1);
book1.addContent(author1);
book1.addContent(page1);
book2.addContent(name2);
book2.addContent(author2);
book2.addContent(page2);
//格式化
Format format = Format.getCompactFormat();
format.setEncoding("utf-8");
//保证输出后的xml的格式
format.setIndent(" ");
XMLOutputter out = new XMLOutputter(format);
ByteArrayOutputStream byteRsp = new ByteArrayOutputStream();
out.output(doc, byteRsp);
String str = byteRsp.toString("utf-8");
System.out.println(str);
out.output(doc, new FileOutputStream("books_jdom.xml"));
}