什么是xml
xml(extensible markup language),可扩展标记语言,是一种简单的基于文本的语言,旨在以村文本格式存储和传输数据,他代表可扩展标记语言。
- 1、作为系统的配置文件
- 2、作为一种特殊的数据结构,在网络中进行传输
特点
xml与操作系统、编程语言的开发平台无关
实现不同系统之间的数据交换
xml作用
- 数据交互
- 配置应用程序和网站
- ajax基石
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[..内容... ]]>,里面的内容可以随便写
<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
根目录只能叫做书并且可以有多个书的子元素
书只能由书名作者售价构成
<!element 书架 (书+)> <!element 书 (书名,作者,售价)> <!element 书名 (#pcdata)> <!element 作者 (#pcdata)> <!element 售价 (#pcdata)>
②:在需要编写的xml文件中导入该dtd约束文档
<!doctype 书架 system "data.dtd">
③:然后xml文件,就必须按照dtd约束文档指定的格式进行编写,否则报错
<?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 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 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 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 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
文件中收藏的手机品牌和型号
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保存到指定文件中
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 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树中
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 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>
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 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官网
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 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>
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 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>
修改
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(); } }
结果
<?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() | 关闭流 |
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 version="1.0" encoding="gb2312"?> <phoneinfo> <brand name="华为"> <type name="p10"/> </brand> </phoneinfo>
案例:使用dom4j解析xml文件
- 显示手机收藏信息
- 保存手机收藏信息
- 为手机收藏信息添加新的节点
- 修改/删除手机收藏信息节点
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(); } }
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 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>
综合案例
<?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文件
解析
这道题我的思路是
将客户端和服务端抽象成类,都有接收和发送功能。
然后把xml文件的添加,保存,查询都给保存起来。
citys.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
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
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
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
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
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
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; } }
运行结果
客户端启动成功
请选择操作
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.退出
服务器启动成功
客户端已连接
服务器开始接收
收到客户端指令: 1
服务器开始接收
查询省份id: 010
服务器开始发送
服务器发送成功服务器开始接收
收到客户端指令: 2
服务器开始接收
添加城市信息: [035, 河南, 华中, 1234万人]
035
河南
华中
1234万人
服务器开始接收
收到客户端指令: 1
服务器开始接收
查询省份id: 035
服务器开始发送
服务器发送成功服务器开始接收
<?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>
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
发表评论