XML的应用
- 使用实例:qq消息发送,利于程序的维护
- 用来表示生活中的关系
XML的语法
- XML的文档声明
创建一个文件,后缀名为 .XML
如果要写XML,第一步必须要写一个文档声明(写了文档声明之后,才能写xml的内容)
属性:
version : 1.0 和 1.1 ,但是我们只用1.0 因为1.1不向下兼容
encoding : xml编码 gbk utf-8 iso8859-1
standalone : 表示这个xml文档是否可以独立存在。
<?xml version="1.0" encoding="gbk"?> // xml文档声明
- XML的属性命名规范
一个xml中,只能有一个根标签,其他标签都在这个标签下面
xml中区分大小写
不能以下划线和数字作为开头
不能以xml 、Xml 、 XML开头
不能包含冒号和空格。
- XML的注释
<!-- xml中的注释 —>
注意的是注释是不能嵌套的。
第一行第一列必须放文档声明,注释也不能放在第一行的第一列。
- XML的特殊字符
符号 | xml转义字符 |
---|---|
& | & amp; |
< | & lt; |
> | & gt; |
" | & quot; |
’ | & apos; |
- XML的CDATA区
当文档主体中出现了大量的转义字符的时候,我们可以使用cdata区,可以直接进行转义,不需要用字符。
写法:
这就是 : <![CDATA[if(a < n){}]]>
- XML的PI指令
可以在xml中设置css样式
写法: <?xml-stylesheet type="text/css" href="1.css"?>
但是对中文的标签样式不起作用
- XML的约束
xml的约束一共有两种: DTD约束 和 schema约束
DTD快速入门
- 选创建一个文件,后缀名为 .dtd
书写步骤:
(1)看xml中有多少个元素,那就在dtd中先写多少个<!ELEMENT>
(2)判断元素是简单元素还是复杂元素
- 简单元素: 即没有子元素 <!ELEMENT 元素名称 (子元素)>
- 复杂元素 : 有子元素 <!ELEMENT 元素名称 (#PCDATA)>
(3)在xml中引入dtd文件 < !DOCTYPE 根元素 SYSTEM “dtd文件路径”>
//xml文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE person SYSTEM "1.dtd">
<person>
<name>骚包</name>
<age>20</age>
</person>
// dtd文件
<!ELEMENT person (name,age)>
<!ELEMENT name (#PCDATA)>
<!ELEMENT age (#PCDATA)>
dtd文件的三种引用方式
(1)引入外部dtd文件
< !DOCTYPE 根元素 SYSTEM “dtd文件路径”>
(2) 使用内部dtd文件
<?xml version="1.0" encoding="UTF-8"?>
<!-- <!DOCTYPE person SYSTEM "1.dtd"> -->
<!DOCTYPE person [
<!ELEMENT person (name,age)>
<!ELEMENT name (#PCDATA)>
<!ELEMENT age (#PCDATA)>
]>
<person>
<name>骚包</name>
<age>20</age>
<!-- <a>aaa</a> -->
</person>
(3)使用外部的dtd文件(网络上的一些dtd文件)
< !DOCTYPE 根元素 PUBLIC “dtd名称” “dtd文档对象URL” >
后面学习的框架struct2 使用配置文件 使用外部dtd文件
使用dtd来定义元素
- 语法格式:<!ELEMENT 元素名称 约束>
简单元素定义:
(1) (#PCDATA) : 约束name是字符串类型
(2)EMPTY : 元素为空 (没有内容)
(3)ANY : 任意
复杂元素定义:
(1)<!ELEMENT person (name,age,sex)> 子元素只能出现一次
(2)<!ELEMENT person (name+,age?,sex*)>
+ 号 : 一次或者多次
? 号 : 零次或者一次
* 号 : 零次或者多次
(3)<!ELEMENT person (name | age | sex)> “ | ” : 表示这么多中只能出现其中一个
使用dtd来定义属性
语法:<!ATTLIST 元素名称
属性名称 属性类型 属性的约束
>
属性的类型
- CDATA : 字符串
- 枚举 : 表示只能在一定范围内它能出现的值,但是每次只能出现其中的一个。
**(aa|bb|cc)
** 红绿灯效果
- ID : 只能以字母和下划线开头
属性的约束
- #REQUIRED : 属性必须存在
- #IMPLIED : 属性可有可无
- #FIXED : 表示一个固定值 #FIXED “aaa”
- 表示属性的值必须是aaa
- 直接值 : 默认值
实体的定义 :
- <!ENTITY npos " ">
调用 &npos; 就可以直接输出空格。
- 注意点:实体的定义需要写在内部引用里面。如果写在外部的dtd里面,在某些浏览器里面下,内容可能不能用。
xml解析的介绍
xml是标记型文档
js使用dom解析标记型文档?
- 根据html中层级结构,在内存中分配一个属性的结构,把html中的标签,属性和文本都封装成对象;
- document对象、element对象、属性对象、文本对象、Node节点对象。
xml的解析方式: dom 和 sax
dom解析xml
------ 根据xml中的层级结构,在内存中分配一个树形结构,即把xml中的每一个部分封装都封装成对象。
缺点: 但是使用dom方式进行解析xml的时候,如果文件过大,就可能造成内存的溢出。
优点: 很方便进行增删改操作。
sax解析xml
采用事件驱动,边读边解析。
------ 从上到下,一行一行的解析,解析到某一个对象,把对象的名称返回。
缺点: 使用sax方式进行解析,不能进行增删改操作。
优点: 不会造成内存溢出,方便实现查询,
- 想要解析xml,我们便需要一个解析器,
- 不同公司和组织呢,提供了 针对 dom 和 sax 当时的解析器,通过api的方式提供。
- sun公司针对dom和sax提供了解析器 ----- jaxp
- dom4j组织,针对dom和sax方式提供了解析器 ----- dom4j (实际开发中使用最多的一种解析器。包含了jdom)
- jdom组织, 针对dom和sax方式提供了解析器 ------ jdom
JAXP的API使用
- jaxp是 java se 中的一部分。
- jaxp解析器在 javax.xml.parsers 包下面。
- 四个类,分别针对dom和sax解析器的类
- --------- DOM :
- ------------------ DocumentBuilder : 解析器类
- ------------------ DocumentBuilderFactory : 解析器工厂类
- --------- SAX:
- ------------------ SAXparser: 解析器类
- ------------------ SAXparserFactory : 解析器工厂类
使用JAXP实现查询
- 给定初始xml文件
<?xml version="1.0" encoding="UTF-8"?>
<person>
<p1>
<name>张三</name>
<age>20</age>
</p1>
<p1>
<name>李四</name>
<age>30</age>
</p1>
</person>
- 查询xml中的所有name元素的值
package cn.itcast.jaxptest;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
/**
* @program: Test
* @description:
* @author: 作者
* @create: 2021-05-17 10:38
*/
public class TestJaxp {
public static void main(String[] args) throws Exception{
// 查询所有的name元素的值
/**
* 1、创建解析器工厂
* 2、根据解析器工厂创建解析器
* 3、解析xml返回document
* 4、得到所有的name元素
* 5、返回集合,遍历集合,返回得到的每一个name元素
*/
// 1.创建解析器工厂
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
// 2.创建解析器
DocumentBuilder builder = builderFactory.newDocumentBuilder();
// 3.解析xml返回document
Document document = builder.parse("XmlTest/src/person.xml");
// 4.得到所有的name元素
NodeList list = document.getElementsByTagName("name");
// 遍历集合
for(int i=0;i<list.getLength();i++){
Node name1 = list.item(i); // 得到每一个name元素
String s = name1.getTextContent();
System.out.println(s);
}
}
}
- 修改添加xml文件
// 对p1进行添加一个sex标签
public static void addSex() throws Exception{
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = builderFactory.newDocumentBuilder();
Document document = builder.parse("XmlTest/src/person.xml");
// 得到p1
NodeList list = document.getElementsByTagName("p1");
// 得到第一个p1
Node node = list.item(0);
// 创建标签
Element sex1 = document.createElement("sex");
// 创建文本
Text text1 = document.createTextNode("女");
// 把文本1添加到标签下
sex1.appendChild(text1);
// 把sex1添加到p1下面去。
node.appendChild(sex1);
// 回写xml
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
transformer.transform(new DOMSource(document) , new StreamResult("XmlTest/src/person.xml"));
}
- 使用jaxp修改节点
// 对p1下面的节点sex进行修改成男
public static void modifySex() throws Exception{
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = builderFactory.newDocumentBuilder();
Document document = builder.parse("XmlTest/src/person.xml");
// 获得节点并且修改
Node sex1 = document.getElementsByTagName("sex").item(0);
sex1.setTextContent("男");
// 回写
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
transformer.transform(new DOMSource(document) , new StreamResult("XmlTest/src/person.xml"));
}
- 使用JAXP遍历xml中所有的标签
// 打印所有的标签
public static void listElement() throws Exception {
// 获得dom解析器
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = builderFactory.newDocumentBuilder();
Document document = builder.parse("XmlTest/src/person.xml");
//进行递归调用
list1(document);
}
private static void list1(Node node) {
// 判断是否是元素类型
if(node.getNodeType() == node.ELEMENT_NODE){
System.out.println(node.getNodeName());
}
NodeList list = node.getChildNodes();
for(int i=0;i<list.getLength();i++){
list1(list.item(i));
}
}
Schema约束
- 完全符合xml中的语法,在xml中,只能使用一个dtd约束,但是可以使用多个schema约束。
- dtd约束的支持的数据类只能是string类型,但是我们的schema约束可以有多个数据类型。
- schema语法更加的复杂,不好学习。
- schema文件后缀名为.xsd
创建schema文件
(1)、看xml文件里面有多少个元素
有多少个元素就写多少个 < element > 标签。
(2)、看开始的是简单元素还是复杂元素
如果是复杂元素,那就要这样写,然后简单元素存放在复杂元素下方
<?xml version="1.0" encoding="UTF-8" ?>
<schema
xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.itcast.cn//20210519"
elementFormDefault="qualified"
>
<element name="person">
<complexType>
<sequence>
<element name="name" type="string"/>
<element name="age" type="int"/>
</sequence>
</complexType>
</element>
</schema>
(4)、在xml文件中,引入schema约束文件。
<?xml version="1.0" encoding="UTF-8" ?>
<schema
xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.itcast.cn//20210519"
elementFormDefault="qualified"
>
<element name="person">
<complexType>
<sequence>
<element name="name" type="string"/>
<element name="age" type="int"/>
</sequence>
</complexType>
</element>
</schema>
schema约束属性
<sequence> 表示元素必须按照顺序出现。
<all> 表示元素只能出现一次。
<choice> 表示元素只能出现其中的一个
maxOccurs = "unbounded" 表示该简单元素可以出现无数次。
<any> 表示可以出现任意元素。
元素属性的定义:
<attribute name="id1" type="int" use="required" />
sax解析xml文件过程
当解析到开始标签的时候,会自动执行startElement方法,参数qName:返回标签名称。
当解析到文本内容的时候,执行characters方法,通过string构造器返回内容
当解析到结束标签的时候,执行endElement方法,通过qName,返回标签名称。
使用JAXP的sax方式进行解析xml文件
- sax不能实现增删改操作。只能进行查询操作。
- 打印出整个文档。
public class TestSax {
public static void main(String[] args) throws Exception{
/**
* 1、创建一个解析器工厂
* 2、创建解析器
* 3、执行parse方法
*
* 4、需要自己创建一个类,来继承DefaultHandler
* 5、重写类里面的那个三个方法。
*/
SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
SAXParser saxParser = saxParserFactory.newSAXParser();
saxParser.parse("XmlTest/src/p1.xml",new MyDefault1());
}
}
class MyDefault1 extends DefaultHandler {
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
//super.startElement(uri, localName, qName, attributes);
System.out.print("<" + qName + ">");
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
//super.endElement(uri, localName, qName);
System.out.print("</" + qName + ">");
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
//super.characters(ch, start, length);
System.out.print(new String(ch,start,length));
}
}
- 通过重写里面的主要的三个方法,就可以打印出整个文档了。
- 打印所有的name标签内容
public class MyDefault2 extends DefaultHandler {
boolean flag = false;
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
flag = qName.equals("name");
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
flag = false;
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
if(flag) System.out.println(new String(ch,start,length));
}
}
使用 dom4j 来解析xml
- 先下载好dom4j jar包,然后导入
- 然后学习里面的api使用,然后我们来试试查询xml中所有内容。
public class testDom4j {
public static void main(String[] args) throws Exception{
/**
* 1、创建解析器
* 2、得到document
* 3、得到根节点
*
* 4、得到p1
* 5、得到p1下面的name
* 6、得到name的值
*/
SAXReader saxReader = new SAXReader();
Document document = saxReader.read("XmlTest/src/p1.xml");
Element root = document.getRootElement();
// 得到p1
List<Element> list = root.elements("p1");
// 遍历list
for(Element element : list){
Element name1 = element.element("name");
System.out.println(name1.getText());
}
}
}
- 得到第二name里面的值
public class testDom4j {
public static void main(String[] args) throws Exception{
/**
* 1、创建解析器
* 2、得到document
* 3、得到根节点
*
* 4、得到p1
* 5、得到p1下面的name
* 6、得到name的值
*/
SAXReader saxReader = new SAXReader();
Document document = saxReader.read("XmlTest/src/p1.xml");
Element root = document.getRootElement();
// 得到p1
List<Element> list = root.elements("p1");
Element p2 = list.get(1);
Element name2 = p2.element("name");
System.out.println(name2.getText());
}
}
使用dom4j实现添加操作
// 向xml文件中添加sex标签
public static void addSex() throws Exception{
/**
* 1、创建解析器
* 2、得到document
* 3、得到根节点
*
* 4、获取第一个p1标签
* 5、在p1下面添加元素
* 6、在添加完成以后的元素下面添加文字。
* 7、回写xml
*/
SAXReader saxReader = new SAXReader();
Document document = saxReader.read("XmlTest/src/p1.xml");
Element root = document.getRootElement();
Element p1 = root.element("p1");
Element sex1 = p1.addElement("sex");
sex1.setText("女");
// 回写xml
OutputFormat format = OutputFormat.createPrettyPrint(); // 可以有缩进的效果
XMLWriter xmlWriter = new XMLWriter(new FileOutputStream("XmlTest/src/p1.xml"), format);
xmlWriter.write(document);
xmlWriter.close();
}
- 回写很重要哦,还有出现流文件要记得关闭哦;
在特定位置进行添加元素
// 在第一个p1标签里面的age标签前进行添加<school>标签
public static void addschool() throws Exception{
SAXReader saxReader = new SAXReader();
Document document = saxReader.read("XmlTest/src/p1.xml");
Element root = document.getRootElement();
Element p1 = root.element("p1");
List<Element> list = p1.elements();
Element school = DocumentHelper.createElement("school");
school.setText("湖南警察学院");
list.add(0,school);
// 回写
OutputFormat format = OutputFormat.createPrettyPrint();
XMLWriter xmlWriter = new XMLWriter(new FileOutputStream("XmlTest/src/p1.xml"),format);
xmlWriter.write(document);
xmlWriter.close();
}
对常用方法的利用进行封装
public class Dom4jUtils {
// 路径的封装
public static final String PATH = "XmlTest/src/p1.xml" ;
// 返回document
public static Document getDocument(String s) {
try {
SAXReader saxReader = new SAXReader();
return (Document) saxReader.read(s);
}catch (Exception e){
e.printStackTrace();
}
return null;
}
// 回写xml
public static void xmlWriters( String path , Document document) {
try{
OutputFormat format = OutputFormat.createPrettyPrint();
XMLWriter xmlWriter = new XMLWriter(new FileOutputStream(path),format);
xmlWriter.write(document);
xmlWriter.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
使用dom4j对xml文件进行修改
// 修改age里面的值。
public static void modify() throws Exception {
Document document = Dom4jUtils.getDocument(Dom4jUtils.PATH);
Element root = document.getRootElement();
Element p1 = root.element("p1");
Element age1 = p1.element("age");
age1.setText("66");
// 对xml进行回写操作
Dom4jUtils.xmlWriters(Dom4jUtils.PATH , document);
}
使用dom4j对xml进行删除操作
// 删除school 标签
public static void delSchool() throws Exception {
// 获得document
Document document = Dom4jUtils.getDocument(Dom4jUtils.PATH);
// 得到根元素
Element root = document.getRootElement();
Element p1 = root.element("p1");
p1.remove(p1.element("school"));
// 回写 xml
Dom4jUtils.xmlWriters(Dom4jUtils.PATH , document);
}
使用dom4j来获取标签的属性值
// 获取属性值
public static void getValues() throws Exception {
Document document = Dom4jUtils.getDocument(Dom4jUtils.PATH);
Element root = document.getRootElement();
Element p1 = root.element("p1");
System.out.println(p1.attributeValue("id1"));
}
使用dom4j来支持xpath操作
- 直接进行获取某个元素
- 第一种形式 : /AAA/DDD/BBB : 表示一层一层,A下面是D,D下面是B
- 第二种://BBB 表示和这个名称相同,表示名称是BBB,都可以得到。
- 第三种:/* 表示所有元素。
- 第四种: /BBB[0] 表示第一个bbb元素。
- 第五种: //BBB[@id] : 表示只要BBB元素上面有id属性,都得到。
- 第六种://BBB[@id=“b1”] : 表示名称是BBB,在BBB上面有id属性。并且这个id属性是b1
那么我们想要用它的话呢,需要先导入支持xpath的jar包。
然后就可使用了
public class testXpath {
public static void main(String[] args) throws Exception {
name1();
}
// 使用xpath获取xml中第一个name的值
public static void name1() throws Exception{
Document document = Dom4jUtils.getDocument(Dom4jUtils.PATH);
assert document != null;
Node node = document.selectSingleNode("//p1[@id1='aaa']/name");
if(node != null) System.out.println(node.getText());
}
// 查询xml中所有name的值
public static void allName() throws Exception {
Document document = Dom4jUtils.getDocument(Dom4jUtils.PATH);
assert document != null;
List<Node> list = document.selectNodes("//name");
for(Node node : list){
System.out.println(node.getText());
}
}
}
学生管理系统实战
- 我们先来建立原始的xml文件
<?xml version="1.0" encoding="UTF-8"?>
<student>
<stu>
<id>100</id>
<name>张三</name>
<age>20</age>
</stu>
<stu>
<id>101</id>
<name>李四</name>
<age>30</age>
</stu>
</student>
- 然后我们通过jaxp进行实现他的增删查改
package service;
import com.sun.javafx.collections.ElementObservableListDecorator;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import org.w3c.dom.NodeList;
import vo.Student;
import java.io.FileOutputStream;
import java.util.List;
/**
* @program: Test
* @description:
* @author: 作者
* @create: 2021-05-20 20:54
*/
public class stuService {
public static void main(String[] args) throws Exception{
//addStu(new Student("102","王老五","40"));
//delStu("102");
Student ans = getStu("100");
System.out.println(ans.getId());
System.out.println(ans.getName());
System.out.println(ans.getAge());
}
// 增加
public static void addStu(Student student) throws Exception{
SAXReader saxReader = new SAXReader();
Document document = saxReader.read("student/src/student.xml");
Element root = document.getRootElement();
Element stu = root.addElement("stu");
Element id1 = stu.addElement("id");
Element name1 = stu.addElement("name");
Element age1 = stu.addElement("age");
id1.setText(student.getId());
name1.setText(student.getName());
age1.setText(student.getAge());
// 回写xml
OutputFormat format = OutputFormat.createPrettyPrint();
XMLWriter xmlWriter = new XMLWriter(new FileOutputStream("student/src/student.xml"),format);
xmlWriter.write(document);
xmlWriter.close();
}
// 删除
public static void delStu(String id) throws Exception {
Document document = Dom4jUtils.getDocument(Dom4jUtils.PATH);
Element root = document.getRootElement();
assert document != null;
List<Node> list = document.selectNodes("//id");
for(Node node : list){
if(node.getText().equals(id)){
root.remove(node.getParent());
break;
}
}
// 回写xml
Dom4jUtils.xmlWriters(Dom4jUtils.PATH,document);
}
// 查询
public static Student getStu(String id) throws Exception {
Document document = Dom4jUtils.getDocument(Dom4jUtils.PATH);
assert document != null;
Element root = document.getRootElement();
List<Node> list = document.selectNodes("//id");
for(Node node : list){
if(node.getText().equals(id)){
String name = node.getParent().element("name").getText();
String age = node.getParent().element("age").getText();
return new Student(id,name,age);
}
}
return null;
}
}
欧拉,到这里基本上xml就结束拉。告辞拉