文章目录
- 了解xml
- xml文件的结构
- **特殊处理**
- **CDATA**
- 强烈建议
- 处理xml文件的几种方式
- 认识Document对象
- 解析xml文档
- 该选择哪种方式解析
- DOM解析xml文件
- DOM4j解析xml文档
- SAX方式解析xml
了解xml
xml全称(Extensible Markup Language)可扩展标记语言。
xml和HTML属于同宗同源,都是SGML的衍生语言,下面是两者之间的区别:
- xml是大小写敏感的,例如
<H1>
h和<h1>
是不同的xml标签; - 在xml中,属性值必须用引号括起来,在HTML中,引号是可有可无的,例如,
<applet code="MyApplet.class" width=300>
对于HTML来说是合法的,在xml中,必须使用引号,比如<applet width="300">
- xml中,属性名必须有值,HTML中可以没有值,例如
<applet code="MyApplet.class" width>
对HTML是合理的,但是对xml来时就是错误的,width属性必须有值,<applet code="MyApplet.class" width=“300”>
xml需要注意的是注释中不能有–,否则会报错,如<!--这是错误--的注释-->
错误后面的–是不能加的。
xml文件的结构
1、文件头
ML文件头由XML声明与DTD文件类型声明组成。其中DTD文件类型声明是可以缺少的,XML声明:
<?xml version="1.0" encoding="gb2312"?>
XML声明必须出现在文档的第一行。
2、文件体
有元素和元素属性组成,
3、约束文档
这个可有可无,可以提供一个文档类型定义(DTD)或一个XML Schema定义。作用是包含了用于解释文档应如何构成的规则,这些规则指定了每个元素的合法子元素和属性。不能添加指定外的元素和属性。
4. 命名空间
:
特殊处理
实体引用
实体引用是指分析文档时会被字符数据取代的元素,实体引用用于XML文档中的特殊字符,否则这些字符会被解释为元素的组成部分。例如,如果要显示“<”,需要使用实体引用“<”否则会被解释为一个标记的起始。
CDATA
在XML中由一个特殊的标记CDATA,在CDATA中所有文本都不会被XML处理器解释,直接显示在浏览器中,使用方法如下:
<![CDATA[ 这里的内容可以直接显示。 ]]>
强烈建议
对于属性,一个常用的经验法则是,属性只应用来节点值得解释,而不是用来指定值,如正确的用法是
<font name="姓名" age="年龄">
<name>张三</name>
<age>18</age>
</font>
错误的用法:
<font name="张三" age="18">
</font>
处理xml文件的几种方式
有DOM,SAX,JDOM和DOM4J
等;DOM和SAX是解析方式,JDOM和DOM4J是解析开发包;jsoup也是xml解析开发包,但解析HTML更加方便
认识Document对象
Document对象时xml文档的树形结构在内存中的表现,它由实现了Node接口及其子接口的对象构成
各个子接口的层次结构
解析xml文档
要处理xml文档,就要先解析它。解析器是这样一个程序:它读入一个文件,确认这个文件具有正确的格式,然后将其分解成各种元素,是的程序员能够访问这些元素。java库提供了两种xml解析器:
- 文档对象模型(Document Object Model,DOM)解析器这样的树形解析器,它们将读入的xml整个文档转换成树结构。
- XML简单API(Simple API for XML,SAX)解析器这样的流机制解析器,它们在读入xml文档时生成相应的事件。
该选择哪种方式解析
DOM解析器对于实现我们大多数目的来说更容易些,缺点是它需要读取整个文档到内存,需要消耗较多内存,如果文档过大,那就建议使用SAX方式读取文件
DOM解析xml文件
JDK中包含DOM解析器,所以不需要额外的jar包或依赖。
要读入一个XML文档,首先需要一个DocumentBuilder对象,可以从DocumentBuilderFactory中获取
解析前xml文档
<?xml version="1.0" encoding="gb2312"?>
<grandfather>
<import location="http://localhost:8000/user?wsdl=IUserService.wsdl" namespace="http://webservice.com/">
</import>
<parent>
<son>
</son>
</parent>
<son>
</son>
</grandfather>
解析代码
try{
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
InputStream resourceAsStream = App.class.getClassLoader().getResourceAsStream("test1.xml");
Document document = builder.parse(resourceAsStream);
// getDocumentElement将返回根元素
Element documentElement = document.getDocumentElement();
// 通过节点名称获取所有此节点名称的节点
NodeList sonNodeList = documentElement.getElementsByTagName("son");
// 构建子节点,此节点可以添加到任意节点下
Element name = document.createElement("name");
name.setTextContent("姓名");
for (int i = 0; i < sonNodeList.getLength(); i++) {
// 获取指定索引的节点
Node item = sonNodeList.item(i);
// 可以用此判断只获取子节点
if (item instanceof Element){
Element element = (Element) item;
System.out.println(element.getTextContent());
// 添加子节点的方法
element.appendChild(name);
System.out.println(i);
}
}
// 获取节点中的文本内容,一般要用trim方法,否则会有换行符
String textContent = documentElement.getTextContent().trim();
// 获取指定属性的值
String location = documentElement.getAttribute("location");
documentElement.setAttribute("test","测试属性");
// 返回子节点的集合,此方法如果xml文件中没有DTD文件,则返回的除了子节点外还有节点之间的空格信息
NodeList childNodes = documentElement.getChildNodes();
//将构建好的xml输出到指定文件
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();;
// 输出内容是否使用换行
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
// 输出到文件
//transformer.transform(new DOMSource(document), new StreamResult(new File("language.xml")));
File file = new File("language.xml");
// file.createNewFile();
FileWriter fileWriter = new FileWriter(file);
// 之前用的file可以,但是后来就不行了,包文件名、目录名或卷标语法不正确。,改成filewrite就可以了
transformer.transform(new DOMSource(document), new StreamResult(fileWriter));
}catch (Exception e){
e.printStackTrace();
}
生成的文档
<?xml version="1.0" encoding="GB2312" standalone="no"?>
<grandfather test="测试属性">
<import location="http://localhost:8000/user?wsdl=IUserService.wsdl" namespace="http://webservice.com/">
</import>
<parent>
<son>
</son>
</parent>
<son>
<name>姓名</name>
</son>
</grandfather>
废了很大劲就是没有用代码将生成的xml文件格式化好,如有大佬知道,还望不吝赐教。还有就是name节点只在
DOM4j解析xml文档
需要用到的依赖
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
<!--使用xpath用到的依赖-->
<dependency>
<groupId>jaxen</groupId>
<artifactId>jaxen</artifactId>
<version>1.1-beta-8</version>
</dependency>
try {
InputStream resourceAsStream = App.class.getClassLoader().getResourceAsStream("test1.xml");
SAXReader saxReader = new SAXReader();
Document document = saxReader.read(resourceAsStream);
// 通过xpath获取节点
Node node = document.selectSingleNode("/grandfather/parent/son");
String sonNod = node.getText();
System.out.println("zijiediandenrirong:" + sonNod);
// 通过xpath获取节点并获取节点的属性
// document.
// 获取根节点
Element rootElement = document.getRootElement();
// 获取属性值
Attribute attribute = (Attribute)rootElement.selectSingleNode("/grandfather/import/@location");
String value = attribute.getValue();
System.out.println("属性值" + value);
// 普通方法获取节点对象直接点element()方法即可,这种只能获取子节点
Element sonElement = rootElement.element("子节点的节点名称");
// 获取根节点下面的子节点
Element anImport = rootElement.element("import");
// 会获取匹配到的符合条件的节点就返回此节点,即哪个节点靠前就返回哪个节点
Node sonN = rootElement.selectSingleNode("//son");// 表示不分任何层次结构的选择元素
String sonNo = sonN.getText();
System.out.println("22222222:" + sonNo);
List<Node> sonNode = rootElement.selectNodes("//son");
for (Node node1: sonNode) {
String sonNod1 = node1.getText();
System.out.println("111111111111:" + sonNod1);
}
// 添加节点和属性
Node node1 = rootElement.addElement("person");
node1.setText("新增加的节点");
// 设置生成xml的格式,会有层次结构
OutputFormat xmlFormat = OutputFormat.createPrettyPrint();
// 没有层次结构,所有节点都在一行
// OutputFormat compactFormat = OutputFormat.createCompactFormat();
//设置文件编码
xmlFormat.setEncoding("UTF-8");
// 设置换行
// xmlFormat.setNewlines(true);
// 生成缩进
// xmlFormat.setIndent(true);
// 使用4个空格进行缩进, 可以兼容文本编辑器
xmlFormat.setIndent(" ");
//创建写文件方法
XMLWriter xmlWriter = new XMLWriter(new FileWriter("language.xml"),xmlFormat);
//写入文件
xmlWriter.write(document);
//关闭
xmlWriter.close();
} catch (Exception e) {
e.printStackTrace();
}
SAX方式解析xml
此方式只适合获取节点信息,不适合修改xml文件
book实体类
package com.webservice;
/**
* @author :li
* @date :Created in 2020/12/12 21:34
* @description:book实体类
* @modified By:
* @version: $
*/
public class Book {
private String title;
private String author;
private Double price;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
@Override
public String toString() {
return "Book{" +
"title='" + title + '\'' +
", author='" + author + '\'' +
", price=" + price +
'}';
}
}
book.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<books>
<book>
<title>java基础</title>
<author>张三</author>
<price>45</price>
</book>
<book>
<title>C语言</title>
<author>李四</author>
<price>33</price>
</book>
</books>
MySaxHandler解析类
package com.webservice;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import java.util.ArrayList;
import java.util.List;
/**
* @author :li
* @date :Created in 2020/12/12 21:24
* @description:SAX解析器
* @modified By:
* @version: $
*/
public class MySaxHandler extends DefaultHandler {
private List<Book> list = new ArrayList<>();
private String nodeName;
private Book book;
public List<Book> getList() {
return list;
}
public void setList(List<Book> list) {
this.list = list;
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
super.characters(ch, start, length);
// System.out.println("characters");
String text = new String(ch, start, length);
if ("title".equals(nodeName)){
book.setTitle(text);
}else if ("author".equals(nodeName)){
book.setAuthor(text);
}else if ("price".equals(nodeName)){
book.setPrice(Double.parseDouble(text));
}
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
super.endElement(uri, localName, qName);
// System.out.println("endElement");
if (qName.equals("book")){
list.add(book);
}
/**
* 此处要设置为空,否则当节点为price时,会调用characters()方法,此时得到的文本内容会是空,而
* 执行Double.parseDouble(text)回报错
*/
nodeName = "";
}
@Override
public void endDocument() throws SAXException {
super.endDocument();
// System.out.println("endDocument");
}
@Override
public void startDocument() throws SAXException {
super.startDocument();
// System.out.println("startDocument");
}
/**
*
* @param uri 节点的命名空间 ,对命名空间的详细介绍https://www.runoob.com/xml/xml-namespaces.html
* @param localName
* @param qName 节点名称
* @param attributes 属性实体类
* @throws SAXException
*/
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
super.startElement(uri, localName, qName, attributes);
// System.out.println("startElement");
System.out.println("uri:" + uri + "===" + "localname:" + localName);
this.nodeName = qName;
Book book = null;
if (qName.equals("book")){
book = new Book();
this.book = book;
}
}
}
测试类
package com.webservice;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.InputStream;
import java.util.List;
/**
* @author :li
* @date :Created in 2020/12/12 18:44
* @description:通过SAX解析xml文档
* @modified By:
* @version: $
*/
public class SAXTest {
public static void main(String[] args) {
SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
try {
/**
* 通过打印发现规律
* 1、重写方法是按照startDocument、startElement、characters、endElement、endDocument执行的,
* 且执行完所有节点的startElement后才开始执行endElement;
* 2、每次执行startElement和endElement后就执行characters方法
* 3、重写的方法的参数都是初始化好的
*/
InputStream resourceAsStream = SAXTest.class.getClassLoader().getResourceAsStream("book.xml");
SAXParser saxParser = saxParserFactory.newSAXParser();
MySaxHandler mySaxHandler = new MySaxHandler();
saxParser.parse(resourceAsStream,mySaxHandler);
// 获取解析到的数据
List<Book> bookList = mySaxHandler.getList();
for (Book book : bookList) {
System.out.println("book====" + book );
}
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}