XML即Extensible Markup Language,可扩展标记语言,主要的应用有三方面:
1.存储数据,这个没什么好说的
2.传输数据,纯文本文件,不存在转换格式的麻烦
3.软件配置,比如今后学的配置tomcat虚拟目录映射等就用到了
那么直奔主题:
一、XML文件结构
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<!DOCTYPE root SYSTEM "path.dtd">
<root>
.......
</root>
version是告诉浏览器使用什么版本的XML解析器,encoding是来设置文件的编码,standalone表明XML是否引入了其他非XML文件如css、dtd文件
<!DOCTYPE ...>为内部或外部引入的DTD文件,DTD为Document Type Definition,用来定义合法的XML文件结构
<root></root>为XML的根节点,只能有一个,里面存储自定义的标签元素
1.标签的书写规范
XML语法严格,对大小写敏感,不可间接嵌套;标签名不能以数字、_下划线、xml开头;标签名中不能出现空格、:
在XML中<,>,&,“,及逗号都是特殊字符,如要在标签内部使用需要使用内部实体代替
<label attr=""></label>←跟html书写很像不再赘述
<?xml version="1.1" encoding="UTF-8"?>
<studentList>
<student id="A01" class="A">
<name>小明</name>
<age>19</age>
<gender>man</gender>
<score>
<subject name="Advanced Mathematics">90</>
<subject name="College English">85</>
<subject name="C++Programming">88</>
</score>
</student>
<student id="A02" class="B">
<name>小红</name>
<age>20</age>
<gender>woman</gender>
<score>
<subject name="Data Structure">80</subject>
<subject name="JavaProgramming">90</subject>
</score>
</student>
</studentList>
一个简单的XML文件
2.CDATA区
所有 XML 文档中的文本均会被解析器解析,只有 CDATA(Unparsed Character Data) 区段中的文本会被解析器忽略。
作用:因为XML中有特殊字符的存在(< > &等),所以我们在用XML传送JavaScript代码或者其他数据时,只要将内容声明在CDATA区中就不会被浏览器解析,出错。
使用方法:
<![CDATA[your data]]>
3.处理指令
<?xml-stylesheet type="text/css" href="path.css"?>
<?xml-stylesheet type="text/xsl href="path.xsl"?>
↑没什么好说的
二、DTD语法
在XML文件内使用DTD格式为:
<!DOCTYPE 根标签名称 [
<!ELEMENT>
<!ATTLIST>
<!ENTITY>
]>
在外部引入为:
<!DOCTYPE 根标签名字 SYSTEM ”path.dtd“>
1.<!ELEMENT>定义元素
书写格式:<!ELEMENT 标签名 类别/(内容)>
其中类别值有EMPTY、ANY
()内填写子标签数量、顺序描述,或对文本内容描述(#PCDATA)
对于子标签数量,有+、*、?、|修饰,类似正则表达式不再赘述
对于顺序描述,(name,age,gender,score)即表达了子标签必须以此顺序定义
PCDATA为Parsed Character Data可解析的字符内容,当标签内只有文本内容(不含嵌套的标签时)可以使用(#PCDATA)
EMPTY,ANY表示标签内容可以是空的,空的或纯文本
对上述XML文件进行定义
<!DOCTYPE studentList [
<!ELEMENT studenList (student+)>
<!ELEMENT student (name,(age?),(gender?),(score?))> //名字最重要,其他信息可有可无
<!ELEMENT name (#PCDATA)>
<!ELEMENT age (#PCDATA)>
<!ELEMENT gender (#PCDATA)>
<!ELEMENT score (subject*)>
<!ELEMENT subject ANY> //这样就表示支持<s></s>、<s>100</s>这两种写法
]>
DTD定义中必须将所有标签元素全部定义完、属性也是一样的,上述DTD定义不完整,还缺少属性定义
2.<!ATTLIST>定义属性
<!ATTLIST 标签名 属性名 属性类型 属性约束>
属性类型有
CDATA 属性值是字符数据
ID 属性值是唯一的一个以英文字母开头的ID值
IDREF 属性值与同一标签内ID型属性的值相等
(en1|en2...) 属性值是枚举中的一个
<!ATTLIST label name ID #REQUIRED nickname IDREF #REQUIRED>
则说明属性nickname的值必须与name属性的值相同
属性约束有
“ ” 如果属性为空,则默认等于“ ”内值
#REQUIRED 属性值是必需要填写的,不能为空
#IMPLIED 不必需,可空
#FIXED “ ” 属性值必填,必须与“ ”内值一样
<!ATTLIST student id ID #REQUIRED class (A|B) #REQUIRED>
id属性值为必填的ID类型,class属性值为必填的、值只能为A或B的枚举类型
<!ATTLIST subject name CDATA #IMPLIED>
name属性的值为选填的字符类型
所以对开头XML的完整DTD定义为
<!DOCTYPE root [
<!ELEMENT>
...
<!ATTLIST>
...
]>
3.<!ENTITY>定义实体
类似c语言#define
引用实体
<!ENTITY d "doctor">
<occupation>&d;</occupation> → 即为<occupation>doctor</occupation>
使用方法: &+实体+;
预定义好的引用实体:
& \& < \< > \> " \" ' \'
参数实体
<!ENTITY % order "name,age,gender,score">
顾名思义,参数实体只能用来替换DTD定义标签中的参数
<!ELEMENT student (%order;)> → <!ELEMENT student (name,age,gender,score)>
参数实体定义位置必须位于使用之前,参数实体无法在内部DTD使用,只能在外部使用,一个XML文件只能有一个DTD文件约束
三、使用java解析XML
java不像js一样提供对XML文档的原生支持,我们通过使用dom4j的API来对XML进行操作
0.提前做好的准备工作
写好一份XML文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE studentList SYSTEM "Demo.dtd">
<studentList>
<student id="A01" class="A">
<name>小明</name>
<age>19</age>
<gender>man</gender>
<score>
<averageScore>84.8</averageScore>
<subject name="AdvancedMathematics">82</subject>
<subject name="CollegeEnglish">86</subject>
<subject name="C++">94</subject>
<subject name="DataStructure">77</subject>
<subject name="Java">85</subject>
</score>
<identity minority="">
<position>monitor</position>
<politicalStatus>communist youth league member</politicalStatus>
</identity>
</student>
<student id="A02" class="B">
<name>小红</name>
<age>20</age>
<gender>woman</gender>
<score>
<averageScore>91</averageScore>
<subject name="AdvencedMathematics">97</subject>
<subject name="CollegeEnglish">89</subject>
<subject name="C++">82</subject>
<subject name="DataStructure">95</subject>
<subject name="Java">92</subject>
</score>
<identity minority="壮族">
<position></position>
<politicalStatus>party member</politicalStatus>
</identity>
</student>
</studentList>
1.读取XML文件
SAXReader saxReader = new SAXReader();
Document xml = saxReader.read(XMLparse.class.getClassLoader().getResource("Demo.xml"));
//使用类加载器可以避免复杂的路径。。。其实也没方便多少
//saxReader.read(new File("C:\Users\15421\eclipse-workspace\XMLparse\src\Demo.xml"))
System.out.println(xml==null?"加载失败":"加载成功");
2.实现增功能
/*--------创建小刚同学的XML结构--------*/
Element rootElement = xml.getRootElement();
System.out.println(rootElement.getName());
Element newElement = DocumentHelper.createElement("student");
newElement.addAttribute("id", "A03");
newElement.addAttribute("class", "A");
newElement.addElement("name").setText("小刚");
System.out.println("id: "+newElement.attributeValue("id")+" class: "+newElement.attributeValue("class")+" name: "+newElement.element("name").getText());
/*----------获取节点列表,在小红前添加小刚---------*/
List<Element> list = rootElement.elements("student");
Iterator<Element> iterator = list.iterator(); //使用集合类的迭代器iterator进行遍历
int index = 0;
while(iterator.hasNext()) {
Element element = iterator.next();
if(element.elementText("name").equals("小红")) {
System.out.println("小红在第"+index+"个上");
list.add(index,newElement); //插入小刚
break; //注意,在某些情况下不break会造成无限循环的后果(因为list已经变化了),这里倒没有影响
}
++index;
}
System.out.println("添加后:");
iterator = list.iterator(); //迭代器用完了就要换一个(不管原来List变化没有),这里重新加载了一遍
while(iterator.hasNext()) {
System.out.println(iterator.next().elementText("name"));
}
3.实现删功能
iterator = list.iterator();
int index = 0;
while(iterator.hasNext()) {
if(iterator.next().elementText("name").equals("小刚")) {
list.remove(index);
break;
}
++index;
}
iterator = list.iterator();
System.out.println("删除后:");
for(Element element:list){
System.out.println(element.elementText("name"));
}
4.实现查、改功能
/*--------------查找----------------*/
//使用xpath快速定位标签
System.out.println("Java成绩:");
String xpath = "//subject[@name='Java']"; //在全体人员中查找name属性为Java的subject标签
List<Node> subjects = xml.selectNodes(xpath);
for(Node node:subjects) {
System.out.println(node.getText());
}
//使用迭代器遍历(雾) 你喜欢就好
iterator = list.iterator();
for(;iterator.hasNext();) {
List<Element> list2 = iterator.next().elements();
Iterator<Element> iterator2 = list2.iterator();
for(;iterator2.hasNext();) {
Element element = iterator2.next();
if(element.getName().equals("score")) {
List<Element> list3 = element.elements();
Iterator<Element> iterator3 = list3.iterator();
for(;iterator3.hasNext();) {
Element element2 = iterator3.next();
if(element2.getName().equals("subject")&&element2.attributeValue("name").equals("Java")) {
System.out.println(element2.getText());
}
}
}
}
}
/*-------------修改标签属性值/内容-------------*/
//1.修改小明少数民族为苗族
//2.修改全体人员职位为student
xpath = "student[@id='A01']//identity";
Element identity = (Element)xml.selectSingleNode(xpath);
identity.addAttribute("minority", "苗族");
//↑这里失败了,原因是select方法返回的是Node类型,强制转换后虽然能使用addAttribute方法但是报错空指针
//以后再研究吧
xpath = "//position";
List<Node> position_list = xml.selectNodes(xpath);
for(Node node:position_list) {
node.setText("student");
}
5.向硬盘中输出修改的XML
OutputStream os = new FileOutputStream(new File("C:\\Users\\15421\\Desktop\\demo_out.xml"));
\\是转义符哦
OutputFormat of = OutputFormat.createPrettyPrint();
//createCompactPrint 将去掉所有缩进
XMLWriter xml_out = new XMLWriter(os,of);
xml_out.write(xml);
xml_out.close();
小结
最近学的好杂啊。。。快爆炸了,我要写物理实验了。