文章目录
什么是XML
XML(EXtensible Markup Language),可扩展标记语言,是一种简单的基于文本的语言,旨在以村文本格式存储和传输数据,他代表可扩展标记语言。
1、作为系统的配置文件
2、作为一种特殊的数据结构,在网络中进行传输
特点
XML与操作系统、编程语言的开发平台无关
实现不同系统之间的数据交换
XML作用
- 数据交互
- 配置应用程序和网站
- Ajax基石
XML的编写语法
基本语法
所有XML元素都必须有结束标签
XML标签对大小写敏感
XML必须正确的嵌套
同级标签以缩进对齐
元素名称可以包含字母、数字或其他的字符
元素名称不能以数字或者标点符号开始
元素名称中不能含空格
xml
<?xml version="1.0" encoding="UTF-8"?>
<books>
<!--图书信息 这是注释-->
<book id="bk101">
<author>王珊</author>
<title>.NET高级编程</title>
<description>包含C#框架和网络编程等</description>
</book>
<book id="bk102">
<author>李明明</author>
<title>XML基础编程</title>
<description>包含XML基础概念和基本作用</description>
</book>
</books>
注意一:<?xml version="1.0" encoding="utf-8" ?>这行是必须要写的,且必须放在首行(前面有注释都不行)。表示版本为1.0,以utf-8字符集来编码
注意二:根标签只能有一个,子标签可以有多个
注意三:标签是成对存在的,记得嵌套正确
XML文件可以在浏览器中查看,我们打开浏览器看到,我们写的特殊字符的格式是我们所预期的
特殊字符编写
1、 指定字符替代特殊字符
XML中书写"<'
"&"等,可能会出现冲突,导致报错,此时可以用如下特殊字符替代。
指定字符 | 特殊字符 | 含义 |
---|---|---|
< | < | 小于 |
> | > | 大于 |
& | & | 小于 |
' | ' | 单引号 |
" | " | 双引号 |
2、CDATA的数据区
XML中可以写一个叫CDATA的数据区:<![CDATA[..内容... ]]>,里面的内容可以随便写
xml
<Users>
<user id="1">
<name>张三</name>
<age>18</age>
<address>广州</address>
</user>
<userAttribute>都是爱学习的人</userAttribute>
<user id="2">
<name>李四</name>
<age>25</age>
<address>哈尔滨</address>
</user>
<!--以下是带有大于号小于号等特殊字符的写法-->
<special>
<![CDATA[
5 > 2 && 3 < 5
]]>
</special>
<!--特殊字符用法二-->
<special> 5 > 2 && 3 < 5 </special>
</Users>

