java中XML的使用

文章目录

什么是XML

XML(EXtensible Markup Language),可扩展标记语言,是一种简单的基于文本的语言,旨在以村文本格式存储和传输数据,他代表可扩展标记语言。

1、作为系统的配置文件

2、作为一种特殊的数据结构,在网络中进行传输

特点

XML与操作系统、编程语言的开发平台无关

实现不同系统之间的数据交换

XML作用

  1. 数据交互
  2. 配置应用程序和网站
  3. 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中书写"<'

"&"等,可能会出现冲突,导致报错,此时可以用如下特殊字符替代。

指定字符 特殊字符 含义
&lt; < 小于
&gt; > 大于
&amp; & 小于
' ' 单引号
&quot; " 双引号

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 &gt; 2 &amp;&amp; 3 &lt; 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)

  1. 基于XML文档树结构的解析
  2. 适用于多次访问的XML文档
  3. 特点:比较消耗资源

SAX(内置解析XML)

  1. 基于事件的解析
  2. 适用于大数据量的XML文档
  3. 特点:占用资源少,内存消耗小

DOM4J

  1. 非常优秀的Java XML API
  2. 性能优异、功能强大
  3. 开放源代码

​​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文件步骤

  1. 创建解析器工厂对象
  2. 解析器工厂对象创建解析器对象
  3. 解析器对象指定XML文件创建Document对象
  4. 以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文件

步骤

  1. 获得TransformerFactory对象
  2. 创建Transformer对象
  3. 创建DOMSource对象:包含XML信息
  4. 设置输出属性:编码格式
  5. 创建StreamResult对象:包含保存文件的信息
  6. 将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节点

添加手机收藏

  1. 添加新的Brand:三星
  2. 给Brand节点添加新的子标签Type:Note4
  3. 将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节点
  1. 给所有的Brand标签添加id属性
    • 获取Brand标签
    • 调用setAttribute()方法添加属性
  2. 删除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文件

  1. 显示手机收藏信息
  2. 保存手机收藏信息
  3. 为手机收藏信息添加新的节点
  4. 修改/删除手机收藏信息节点
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>
相关推荐
休息一下接着来2 分钟前
C++ 条件变量与线程通知机制:std::condition_variable
开发语言·c++·算法
爱尚你199312 分钟前
Java 泛型与类型擦除:为什么解析对象时能保留泛型信息?
java
小哈里22 分钟前
【pypi镜像源】使用devpi实现python镜像源代理(缓存加速,私有仓库,版本控制)
开发语言·python·缓存·镜像源·pypi
努力学习的小廉26 分钟前
【C++】 —— 笔试刷题day_29
开发语言·c++·算法
电商数据girl35 分钟前
酒店旅游类数据采集API接口之携程数据获取地方美食品列表 获取地方美餐馆列表 景点评论
java·大数据·开发语言·python·json·旅游
天天打码35 分钟前
python版本管理工具-pyenv轻松切换多个Python版本
开发语言·python
CircleMouse36 分钟前
基于 RedisTemplate 的分页缓存设计
java·开发语言·后端·spring·缓存
ktkiko1142 分钟前
顶层架构 - 消息集群推送方案
java·开发语言·架构
楠奕42 分钟前
python中使用neo4j
开发语言·python·neo4j
zybsjn1 小时前
后端系统做国际化改造,生成多语言包
java·python·c#