约束XML的书写格式
DTD文档
特点
可以约束XML文件的编写
不能约束具体的数据类型
DTD文档的使用
①:编写DTD约束文档,后缀必须是.dtd
data.dtd
根目录只能叫做书并且可以有多个书的子元素
书只能由书名作者售价构成
dtd
<!ELEMENT 书架 (书+)>
<!ELEMENT 书 (书名,作者,售价)>
<!ELEMENT 书名 (#PCDATA)>
<!ELEMENT 作者 (#PCDATA)>
<!ELEMENT 售价 (#PCDATA)>
②:在需要编写的XML文件中导入该DTD约束文档
<!DOCTYPE 书架 SYSTEM "data.dtd">
③:然后XML文件,就必须按照DTD约束文档指定的格式进行编写,否则报错
xml
<?xml version="1.0" encoding="UTF-8"?>
<!-- 导入约束格式 -->
<!DOCTYPE 书架 SYSTEM "data.dtd">
<书架>
<!-- 只能这么写否则报错 -->
<书>
<书名>哈利波特</书名>
<作者>J.K.罗琳</作者>
<!-- 售价的类型可以是浮点型,字符串,也可以是任何数据类型 -->
<售价>49.9</售价>
</书>
<书>
<书名>西游记</书名>
<作者>吴承恩</作者>
<售价>49.9</售价>
</书>
</书架>
schema文档
特点
可以约束XML文件的编写
可以约束具体的数据类型
schema文档的使用
1、编写schema约束文档,后缀必须是.xsd,具体的形式到代码中观看。
2、在需要编写的XML文件中导入该schema约束文档
3、按照约束内容编写XML文件的标签
xml
<?xml version="1.0" encoding="UTF-8"?>
<!-- xmlns: 核心命名空间声明 -->
<!-- xmlns="http://www.w3.org/2001/XMLSchema:
声明使用W3C XML Schema规范作为默认命名空间,所有未加前缀的标签均属于该规范。 -->
<!-- targetNamespace(目标命名空间): 申明约束文档的地址(命名空间) 这里的data.xsd也是被约束的 -->
<!-- elementFormDefault(元素命名空间规则): 先不用管,这是关于局部元素的命名空间归属的属性-->
<schema xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.itcast.cn"
elementFormDefault="qualified" >
<!--全局元素定义,作为根元素,该元素直接属于targetNamespace命名空间-->
<element name="书架">
<complexType>
<!-- maxOccurs="unbounded" 书架下的子元素可以有无穷多个 -->
<sequence maxOccurs="unbounded">
<element name="书">
<!-- 写子元素 -->
<complexType>
<sequence>
<element name="书名" type="string"/>
<element name="作者" type="string"/>
<element name="价格" type="double"/>
</sequence>
</complexType>
</element>
</sequence>
</complexType>
</element>
</schema>

属性命名空间
xml
<?xml version="1.0" encoding="UTF-8"?>
<batchCompany xmlns="http://www.Aptech_edu.ac"
xmlns:tea="http://www.tea.org">
<batch-list>
<!-- 下面这个命名空间属于xmlns:tea="http://www.Aptech_edu.ac" -->
<batch type="thirdbatch">第三批次</batch>
<!-- 下面这个命名空间属于xmlns:tea="http://www.tea.org" -->
<batch tea:type="thirdbatch">第三批茶</batch>
<!-- 下面这个命名空间属于xmlns:tea="http://www.Aptech_edu.ac" -->
<batch>午班批次</batch>
</batch-list>
</batchCompany>
除非带有前缀,否则属性属于所属的元素的命名空间
XML命名空间的作用
解决在复杂、大型XML文件中,出现名称相同,但是含义不同的元素
xml
<?xml version="1.0" encoding="UTF-8"?>
<!-- 两个厂家(佳能相机和尼康相机)的地址 -->
<cameras xmlns:canon="http://www.canon"
xmlns:nikon="http://www.nikon.com">
<!-- 虽然都是相机camera
但是第一个是canon(佳能牌)的相机
第二个是nikon(尼康牌)的相机
-->
<canon:camera prodID="P663" name="Camera傻瓜相机"/>
<nikon:camera prodID="K29B3" name="Camera超级35毫米相机"/>
</cameras>
解析XML的方法
本节分三块
DOM(内置解析XML)
- 基于XML文档树结构的解析
- 适用于多次访问的XML文档
- 特点:比较消耗资源
SAX(内置解析XML)
- 基于事件的解析
- 适用于大数据量的XML文档
- 特点:占用资源少,内存消耗小
DOM4J
- 非常优秀的Java XML API
- 性能优异、功能强大
- 开放源代码
DOM解析XML
基于XML文档树结构的解析
适用于多次访问的XML文档
特点:比较消耗资源
DOM介绍
文档对象模型(Document Object Model)
DOM把XML文档映射成一个倒挂的树
DOM解析包:org.w3c.dom
org.w3c.dom 是 Java 中用于处理 文档对象模型(DOM) 的核心包,由 万维网联盟(W3C) 制定并维护。它是 W3C DOM 标准的 Java 语言绑定实现,主要用于解析、访问和操作 XML/HTML 文档的结构化内容。(jdk自带的用于解析xml文件的API)
常用接口
常用接口 | 常用方法 | 说明 |
---|---|---|
Document:表示整个 XML 文档 | NodeList getElementsByTagName(String Tag) | 按文档顺序返回文档中指定标记名称的所有元素集合 |
Element createElement(String tagName) | 创建指定标记名称的元素 | |
Node:该文档树中的单个节点 | NodeList getChildNodes() | 获取该元素的所有子节点,返回节点集合 |
Element:XML 文档中的一个元素 | String getTagName() | 获取元素名称 |
DOM解析包的使用
DOM解析XML文件步骤
- 创建解析器工厂对象
- 解析器工厂对象创建解析器对象
- 解析器对象指定XML文件创建Document对象
- 以Document对象为起点操作DOM树
xml
<?xml version="1.0" encoding="utf-8"?>
<PhoneInfo>
<Brand name="华为">
<Type name="U8650"/>
<Type name="HW123"/>
<Type name="HW321"/>
</Brand>
<Brand name="苹果">
<Type name="iPhone4"/>
</Brand>
</PhoneInfo>
显示phoneinfo.xml
文件中收藏的手机品牌和型号
java
package com.hsh.exercise2;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
public class Main {
public static void main(String[] args) throws Exception {
// 创建解析器工厂对象
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
// 解析器工厂对象创建解析器对象
DocumentBuilder db = factory.newDocumentBuilder();
// 解析 XML 文件
Document document = db.parse("./src/com/hsh/exercise2/phoneinfo.xml");
// 获取根元素
Element root = document.getDocumentElement();
// 获取所有 Brand 元素
NodeList brandList = root.getElementsByTagName("Brand");
// 遍历每个 Brand 节点并打印 name 属性
for (int i = 0; i < brandList.getLength(); i++) {
// 获取 Brand 元素
Element brand = (Element) brandList.item(i);
// 获取节点名称
System.out.print(brand.getNodeName()+": ");
// 获取 name 属性
System.out.print(brand.getAttribute("name")+",");
// 获取节点文本内容 由于是单标签所以为空。
// System.out.println(brand.getTextContent());
// 获取Brand 元素下面的 Type 元素
NodeList typeLists = brand.getElementsByTagName("Type");
for (int j = 0; j < typeLists.getLength(); j++) {
// 获取 Type 元素
Element type = (Element) typeLists.item(j);
// 获取节点名称
System.out.print(type.getNodeName()+": ");
// 获取 name 属性
System.out.print(type.getAttribute("name")+" ");
}
System.out.println();
}
// 输出结果
// Brand: 华为,Type: U8650 Type: HW123 Type: HW321
// Brand: 苹果,Type: iPhone4
}
}
保存XML文件
步骤
- 获得TransformerFactory对象
- 创建Transformer对象
- 创建DOMSource对象:包含XML信息
- 设置输出属性:编码格式
- 创建StreamResult对象:包含保存文件的信息
- 将XML保存到指定文件中
java
package com.hsh.exercise3;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.bootstrap.DOMImplementationRegistry;
import org.w3c.dom.ls.DOMImplementationLS;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
public class Main {
public static void main(String[] args) throws Exception {
//1. 创建工厂TransformerFactory对象
TransformerFactory factory = TransformerFactory.newInstance();
//2. 创建Transformer对象
Transformer transformer = factory.newTransformer();
// 3. 创建Document对象来创建新的XML文件,给XML文件设置内容,并将DOM结构添加到DOMsource对象
// 3.1 创建Document对象
DocumentBuilderFactory documentFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = documentFactory.newDocumentBuilder();
Document document = builder.newDocument();
// 3.2 创建XML结构(即给XML文件设置内容)
// 创建根元素
Element root = document.createElement("root");
// 加入到document中
document.appendChild(root);
// 创建子元素
Element child = document.createElement("child");
// 设置属性名和属性值
child.setAttribute("name", "hsh");
// 设置元素内容
child.appendChild(document.createTextNode("Text Content"));
//加入根节点树中
root.appendChild(child);
// 3.3 将文件添加到DOMsource对象中
DOMSource source = new DOMSource(document);
// 4. 给第二步 的Transformer对象设置输出属性
// 4.1设置是否再XML中添加缩进
transformer.setOutputProperty(OutputKeys.INDENT,"yes");
// 4.2指定输出方法
transformer.setOutputProperty(OutputKeys.METHOD, "xml");
// 4.3指定输出文件编码
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
// 5. 创建StreamResult对象,指定输出文件 StreamResult对象包含了文件信息
StreamResult result = new StreamResult("./src/com/hsh/exercise3/collection.xml");
// 6. 将DOMsource对象和StreamResult对象作为参数传递给Transformer对象的transform方法进行保存
transformer.transform(source, result);
System.out.println("保存成功!");
}
}
保存后的文件如下
xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<root>
<child name="hsh">Text Content</child>
</root>
添加DOM节点
添加手机收藏
- 添加新的Brand:三星
- 给Brand节点添加新的子标签Type:Note4
- 将Brand添加到DOM树中
练习:给手机收藏信息XML中添加新的手机信息,并将手机收藏信息保存到新文件中
添加新的Brand:三星
给Brand节点添加新的子标签Type:Note4
将Brand添加到DOM树中
java
package com.hsh.exercise3;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
public class Main {
public static void main(String[] args) throws Exception {
// 创建解析器工厂对象
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder db = factory.newDocumentBuilder();
Document document = db.parse("./src/com/hsh/exercise3/收藏信息.xml");
// 获取根元素
Element root = document.getDocumentElement();
System.out.println(root.getNodeName());
// 给根元素添加子元素Brand
Element brand = document.createElement("Brand");
brand.setAttribute("name","三星");
// 给Brand 元素添加子元素Type
Element type = document.createElement("Type");
// 设置Type的属性
type.setAttribute("name","Note4");
// 将Type添加到Brand中
brand.appendChild(type);
root.appendChild(brand);
// 创建工厂进行保存
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
// 设置格式化
// 缩进
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
// 指定输出
transformer.setOutputProperty(OutputKeys.METHOD, "xml");
// 指定编码
transformer.setOutputProperty(OutputKeys.ENCODING, "GB2312");
DOMSource domSource = new DOMSource(document);
StreamResult streamResult = new StreamResult("./src/com/hsh/exercise3/收藏信息.xml");
transformer.transform(domSource, streamResult);
System.out.println("保存成功");
}
}
修改/删除DOM节点
- 给所有的Brand标签添加id属性
- 获取Brand标签
- 调用setAttribute()方法添加属性
- 删除Brand值为"华为"的标签
- getElementsByTagName()方法获取Brand标签列表
- 获得Brand值为"华为"的标签对象
- 通过getParentNode()方法获得父节点对象
- 调用父节点的removeChild()方法删除节点
xml
<?xml version="1.0" encoding="GB2312"?>
<PhoneInfo>
<Brand name="华为">
<Type name="U8650"/>
<Type name="HW123"/>
<Type name="HW321"/>
</Brand>
<Brand name="苹果">
<Type name="iPhone4"/>
</Brand>
<Brand name="三星">
<Type name="Note4"/>
</Brand>
</PhoneInfo>
java
package com.hsh.exercise4;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
public class Main {
public static void main(String[] args) throws Exception {
// 创建解析器工厂对象
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder db = factory.newDocumentBuilder();
Document document = db.parse("./src/com/hsh/exercise4/收藏信息.xml");
// 获取根元素
Element root = document.getDocumentElement();
System.out.println(root.getNodeName());
// 获取root所有Brand子级标签
NodeList nodeList = root.getElementsByTagName("Brand");
for (int i = 0; i < nodeList.getLength(); i++) {
// 给每一个Brand标签加属性
Element brand = (Element) nodeList.item(i);
brand.setAttribute("id", (i+1)+"");
}
// 遍历子级标签删除 Brand的属性为华为的标签
for (int i = 0; i < nodeList.getLength(); i++) {
Element brand = (Element) nodeList.item(i);
if (brand.getAttribute("name").equals("华为")) {
// 得到父元素
Element parent = (Element) brand.getParentNode();
// 删除
parent.removeChild(brand);
}
}
// 创建工厂进行保存
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
// 设置格式化
// 缩进
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
// 指定输出
transformer.setOutputProperty(OutputKeys.METHOD, "xml");
// 指定编码
transformer.setOutputProperty(OutputKeys.ENCODING, "GB2312");
DOMSource domSource = new DOMSource(document);
StreamResult streamResult = new StreamResult("./src/com/hsh/exercise4/收藏信息.xml");
transformer.transform(domSource, streamResult);
System.out.println("保存成功");
}
}
结果如下。
xml
<?xml version="1.0" encoding="GB2312" standalone="no"?>
<PhoneInfo>
<Brand id="2" name="苹果">
<Type name="iPhone4"/>
</Brand>
<Brand id="3" name="三星">
<Type name="Note4"/>
</Brand>
</PhoneInfo>
SAX
基于事件的解析
适用于大数据量的XML文档
特点:占用资源少,内存消耗小
DOM4J
优点
非常优秀的Java XML API
性能优异、功能强大
开放源代码
Document:定义XML文档
Element:定义XML元素
Text:定义XML文本节点
Attribute:定义了XML 的属性
DOM4J下载和导入项目
1、下载相关jar包
方法一:去DOM4j官网
方法二:我的百度网盘提取
这官网有限制,有的同学访问不了可以通过百度网盘获取jar包。
通过网盘分享的文件:dom4j
链接: https://pan.baidu.com/s/1301CPh5h7yv1wa1ddvUqtQ?pwd=dsvj
提取码: dsvj
2、将下载的jar包导入到idea项目中去
3、将jar包添加到库中
点击确定,打开lib出现如下界面就说明添加成功。
DOM4j代码编写
获取所有值
解析器的构造方法
构造方法 | 说明 |
---|---|
public SAXReader() | xml解析器对象 |
解析器对象中的方法
方法 | 说明 |
---|---|
public Document read(String systemId) | 读取Xml文件 |
Document类中的方法
方法 | 说明 |
---|---|
Element getRootElement(); | 获取根元素对象 |
public String getName() | 获取元素标签名 |
public String attributeValue(QName qName) | 获取元素的属性名 |
public String getText() | 获取元素的内容 |
public List<Element> elements() | 获取所有一级子标签 |
public List elements(String name) | 获取所有一级子标签中的指定标签 |
public Element element(String name) | 获取一级子标签中的指定标签,若该标签有多个则获取第一个 |
xml
<?xml version="1.0" encoding="GB2312"?>
<PhoneInfo>
<Brand name="华为">
<Type name="U8650"/>
<Type name="HW123"/>
<Type name="HW321"/>
</Brand>
<Brand name="苹果">
<Type name="iPhone4"/>
</Brand>
</PhoneInfo>
java
package com.hsh.exercise5;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.util.List;
public class Main {
public static void main(String[] args) throws Exception {
//创建一个dom4j提供的解析器对象
SAXReader saxReader = new SAXReader();
//将xml文件读取到我们的内存当中,获取到这个Document 对象之后就可以读取里面的数据了
Document document = saxReader.read("./src/com/hsh/exercise5/收藏信息.xml");
System.out.println("---获取根元素---");
//1、获取根元素对象里面的所有信息,下面根据这个根元素对象去获取想要的数据
Element rootElement = document.getRootElement();
System.out.println(rootElement.getName());// PhoneInfo
System.out.println("---获取所有一级子标签---");
//2、获取根元素里面的一级子元素
List<Element> elements = rootElement.elements();
for (Element element : elements){
// 获取标签名
System.out.println(element.getName());
// 获取属性值
System.out.println(element.attributeValue("name"));
// 获取标签内容 这是空,因为没有设置内容。
System.out.println(element.getText());
}
// Brand
// 华为
// Brand
// 苹果
System.out.println("---获取所有一级子标签中的指定标签---");
//获取节点名称为books下所有子节点
List<Element> Elist = rootElement.elements("Brand");
for (Element element : Elist){
System.out.println(element.getName());
}
// Brand
// Brand
System.out.println("---获取一级子标签中的指定标签---");
// 如果重复,则获取第一个
Element element = rootElement.element("Brand");
System.out.println(element.getName());// Brand
}
}
修改值和删除值
方法 | 说明 |
---|---|
public Node detach() | 删除dom元素(标签) |
public void setAttributeValue(String name, String value) | 修改属性值 |
原文件
xml
<?xml version="1.0" encoding="GB2312"?>
<PhoneInfo>
<Brand name="华为">
<Type name="U8650"/>
<Type name="HW123"/>
<Type name="HW321"/>
</Brand>
<Brand name="苹果">
<Type name="iPhone4"/>
</Brand>
</PhoneInfo>
修改
java
package com.hsh.exercise5;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import java.io.FileWriter;
import java.util.List;
public class DelUpdXml {
public static void main(String[] args) throws Exception {
//创建一个dom4j提供的解析器对象
SAXReader saxReader = new SAXReader();
//将xml文件读取到我们的内存当中,获取到这个Document 对象之后就可以读取里面的数据了
Document document = saxReader.read("./src/com/hsh/exercise5/收藏信息.xml");
// 获取根元素对象
Element rootElement = document.getRootElement();
System.out.println(rootElement.getName());
// 获取所有一级子标签
List<Element> elements = rootElement.elements();
for (int i = 0; i < elements.size(); i++){
if(elements.get(i).attributeValue("name").equals("苹果")){
// 删除
elements.get(i).detach();
}else {
// 修改
elements.get(i).setAttributeValue("name", "华为手机");
}
}
// 设置XML文件的格式
OutputFormat outputFormat = OutputFormat.createPrettyPrint();
outputFormat.setEncoding("GB2312"); // 设置编码格式
// 写入XML文件的位置 以及指定的格式
XMLWriter xmlWriter=new XMLWriter(new FileWriter("./src/com/hsh/exercise5/exercise.xml"),outputFormat);
// 开始写入XML文件 写入Document对象
xmlWriter.write(document);
xmlWriter.close();
}
}
结果
java
<?xml version="1.0" encoding="GB2312"?>
<PhoneInfo>
<Brand name="华为手机">
<Type name="U8650"/>
<Type name="HW123"/>
<Type name="HW321"/>
</Brand>
</PhoneInfo>
添加值并保存文件
添加相关方法
方法 | 说明 |
---|---|
public static Element createElement(String name) | 创建元素(标签) |
Element addAttribute(String var1, String var2); | 设置元素的属性 |
public void add(Element element) | 添加元素()中是传入的子元素 |
保存文件相关方法
方法 | 说明 |
---|---|
public static OutputFormat createPrettyPrint() | 创建xml格式 |
public XMLWriter(Writer writer, OutputFormat format) | 参数分别是java的输出流和创建xml格式 |
public void write(Document doc) | 写入Document对象 |
public void close() | 关闭流 |
java
package com.hsh.exercise5;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;
import java.io.FileWriter;
public class WriteXML {
public static void main(String[] args) throws Exception {
// 创建根元素对象
Element rootElement = DocumentHelper.createElement("PhoneInfo");
// 创建子元素
Element Brand = DocumentHelper.createElement("Brand");
Brand.addAttribute("name","华为");
Element Type = DocumentHelper.createElement("Type");
// 设置子元素的属性
Type.addAttribute("name","P10");
Brand.add(Type);
rootElement.add(Brand);
// 创建Document对象
Document document = DocumentHelper.createDocument(rootElement);
// 设置XML文件的格式
OutputFormat outputFormat = OutputFormat.createPrettyPrint();
outputFormat.setEncoding("GB2312"); // 设置编码格式
// 写入XML文件的位置 以及指定的格式
XMLWriter xmlWriter=new XMLWriter(new FileWriter("./src/com/hsh/exercise5/exercise.xml"),outputFormat);
// 开始写入XML文件 写入Document对象
xmlWriter.write(document);
xmlWriter.close();
}
}
// 输出结果
xml
<?xml version="1.0" encoding="GB2312"?>
<PhoneInfo>
<Brand name="华为">
<Type name="P10"/>
</Brand>
</PhoneInfo>
案例:使用DOM4J解析XML文件
- 显示手机收藏信息
- 保存手机收藏信息
- 为手机收藏信息添加新的节点
- 修改/删除手机收藏信息节点
java
package com.hsh.exercise5;
public class Test {
public static void main(String[] args) throws Exception {
XmlServise xmlServise = new XmlServise("./src/com/hsh/exercise5/收藏信息.xml");
xmlServise.addElemnet("小米","小米15");
xmlServise.addElemnet("小米","小米14");
xmlServise.addElemnet("三星","酸14");
xmlServise.addElemnet("三星","三星14");
xmlServise.addElemnet("三星","小米14");
xmlServise.delType("三星","小米14");
xmlServise.delBrand("三星");
xmlServise.updateType("小米","小米14","小米13");
xmlServise.updateBrand("小米","三星");
xmlServise.updateBrand("三星","小米");
xmlServise.save();
xmlServise.print();
}
}
java
package com.hsh.exercise5;
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 java.io.FileWriter;
import java.util.List;
public class XmlServise {
public Document document;
public String url;
SAXReader saxReader = new SAXReader();
public XmlServise(String url) throws Exception {
this.url = url;
this.document =saxReader.read(url);
}
public void print(){
// 获取根节点
Element rootElement = document.getRootElement();
// 获取根节点的所有子标签
List<Element> elements = rootElement.elements();
for (int i = 0; i < elements.size(); i++){
System.out.print("手机品牌:");
// 获取属性值
System.out.print(elements.get(i).attributeValue("name")+",");
System.out.print("手机型号:");
for (int j = 0; j < elements.get(i).elements().size(); j++){
// 获取属性
System.out.print(elements.get(i).elements().get(j).attributeValue("name")+" ");
}
System.out.println();
}
}
public void save() throws Exception {
// 设置XML文件的格式
OutputFormat outputFormat = OutputFormat.createPrettyPrint();
outputFormat.setEncoding("UTF-8");
XMLWriter xmlWriter=new XMLWriter(new FileWriter(url),outputFormat);
xmlWriter.write(document);
xmlWriter.close();
}
public void addElemnet(String brand, String type) throws Exception{
// 获取根节点
Element rootElement = document.getRootElement();
boolean isBrandExist = false;
boolean isTypeExist = false;
// 遍历查找是否有brand的name属性的名字相同的
List<Element> elements = rootElement.elements();
for (int i = 0; i < elements.size(); i++){
if(elements.get(i).attributeValue("name").equals(brand)){
isBrandExist = true;
List<Element> elements1 = elements.get(i).elements();
for (int j = 0; j < elements1.size(); j++){
if(elements1.get(j).attributeValue("name").equals(type)){
isTypeExist = true;
}
}
}
}
if(isBrandExist){
if(isTypeExist){
// 不添加
}else {
// 遍历找到该品牌并添加
for (int i = 0; i < elements.size(); i++){
if(elements.get(i).attributeValue("name").equals(brand)){
Element element = DocumentHelper.createElement("type");
element.addAttribute("name",type);
elements.get(i).add(element);
}
}
}
}else {
Element element = DocumentHelper.createElement("brand");
element.addAttribute("name",brand);
Element element1 = DocumentHelper.createElement("type");
element1.addAttribute("name",type);
element.add(element1);
rootElement.add(element);
}
}
public void delType(String brand, String type) {
// 获取根节点
Element rootElement = document.getRootElement();
for (int i = 0; i < rootElement.elements().size(); i++){
if(rootElement.elements().get(i).attributeValue("name").equals(brand)){
for (int j = 0; j < rootElement.elements().get(i).elements().size(); j++){
if(rootElement.elements().get(i).elements().get(j).attributeValue("name").equals(type)){
rootElement.elements().get(i).elements().remove(j);
}
}
}
}
}
public void delBrand(String brand) {
// 获取根节点
Element rootElement = document.getRootElement();
for (int i = 0; i < rootElement.elements().size(); i++){
if(rootElement.elements().get(i).attributeValue("name").equals(brand)){
rootElement.elements().remove(i);
}
}
}
public void updateType(String brand, String name, String newName) {
// 获取根节点
Element rootElement = document.getRootElement();
for (int i = 0; i < rootElement.elements().size(); i++){
if(rootElement.elements().get(i).attributeValue("name").equals(brand)){
for (int j = 0; j < rootElement.elements().get(i).elements().size(); j++){
if(rootElement.elements().get(i).elements().get(j).attributeValue("name").equals(name)){
rootElement.elements().get(i).elements().get(j).addAttribute("name",newName);
}
}
}
}
}
public void updateBrand(String brand, String newBrand) {
// 获取根节点
Element rootElement = document.getRootElement();
for (int i = 0; i < rootElement.elements().size(); i++){
if(rootElement.elements().get(i).attributeValue("name").equals(brand)){
rootElement.elements().get(i).addAttribute("name",newBrand);
}
}
}
}
结果
xml
<?xml version="1.0" encoding="UTF-8"?>
<PhoneInfo>
<Brand name="华为">
<Type name="U8650"/>
<Type name="HW123"/>
<Type name="HW321"/>
</Brand>
<Brand name="苹果">
<Type name="iPhone4"/>
</Brand>
<brand name="小米">
<type name="小米15"/>
<type name="小米13"/>
</brand>
</PhoneInfo>
综合案例
java
<?xml version="1.0" encoding="GBK"?>
<citys>
<city id='010'>
<cityname>北京</cityname>
<cityarea>华北</cityarea>
<population>2114.8万人</population>
</city>
<city id='021'>
<cityname>上海</cityname>
<cityarea>华东</cityarea>
<population>2,500万人</population>
</city>
<city id='020'>
<cityname>广州</cityname>
<cityarea>华南</cityarea>
<population>1292.68万人</population>
</city>
<city id='028'>
<cityname>成都</cityname>
<cityarea>华西</cityarea>
<population>1417万人</population>
</city>
</citys>
(1)使用dom4j将信息存入xml中
(2)读取信息,并打印控制台
(3)添加一个city节点与子节点
(4)使用socket TCP协议编写服务端与客户端,
客户端输入城市ID,服务器响应相应城市信息
(5)使用socket TCP协议编写服务端与客户端,客户端要求用户输入city对象,服务端接收并使用dom4j保存至XML文件
请参考我的之前的博客 -----> java之网络编程
--->java之IO流
解析
这道题我的思路是
将客户端和服务端抽象成类,都有接收和发送功能。
然后把xml文件的添加,保存,查询都给保存起来。
citys.xml
xml
<?xml version="1.0" encoding="UTF-8"?>
<citys>
<city id="010">
<cityname>北京</cityname>
<cityarea>华北</cityarea>
<population>2114.8万人</population>
</city>
<city id="021">
<cityname>上海</cityname>
<cityarea>华东</cityarea>
<population>2,500万人</population>
</city>
<city id="020">
<cityname>广州</cityname>
<cityarea>华南</cityarea>
<population>1292.68万人</population>
</city>
<city id="028">
<cityname>成都</cityname>
<cityarea>华西</cityarea>
<population>1417万人</population>
</city>
</citys>
Server.java
java
package com.hsh.homework1;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public int port;
ServerSocket s;
Socket socket;
OutputStream os;
InputStream is;
public Server(int port) {
this.port = port;
}
public void start() throws Exception {
System.out.println("服务器启动成功");
s = new ServerSocket(port);
// 每使用一次 accept 说明一个客户端连接
// 再次使用就和上一次的客户端连接断开
socket = s.accept(); // 只 accept 一次
is = socket.getInputStream();
os = socket.getOutputStream();
System.out.println("客户端已连接");
}
public void stop() throws Exception {
s.close();
}
/**
* 发送消息 比如返回该城市的信息
* @param msg
* @throws Exception
*/
public void responseMsg(String msg) throws Exception {
System.out.println("服务器开始发送");
os.write((msg+"END").getBytes());
System.out.println("服务器发送成功");
}
/**
* 接收指令
* @return
* @throws Exception
*/
public String receiveMsg() throws Exception {
System.out.println("服务器开始接收");
byte[] b = new byte[1024];
int len;
String str = "";
boolean receivedEnd = false;
while (!receivedEnd && (len = is.read(b)) != -1) {
str += new String(b, 0, len);
if (str.contains("END")) {
str = str.replace("END", ""); // 去掉结束符
receivedEnd = true;
}
}
return str;
}
}
ServerTest.java
java
package com.hsh.homework1;
public class ServerTest {
public static void main(String[] args) throws Exception {
Server server = new Server(9999);
server.start();
XmlServise xmlServise = new XmlServise("src/com/hsh/homework1/citys.xml");
while (true) {
String msg = server.receiveMsg();
System.out.println("收到客户端指令: " + msg);
switch (msg){
case "1":
// 接收要查询的省份id
String provinceId = server.receiveMsg();
System.out.println("查询省份id: " + provinceId);
String cityInfo = xmlServise.getCityInfo(provinceId);
server.responseMsg(cityInfo);
System.out.println();
break;
case "2":
String addCityInfo =server.receiveMsg();
System.out.println("添加城市信息: " + addCityInfo);
String[] arr = Utils.split(addCityInfo);
xmlServise.addCity(arr[0], arr[1], arr[2], arr[3]);
xmlServise.save();
break;
default:
server.responseMsg("无效指令");
break;
}
}
}
}
Client.java
java
package com.hsh.homework1;
import java.io.OutputStream;
import java.lang.reflect.Array;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
public class Client {
String url;
int port;
Socket socket;
OutputStream os;
public Client(String url, int port) {
this.url = url;
this.port = port;
}
public void start() throws Exception {
socket = new Socket(url, port);
System.out.println("客户端启动成功");
}
/**
* 接收消息
* @return
* @throws Exception
*/
public String receiveMsg() throws Exception {
System.out.println("客户端开始接收");
socket.getInputStream();
byte[] b = new byte[1024];
int len;
String str = "";
// 循环读取,直到读取到结束符,不然可能会卡在这不往下走。
boolean receivedEnd = false;
while (!receivedEnd && (len = socket.getInputStream().read(b)) != -1) {
str += new String(b, 0, len);
if (str.contains("END")) {
str = str.replace("END", ""); // 去掉结束符
receivedEnd = true;
}
}
System.out.println("客户端接收成功");
return str;
}
/**
* 关闭
*
* @throws Exception
*/
public void stop() throws Exception {
os.close();
socket.close();
}
/**
* 发送消息
*
* @param instructions
* @throws Exception
*/
public void sendInstructions(String instructions) throws Exception {
System.out.println("客户端开始发送");
os = socket.getOutputStream();
os.write((instructions + "END").getBytes());
System.out.println("客户端发送成功");
}
}
ClientTest.java
java
package com.hsh.homework1;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class ClientTest {
public static void main(String[] args) throws Exception {
Client client = new Client("127.0.0.1", 9999);
client.start();
Scanner sc = new Scanner(System.in);
while (true){
System.out.println("请选择操作");
System.out.println("1.输入城市ID查看城市信息");
System.out.println("2.输入城市id,省份,省份归属地,人口数");
System.out.println("3.退出");
switch (sc.next()){
case "1":
client.sendInstructions("1");
System.out.println("请输入城市ID");
// client.sendID(sc.next());
client.sendInstructions(sc.next());
System.out.println(client.receiveMsg());
break;
case "2":
client.sendInstructions("2");
System.out.println("请输入城市ID");
String id =sc.next();
System.out.println("请输入省份");
String province =sc.next();
System.out.println("请输入省份归属地");
String area =sc.next();
System.out.println("请输入人口数");
String population =sc.next();
List<String> list = new ArrayList<>();
list.add(id);
list.add(province);
list.add(area);
list.add(population);
client.sendInstructions(list.toString());
// client.sendCityInfo(id,province,area,population);
break;
case "3":
System.out.println("退出");
client.stop();
return;
default:
System.out.println("请输入正确的选项");
break;
}
}
}
}
XmlServise.java
java
package com.hsh.homework1;
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 java.io.FileWriter;
public class XmlServise {
public Document document;
public String url;
SAXReader saxReader = new SAXReader();
public XmlServise(String url) throws Exception {
this.url = url;
this.document =saxReader.read(url);
}
public String printXml() {
// 直接输出xml内容
return document.asXML();
}
public void print() {
// 直接输出xml内容
// System.out.println(document.asXML());
// System.out.println();
Element rootElement = document.getRootElement();
for (int i = 0; i < rootElement.elements().size(); i++){
Element element = rootElement.elements().get(i);
System.out.println(element.attributeValue("id"));
for (int j = 0; j < element.elements().size(); j++){
Element element1 = element.elements().get(j);
System.out.println(" "+element1.getText());
}
}
}
public void addCity(String number, String cityname, String cityarea, String population) {
Element rootElement = document.getRootElement();
// 创建city元素
Element city = DocumentHelper.createElement("city");
city.addAttribute("id",number);
// 创建cityname元素
Element citynameElement = DocumentHelper.createElement("cityname");
citynameElement.setText(cityname);
// 创建cityarea元素
Element cityareaElement = DocumentHelper.createElement("cityarea");
cityareaElement.setText(cityarea);
// 创建population元素
Element populationElement = DocumentHelper.createElement("population");
populationElement.setText(population);
city.add(citynameElement);
city.add(cityareaElement);
city.add(populationElement);
rootElement.add(city);
}
/**
* 获取城市信息
* @param provinceId
* @return
*/
public String getCityInfo(String provinceId) {
Element rootElement = document.getRootElement();
for (int i = 0; i < rootElement.elements().size(); i++){
Element element = rootElement.elements().get(i);
if(element.attributeValue("id").equals(provinceId)){
StringBuilder stringBuilder = new StringBuilder();
for (int j = 0; j < element.elements().size(); j++){
Element element1 = element.elements().get(j);
stringBuilder.append(element1.getText());
stringBuilder.append(" ");
}
return stringBuilder.toString();
}
}
return "没有此城市";
}
public void save() throws Exception{
OutputFormat outputFormat = OutputFormat.createPrettyPrint();
outputFormat.setEncoding("UTF-8");
XMLWriter xmlWriter=new XMLWriter(new FileWriter(url),outputFormat);
xmlWriter.write(document);
xmlWriter.close();
}
}
Utils.java
java
package com.hsh.homework1;
public class Utils {
public static String[] split(String str) {
String[] arr = str.substring(1, str.length() - 1).split(",");
for (int i = 0; i < arr.length; i++) {
arr[i] = arr[i].trim();
System.out.println(arr[i]);
}
return arr;
}
}
运行结果
java
客户端启动成功
请选择操作
1.输入城市ID查看城市信息
2.输入城市id,省份,省份归属地,人口数
3.退出
1
客户端开始发送
客户端发送成功
请输入城市ID
010
客户端开始发送
客户端发送成功
客户端开始接收
客户端接收成功
北京 华北 2114.8万人
请选择操作
1.输入城市ID查看城市信息
2.输入城市id,省份,省份归属地,人口数
3.退出
2
客户端开始发送
客户端发送成功
请输入城市ID
035
请输入省份
河南
请输入省份归属地
华中
请输入人口数
1234万人
客户端开始发送
客户端发送成功
请选择操作
1.输入城市ID查看城市信息
2.输入城市id,省份,省份归属地,人口数
3.退出
1
客户端开始发送
客户端发送成功
请输入城市ID
035
客户端开始发送
客户端发送成功
客户端开始接收
客户端接收成功
河南 华中 1234万人
请选择操作
1.输入城市ID查看城市信息
2.输入城市id,省份,省份归属地,人口数
3.退出
java
服务器启动成功
客户端已连接
服务器开始接收
收到客户端指令: 1
服务器开始接收
查询省份id: 010
服务器开始发送
服务器发送成功
服务器开始接收
收到客户端指令: 2
服务器开始接收
添加城市信息: [035, 河南, 华中, 1234万人]
035
河南
华中
1234万人
服务器开始接收
收到客户端指令: 1
服务器开始接收
查询省份id: 035
服务器开始发送
服务器发送成功
服务器开始接收
xml
<?xml version="1.0" encoding="UTF-8"?>
<citys>
<city id="010">
<cityname>北京</cityname>
<cityarea>华北</cityarea>
<population>2114.8万人</population>
</city>
<city id="021">
<cityname>上海</cityname>
<cityarea>华东</cityarea>
<population>2,500万人</population>
</city>
<city id="020">
<cityname>广州</cityname>
<cityarea>华南</cityarea>
<population>1292.68万人</population>
</city>
<city id="028">
<cityname>成都</cityname>
<cityarea>华西</cityarea>
<population>1417万人</population>
</city>
<city id="035">
<cityname>河南</cityname>
<cityarea>华中</cityarea>
<population>1234万人</population>
</city>
</citys>