一、XML是什么?有什么用?
XML是指可扩展标记语言(eXtensible MarkupLanguage),它是一种标记语言。它被设计的宗旨是描述数据(XML),而非显示数据(HTML)。
目前遵循的是W3C组织于2000年发布的XML1.0规范
应用场景:
1、描述数据
2、作为配置文件存在
二、XML的基本语法
1、文档声明:很重要
在编写XML文档时,需要先使用文档声明来声明XML文档。且必须出现在文档的第一行。
作用:告知解析器,我是一个XML文档。
最简单的声明语法:
<?xml version="1.0"?> 中间不要加空格,后面加?号
当我们写好的一个xml文件写入内存的时候会转换为二进制保存,这个时候会查码表,记事本保存的时候是gbk,而保存的时候默认查码表时用的是utf-8,
这个时候我们就可以用encoding属性:默认是UTF-8 <?xml version="1.0" encoding="GBK"?>,这样就可以解决乱码等问题。
standlone属性:该xml文件是否独立存在。
2、元素(标签)
XML语法非常严格。不能够省略结束标签。
一个XML文档必须有且仅有一个根标签
XML中不会忽略主体内容中出现的空格和换行
元素(标签)的名称可以包含字母、数字、减号、下划线和英文句点,但必须遵守下面的一些规范:
l 严格区分大小写;<P> <p>
l 只能以字母或下划线开头;abc _abc
l 不能以xml(或XML、Xml等)开头----W3C保留日后使用;
l 名称字符之间不能有空格或制表符;ab
l 名称字符之间不能使用冒号; (有特殊用途)
3、元素的属性
属性值一定要用引号(单引号或双引号)引起来
元素中属性不允许重复
4、注释
XML中的注释语法为:<!--这是注释-->
XML声明之前不能有注释 不允许第一行写注释(不同于java)
5、CDATA区
Character Data:字符数据。
语法:
<![CDATA[
内容
]]>
作用:
被CDATA包围的内容,都是普通的文本字符串。
6、特殊字符
特殊字符 替代符号
& &
< <
> >
" "
' &apos
7、处理指令(PI:ProcessingInstruction)(了解)
XML声明就是一种处理指令
处理指令:<?指令名称 属性?>
1. <?xml version="1.0" encoding="GBK"?>
2. <?xml-stylesheet type="text/css" href="main.css"?>
3. <world>
4. <chinese>中国</chinese>
5. <america>美国</america>
6. <japan>小日本</japan>
7. </world>
三、XML的约束
XML可以自定义。如果作为配置文件。
格式良好的XML文档:遵循XML语法的。
有效的XML文档:遵守约束的XML文档。
有效的XML文档必定是格式良好的,但良好的不一定是有效的。
1、DTD约束:(能看懂DTD即可)
a、DTD(Document Type Definition):文档类型定义
作用:约束XML的书写规范
注意:dtd可以写在单独的文件中,扩展名是dtd,且必须使用UTF-8编码进行保存。
b、XML文档中如何导入DTD约束文档(XML外部)
l dtd文档在本地:
<!DOCTYPE 根元素 SYSTEM "dtd文件的路径">
l dtd文档在网络上:
<!DOCTYPE 根元素 PUBLIC "dtd名称" "DTD文档的URL链接地址">
c、了解:也可以把DTD的内容直接写在XML文档内部。
写在XML文档内部,dtd没有编码要求。(了解)
1. <?xml version="1.0" encoding="GBK"?>
2. <!DOCTYPE 书架 [
3. <!ELEMENT 书架 (书+)>
4. <!ELEMENT 书 (书名,作者,售价)>
5. <!ELEMENT 书名 (#PCDATA)>
6. <!ELEMENT 作者 (#PCDATA)>
7. <!ELEMENT 售价 (#PCDATA)>
8. <!ATTLIST 书
9. ISBN ID #REQUIRED
10. COMMENT CDATA #IMPLIED
11. "指令汇公司"
12. >
13. "指令汇公司">
14. ]>
15. <书架>
16. "a" COMMENT="ddd" 出版社="指令汇公司">
17. <书名>Java就业培训教程</书名>
18. <作者>©right;</作者>
19. 39.00元</售价>
20. </书>
21. "b">
22. <书名>JavaScript网页开发</书名>
23. <作者>张孝祥</作者>
24. 28.00元</售价>
25. </书>
26. </书架>
练习:
1. <?xml version="1.0" encoding="GBK"?>
2. <!DOCTYPE TVSCHEDULE [
3. <!ELEMENT TVSCHEDULE (CHANNEL+)>
4. <!ELEMENT CHANNEL (BANNER,DAY+)>
5. <!ELEMENT BANNER (#PCDATA)>
6. <!ELEMENT DAY (DATE,(HOLIDAY|PROGRAMSLOT+)+)>
7. <!ELEMENT HOLIDAY (#PCDATA)>
8. <!ELEMENT DATE (#PCDATA)>
9. <!ELEMENT PROGRAMSLOT (TIME,TITLE,DESCRIPTION?)>
10. <!ELEMENT TIME (#PCDATA)>
11. <!ELEMENT TITLE (#PCDATA)>
12. <!ELEMENT DESCRIPTION (#PCDATA)>
13.
14. <!ATTLIST TVSCHEDULE NAME CDATA #REQUIRED>
15. <!ATTLIST CHANNEL CHAN CDATA #REQUIRED>
16. <!ATTLIST PROGRAMSLOT VTR CDATA #IMPLIED>
17. <!ATTLIST TITLE RATING CDATA #IMPLIED>
18. <!ATTLIST TITLE LANGUAGE CDATA #IMPLIED>
19. ]>
20.
21. <TVSCHEDULE NAME="NN">
22. "CC">
23. <BANNER>AAA</BANNER>
24. <DAY>
25. 2015</DATE>
26. <PROGRAMSLOT>
27. <TIME>ee</TIME>
28. <TITLE>bb</TITLE>
29. <DESCRIPTION>cc</DESCRIPTION>
30. </PROGRAMSLOT>
31. </DAY>
32. </CHANNEL>
33. </TVSCHEDULE>
2、Schema约束(新,有替换DTD的趋势)
四、利用Java代码解析XML文档
1、解析方式
l DOM:Document Object Model,文档对象模型。这种方式是W3C推荐的处理XML的一种标准方式。
缺点:必须读取整个XML文档,才能构建DOM模型,如果XML文档过大,造成资源的浪费。
优点:适合对XML中的数据进行操作(CRUD)。
l SAX:Simple API for XML。这种方式不是官方标准,属于开源社区XML-DEV,几乎所有的XML解析器都支持它。
2、解析工具
JAXP:
DOM或SAX方式进行解析XML。API在JDK之中。
Dom4J:(推荐)
是开源组织推出的解析开发包。(牛,大家都在用,包括SUN公司的一些技术的实现都在用)
五、JAXP进行DOM方式解析XML基本练习
1、JAXP简介:
开发包:(JDK中)
DOM:W3C。org.w3c.dom.* DOM规范。(接口/抽象类)
SAX:开源组织。org.xml.sax.* SAX规范。(接口/抽象类)
JAXP:javax.xml.*
2、利用JAXP进行DOM方式解析
1. //JAXP进行DOM方式解析的基本操作
2. public class JaxpDemo1 {
3.
4. public static void main(String[] args) throws Exception {
5. //得到解析器
6. DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
7. DocumentBuilder builder = factory.newDocumentBuilder();
8. //通过解析器就可以得到代表整个内存中XML的Document对象
9. "src/book.xml");
10. test8(document);
11. }
12. // 1、得到某个具体的节点内容: 刘丰
13. private static void test1(Document document){
14. "作者");
15. 0);
16. System.out.println(authorNode.getTextContent());
17. }
18. // 2、遍历所有元素节点:打印元素的名称
19. private static void test2(Node node){
20. //确定node的类型
21. //方式一
22. // if(node.getNodeType()==Node.ELEMENT_NODE){
23. // //是元素
24. // }
25. //方式二
26. if(node instanceof Element){
27. //是元素
28. Element e = (Element)node;
29. //打印元素名称
30. }
31. //判断有没有子节点
32. NodeList nl = node.getChildNodes();
33. for(int i=0;i<nl.getLength();i++){
34. Node n = nl.item(i);
35. test2(n);
36. }
37. }
38. // 3、修改某个元素节点的主体内容:<售价>39.00元</售价>--->10元
39. private static void test3(Document document) throws Exception{
40. //得到售价
41. "售价").item(0);
42. "10元");
43. //更新XML文件
44. TransformerFactory tf = TransformerFactory.newInstance();
45. Transformer t = tf.newTransformer();
46. //构建输入源:
47. new DOMSource(document);
48. //构建目标:
49. new StreamResult("src/book.xml");
50.
51. t.transform(source, result);
52. }
53.
54. // 4、向指定元素节点中增加子元素节点:第一本书添加子元素 <出版社>黑马程序员</出版社>
55. private static void test4(Document document) throws Exception{
56. //创建:<出版社>黑马程序员</出版社>
57. "出版社");
58. "黑马程序员");
59. //得到书,把新节点挂上去
60. "书").item(0);
61. bookNode.appendChild(e);
62. //更新XML文件
63. TransformerFactory tf = TransformerFactory.newInstance();
64. Transformer t = tf.newTransformer();
65. //构建输入源:
66. new DOMSource(document);
67. //构建目标:
68. new StreamResult("src/book.xml");
69.
70. t.transform(source, result);
71. }
72. // 5、向指定元素节点上增加同级元素节点:第一本书<售价>前面添加<批发价>30</批发价>
73. private static void test5(Document document) throws Exception{
74. //创建新节点
75. "批发价");
76. "30元");
77. //找到<售价>
78. "售价").item(0);
79. //父标签:调用insertBefore(新节点,参考节点);
80.
81. Node bookNode = priceNode.getParentNode();
82. bookNode.insertBefore(e, priceNode);
83. //更新XML文件
84. TransformerFactory tf = TransformerFactory.newInstance();
85. Transformer t = tf.newTransformer();
86. //构建输入源:
87. new DOMSource(document);
88. //构建目标:
89. new StreamResult("src/book.xml");
90.
91. t.transform(source, result);
92. }
93. // 6、删除指定元素节点:删除批发价
94. private static void test6(Document document) throws Exception{
95. "批发价").item(0);
96. priceNode.getParentNode().removeChild(priceNode);
97. //更新XML文件
98. TransformerFactory tf = TransformerFactory.newInstance();
99. Transformer t = tf.newTransformer();
100. //构建输入源:
101. new DOMSource(document);
102. //构建目标:
103. new StreamResult("src/book.xml");
104.
105. t.transform(source, result);
106. }
107. // 7、操作XML文件属性:书籍添加一个属性:ISBN=“ABC”
108. private static void test7(Document document) throws Exception{
109. "书").item(0);
110. if(bookNode instanceof Element){
111. Element e = (Element)bookNode;
112. "ISBN", "ABC");
113. }
114. //更新XML文件
115. TransformerFactory tf = TransformerFactory.newInstance();
116. Transformer t = tf.newTransformer();
117. //构建输入源:
118. new DOMSource(document);
119. //构建目标:
120. new StreamResult("src/book.xml");
121.
122. t.transform(source, result);
123. }
124. // 8、操作XML文件属性:获取ISBN=“ABC”
125. private static void test8(Document document) throws Exception{
126. "书").item(0);
127. if(bookNode instanceof Element){
128. Element e = (Element)bookNode;
129. "ISBN"));
130. }
131. }
132. }
3、DOM小案例
a、建立xml文件
1. <?xml version="1.0" encoding="UTF-8" standalone="no"?><exam>
2. "222" idcard="111">
3. <name>刘丰</name>
4. <location>湖北</location>
5. 100</grade>
6. </student>
7. <student examid="dsf" idcard="2342"><name>dsf</name><location>435</location><grade>654.0</grade></student></exam>
b、代码要精细。要分层。
DAO:com.zhilinghui.dao
VIEW:com.zhilinghui.view
JavaBean:com.zhilinghui.domain(领域)
c、设计JavaBean
1. public class Student {
2. private String idcard;
3. private String examid;
4. private String name;
5. private String location;
6. private float grade;
7.
8. public Student(){}
9.
10. public Student(String idcard, String examid, String name, String location,
11. float grade) {
12. super();
13. this.idcard = idcard;
14. this.examid = examid;
15. this.name = name;
16. this.location = location;
17. this.grade = grade;
18. }
19. public String getIdcard() {
20. return idcard;
21. }
22. public void setIdcard(String idcard) {
23. this.idcard = idcard;
24. }
25. public String getExamid() {
26. return examid;
27. }
28. public void setExamid(String examid) {
29. this.examid = examid;
30. }
31. public String getName() {
32. return name;
33. }
34. public void setName(String name) {
35. this.name = name;
36. }
37. public String getLocation() {
38. return location;
39. }
40. public void setLocation(String location) {
41. this.location = location;
42. }
43. public float getGrade() {
44. return grade;
45. }
46. public void setGrade(float grade) {
47. this.grade = grade;
48. }
49. @Override
50. public String toString() {
51. return "Student [idcard=" + idcard + ", examid=" + examid + ", name="
52. ", location=" + location + ", grade=" + grade + "]";
53. }
54.
55. }
d、开发DAO
数据访问对象
1. public class StudentDao {
2. /**
3. * 保存学生信息到XML文件中
4. * @param student 封装要保存的信息
5. * @return 成功返回true,否则false
6. * @throws Exception
7. */
8. public boolean save(Student student) throws Exception{
9.
10. if(student==null)
11. throw new IllegalArgumentException("学生参数不能为null");
12.
13. boolean result = false;
14. /*
15. * <student idcard="111" examid="222">
16. <name>刘丰</name>
17. <location>湖北</location>
18. <grade>100</grade>
19. </student>
20. */
21.
22. //得到Document
23. Document document = JaxpUtil.getDocument();
24. //创建一个student元素:设置属性
25. "student");//<student></student>
26. "idcard", student.getIdcard());
27. "examid", student.getExamid());//<student idcard="111" examid="222"></student>
28. //创建name,location,grade元素,挂到student上
29. "name");
30. //<name>刘丰</name>
31. "location");
32. //<location>湖北</location>
33. "grade");
34. "");//<grade>100</grade>
35. studentE.appendChild(nameE);
36. studentE.appendChild(locationE);
37. studentE.appendChild(gradeE);
38. //把student挂接到exam上
39. "exam").item(0);
40. examNode.appendChild(studentE);
41. //写到xml中
42. JaxpUtil.wirte2xml(document);
43. //更改result的取值为true
44. true;
45.
46. return result;
47. }
48. /**
49. * 根据姓名删除信息
50. * @param name
51. * @return 成功返回true,否则false
52. */
53. public boolean delete(String name){
54. boolean result = false;
55. try {
56. Document document = JaxpUtil.getDocument();
57. //得到所有的name元素
58. "name");
59. //遍历:比对文本内容是否和参数一样
60. for(int i=0;i<nl.getLength();i++){
61. if(nl.item(i).getTextContent().equals(name)){
62. //如果找到了一样的:爷爷干掉爸爸
63. nl.item(i).getParentNode().getParentNode().removeChild(nl.item(i).getParentNode());
64. //写回xml
65. JaxpUtil.wirte2xml(document);
66. break;
67. }
68.
69. }
70. true;
71. catch (Exception e) {
72. throw new RuntimeException(e);//异常转译
73. }
74. return result;
75. }
76. /**
77. * 根据准考证号查询学生信息
78. * @param examid
79. * @return 没有返回null
80. */
81. public Student findByExamId(String examid){
82. null;
83. try {
84. Document document = JaxpUtil.getDocument();
85. //得到所有的student元素
86. "student");
87. //遍历:比对examid属性
88. for(int i=0;i<nl.getLength();i++){
89. Element e = (Element) nl.item(i);
90. if(e.getAttribute("examid").equals(examid)){
91. // 找到了:创建student对象,并设置相应的值
92. new Student();
93. "idcard"));
94. student.setExamid(examid);
95. "name").item(0).getTextContent());
96. "location").item(0).getTextContent());
97. "grade").item(0).getTextContent()));
98. break;
99. }
100. }
101. catch (Exception e) {
102. throw new RuntimeException(e);//异常转译
103. }
104. return student;
105. }
106. }
e、测试DAO的功能
1. public class StudentDaoTest {
2.
3. public static void main(String[] args) {
4. new StudentDao();
5.
6. // Student student = new Student();
7. // student.setIdcard("333");
8. //
9. // dao.save(student);
10.
11. // Student s = dao.findByExamId("444");
12. // System.out.println(s);
13.
14. "阿娇"));
15. }
16.
17. }
f、开发界面
1. ublic class Main {
2.
3. public static void main(String[] args) throws Exception {
4. new StudentDao();
5.
6. "a、添加用户\tb、查询成绩\tc、删除用户");
7. "请输入操作类型:");
8. new BufferedReader(new InputStreamReader(System.in));
9. //读取用户输入的a|b|c
10. if("a".equals(op)){
11. //添加
12. "请输入学生姓名:");
13. String name = br.readLine();
14. "请输入学生准考证号:");
15. String examid = br.readLine();
16. "请输入学生身份证号:");
17. String idcard = br.readLine();
18. "请输入学生所在地:");
19. String location = br.readLine();
20. "请输入学生成绩:");
21. String grade = br.readLine();
22.
23. //封装数据
24. new Student(idcard, examid, name, location, Float.parseFloat(grade));
25. //调用dao
26. boolean b = dao.save(student);
27. if(b){
28. "------添加成功------");
29. else{
30. "------服务器忙------");
31. }
32. else if("b".equals(op)){
33. //查询
34. "请输入学生准考证号:");
35. String examid = br.readLine();
36. Student s = dao.findByExamId(examid);
37. if(s==null)
38. "------查无此人------");
39. else
40. System.out.println(s);
41. else if("c".equals(op)){
42. //删除
43. "请输入要删除的学生姓名:");
44. String name = br.readLine();
45. boolean b = dao.delete(name);
46. if(b){
47. "------删除成功------");
48. else{
49. "------服务器忙------");
50. }
51. else{
52. "你傻呀,输错了");
53. }
54. }
55.
56. }
sax解析原理
在使用 DOM 解析 XML 文档时,需要读取整个 XML 文档,在内存中构架代表整个 DOM 树的Doucment对象,从而再对XML文档进行操作。此种情况下,如果 XML 文档特别大,就会消耗计算机的大量内存,并且容易导致内存溢出。
SAX解析允许在读取文档的时候,即对文档进行处理,而不必等到整个文档装载完才会文档进行操作。
SAX采用事件处理的方式解析XML文件,利用 SAX 解析 XML 文档,涉及两个部分:解析器和事件处理器: 解析器可以使用JAXP的API创建,创建出SAX解析器后,就可以指定解析器去解析某个XML文档。 解析器采用SAX方式在解析某个XML文档时,它只要解析到XML文档的一个组成部分,都会去调用事件处理器的一个方法,解析器在调用事件处理器的方法时,会把当前解析到的xml文件内容作为方法的参数传递给事件处理器。 事件处理器由程序员编写,程序员通过事件处理器中方法的参数,就可以很轻松地得到sax解析器解析到的数据,从而可以决定如何对数据进行处理
基本解析操作
//1解析器
SAXParser parse = SAXParserFactory.newInstance().newSAXParser();
//2获取xml读取器
XMLReader reader = parse.getXMLReader();
//3注册内容处理器
reader.setContentHandler(new ContentHandler1());
//4读取xml文档
reader.parse("src/book.xml");
封装读取书
封装到BOOK.java
public class sax3 {
//封装读取书
public static void main(String[] args) throws Exception {
SAXParser parse=SAXParserFactory.newInstance().newSAXParser();
XMLReader reader=parse.getXMLReader();
final List<Book> books=new ArrayList<Book>();
reader.setContentHandler(new DefaultHandler(){
private Book b=null;
private String currentTagName=null;
public void startElement(String uri, String localName,
String qName, Attributes attributes) throws SAXException {
if("书".equals(qName)){
b=new Book();
}
currentTagName=qName;
}
public void endElement(String uri, String localName, String qName)
throws SAXException {
if("书".equals(qName)){
books.add(b);
b=null;
}
currentTagName=null;
}
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
if("书名".equals(currentTagName)){
b.setName(new String(ch,start,length));
}
if("作者".equals(currentTagName)){
b.setAuthor(new String(ch,start,length));
}
if("售价".equals(currentTagName)){
b.setPrice(new String(ch,start,length));
}
}
});
reader.parse("src/book.xml");
for(Book book:books)
System.out.println(book);
}
}
dom4j解析原理
Dom4j是一个简单、灵活的开放源代码的库。Dom4j是由早期开发JDOM的人分离出来而后独立开发的。与JDOM不同的是,dom4j使用接口和抽象基类,虽然Dom4j的API相对要复杂一些,但它提供了比JDOM更好的灵活性。 Dom4j是一个非常优秀的Java XML API,具有性能优异、功能强大和极易使用的特点。现在很多软件采用的Dom4j,例如Hibernate,包括sun公司自己的JAXM也用了Dom4j。 使用Dom4j开发,需下载dom4j相应的jar文件。
1、基本练习 a、拷贝jar包: 把dom4j-1.6.1.jar加入到你的classpath中 b、基本操作
// 1、得到某个具体的节点内容:jinpingmei
@Test
public void test1() throws Exception{
SAXReader reader = new SAXReader();
Document document = reader.read("src/book.xml");
//首先要得到根元素
Element root = document.getRootElement();
List<Element> bookElements = root.elements();
// Element bookName = (Element) bookElements.get(0).elements().get(0);
// System.out.println(bookName.getText());
System.out.println(bookElements.get(0).elementText("书名"));
}
// 2、遍历所有元素节点:名称
@Test
public void test2()throws Exception{
SAXReader reader = new SAXReader();
Document document = reader.read("src/book.xml");
//首先要得到根元素
Element root = document.getRootElement();
treeWalk(root);
}
public void treeWalk(Element rootElement){//递归
System.out.println(rootElement.getName());
int nodeCount = rootElement.nodeCount();//子节点的数量
for(int i=0;i<nodeCount;i++){
Node node = rootElement.node(i);//得到一个子节点
if(node instanceof Element){
treeWalk((Element)node);
}
}
}
// 3、修改某个元素节点的主体内容:<售价>10元---20
@Test
public void test3()throws Exception{
SAXReader reader = new SAXReader();
Document document = reader.read("src/book.xml");
//首先要得到根元素
Element root = document.getRootElement();
//得售价
Element priceElement = root.element("书").element("售价");
priceElement.setText("21元");
//写回XML文档
// OutputFormat format = OutputFormat.createCompactFormat();//去除空格回车换行,适合运行期间
OutputFormat format = OutputFormat.createPrettyPrint();//漂亮的格式 默认编码是UTF-8
XMLWriter writer = new XMLWriter(new FileOutputStream("src/book.xml"), format);
writer.write(document);
writer.close();
}
// 4、向指定元素节点中增加子元素节点:<出版社>黑马程序员
@Test
public void test4()throws Exception{
SAXReader reader = new SAXReader();
Document document = reader.read("src/book.xml");
//首先要得到根元素
Element root = document.getRootElement();
//得售价
Element bookElement = root.element("书");
//创建新元素
Element publisherElement = DocumentHelper.createElement("出版社");
publisherElement.setText("黑马程序员");
bookElement.add(publisherElement);
//写回XML文档
// OutputFormat format = OutputFormat.createCompactFormat();//去除空格回车换行,适合运行期间
OutputFormat format = OutputFormat.createPrettyPrint();//漂亮的格式 默认编码是UTF-8
XMLWriter writer = new XMLWriter(new FileOutputStream("src/book.xml"), format);
writer.write(document);
writer.close();
}
// 5、向指定元素节点上增加同级元素节点:<售价>21元 添加<批发价>
@Test
public void test5()throws Exception{
SAXReader reader = new SAXReader();
Document document = reader.read("src/book.xml");
//首先要得到根元素
Element root = document.getRootElement();
//得售价
Element bookElement = root.element("书");
//创建新元素
Element priceElement = DocumentHelper.createElement("批发价");
priceElement.setText("30元");
List<Element> bookChildren = bookElement.elements();//得到书的子元素
bookChildren.add(2, priceElement);
//写回XML文档
// OutputFormat format = OutputFormat.createCompactFormat();//去除空格回车换行,适合运行期间
OutputFormat format = OutputFormat.createPrettyPrint();//漂亮的格式 默认编码是UTF-8
XMLWriter writer = new XMLWriter(new FileOutputStream("src/book.xml"), format);
writer.write(document);
writer.close();
}
// 6、删除指定元素节点:批发价
@Test
public void test6()throws Exception{
SAXReader reader = new SAXReader();
Document document = reader.read("src/book.xml");
//首先要得到根元素
Element root = document.getRootElement();
Element priceElement = root.element("书").element("批发价");
priceElement.getParent().remove(priceElement);
//写回XML文档
// OutputFormat format = OutputFormat.createCompactFormat();//去除空格回车换行,适合运行期间
OutputFormat format = OutputFormat.createPrettyPrint();//漂亮的格式 默认编码是UTF-8
XMLWriter writer = new XMLWriter(new FileOutputStream("src/book.xml"), format);
writer.write(document);
writer.close();
}
// 7、操作XML文件属性
@Test
public void test7()throws Exception{
SAXReader reader = new SAXReader();
Document document = reader.read("src/book.xml");
//首先要得到根元素
Element root = document.getRootElement();
Element book = root.element("书");
System.out.println(book.attributeValue("ISBN"));
}
@Test
public void test8()throws Exception{
SAXReader reader = new SAXReader();
Document document = reader.read("src/book.xml");
//首先要得到根元素
Element root = document.getRootElement();
Element book = root.element("书");
book.addAttribute("A", "B");
//写回XML文档
// OutputFormat format = OutputFormat.createCompactFormat();//去除空格回车换行,适合运行期间
OutputFormat format = OutputFormat.createPrettyPrint();//漂亮的格式 默认编码是UTF-8
XMLWriter writer = new XMLWriter(new FileOutputStream("src/book.xml"), format);
writer.write(document);
writer.close();
}
Xpath
XPath是一个努力为XSL转换XSLT和XPointer [ ] [ ]之间共享一个共同的XPointer功能语法和语义的结果。它的主要目的是解决一个XML XML文档部分[ ]。为了支持这一功能,还提供用于处理字符串的基本设施、数字和布尔值。XPath使用一个紧凑的、非XML语法方便使用在uri和XML属性值的XPath。XPath操作基于XML文档的逻辑结构,而不是其表面的语法。Xpath的名字来自其使用的符号在URL路径通过一个XML文档的层次结构导航。 除了用于定位,XPath还设计有一个真子集,可用于匹配(测试一个节点是否符合一个模式);使用XPath进行XSLT。
XPath模型的XML文档的节点树。有不同类型的节点,包括元素节点、属性节点和文本节点。XPath定义了一个方法来计算每个节点类型字符串值。某些类型的节点也有名字。XPath完全支持XML命名空间的XML名称] [。因此,一个节点的名称被建模为一个地方的部分和一个可能的空命名空间URI;这就是所谓的扩展名。在[ 5数据模型]中详细描述了数据模型。
@Test//Xpath
public void test11() throws Exception{
SAXReader reader = new SAXReader();
Document document = reader.read("src/book.xml");
Node n = document.selectSingleNode("//书[1]/书名");
System.out.println(n.getText());
}
@Test//Xpath:第一本书的ISBN的值
public void test12() throws Exception{
SAXReader reader = new SAXReader();
Document document = reader.read("src/book.xml");
Node n = document.selectSingleNode("//书[1]");
System.out.println(n.valueOf("@ISBN"));
}
xml约束之schema
XML Schema 也是一种用于定义和描述 XML 文档结构与内容的模式语言,其出现是为了克服 DTD 的局限性
XML Schema 文件自身就是一个XML文件,但它的扩展名通常为.xsd。支持名称空间。 一个XML Schema文档通常称之为模式文档(约束文档),遵循这个文档书写的xml文件称之为实例文档。
和XML文件一样,一个XML Schema文档也必须有一个根结点,但这个根结点的名称为schema。
编写了一个XML Schema约束文档后,通常需要把这个文件中声明的元素绑定到一个URI地址上,在XML Schema技术中有一个专业术语来描述这个过程,即把XML Schema文档声明的元素绑定到一个名称空间上,以后XML文件就可以通过这个URI(即名称空间)来告诉解析引擎,xml文档中编写的元素来自哪里,被谁约束。
学习目标:不需要我们编写xsd 重点:根据xsd编写出xml文档。 难点:在xml中引入xsd约束
基本操作步骤:
a、根据xsd文件,找到根元素
<?xml version="1.0" encoding="UTF-8"?>
<书架>
</书架>
b、根元素来在哪个名称空间 使用xmlns关键字来声明名称空间。
<?xml version="1.0" encoding="UTF-8"?>
<tf:书架 xmlns:tf="http://www.zhilinghui.com">
</tf:书架>
c、名称空间和哪个xsd文件对应
<?xml version="1.0" encoding="UTF-8"?>
<tf:书架 xmlns:tf="http://www.zhilinghui.com"
schemaLocation="http://www.zhilinghui.com book.xsd">
</tf:书架>
d、schemaLocation来自一个标准的名称空间:固定写法
<?xml version="1.0" encoding="UTF-8"?>
<tf:书架 xmlns:tf="http://www.zhilinghui.com"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.zhilinghui.com book.xsd">
</tf:书架>
==============================================================================================================================
DOM4J的另一种深度解读:
DOM4J
与利用DOM、SAX、JAXP机制来解析xml相比,DOM4J 表现更优秀,具有性能优异、功能强大和极端易用使用的特点,只要懂得DOM基本概念,就可以通过dom4j的api文档来解析xml。dom4j是一套开源的api。实际项目中,往往选择dom4j来作为解析xml的利器。
先来看看dom4j中对应XML的DOM树建立的继承关系
针对于XML标准定义,对应于图2-1列出的内容,dom4j提供了以下实现:
同时,dom4j的NodeType枚举实现了XML规范中定义的node类型。如此可以在遍历xml文档的时候通过常量来判断节点类型了。
常用API
class org.dom4j.io.SAXReader
- read 提供多种读取xml文件的方式,返回一个Domcument对象
interface org.dom4j.Document
- iterator 使用此法获取node
- getRootElement 获取根节点
interface org.dom4j.Node
- getName 获取node名字,例如获取根节点名称为bookstore
- getNodeType 获取node类型常量值,例如获取到bookstore类型为1——Element
- getNodeTypeName 获取node类型名称,例如获取到的bookstore类型名称为Element
interface org.dom4j.Element
- attributes 返回该元素的属性列表
- attributeValue 根据传入的属性名获取属性值
- elementIterator 返回包含子元素的迭代器
- elements 返回包含子元素的列表
interface org.dom4j.Attribute
- getName 获取属性名
- getValue 获取属性值
interface org.dom4j.Text
- getText 获取Text节点值
interface org.dom4j.CDATA
- getText 获取CDATA Section值
interface org.dom4j.Comment
- getText 获取注释
实例一:
1 //先加入dom4j.jar包 2 import java.util.HashMap; 3 import java.util.Iterator;
4 import java.util.Map;
5
6 import org.dom4j.Document;
7 import org.dom4j.DocumentException;
8 import org.dom4j.DocumentHelper;
9 import org.dom4j.Element;
10
11 /**
12 * @Title: TestDom4j.java
13 * @Package
14 * @Description: 解析xml字符串
15 * @author 无处不在
16 * @date 2012-11-20 下午05:14:05
17 * @version V1.0
18 */
19 public class TestDom4j {
20
21 public void readStringXml(String xml) {
22 Document doc = null;
23 try {
24
25 // 读取并解析XML文档
26 // SAXReader就是一个管道,用一个流的方式,把xml文件读出来
27 //
28 // SAXReader reader = new SAXReader(); //User.hbm.xml表示你要解析的xml文档
29 // Document document = reader.read(new File("User.hbm.xml"));
30 // 下面的是通过解析xml字符串的
31 doc = DocumentHelper.parseText(xml); // 将字符串转为XML
32
33 Element rootElt = doc.getRootElement(); // 获取根节点
34 System.out.println("根节点:" + rootElt.getName()); // 拿到根节点的名称
35
36 Iterator iter = rootElt.elementIterator("head"); // 获取根节点下的子节点head
37
38 // 遍历head节点
39 while (iter.hasNext()) {
40
41 Element recordEle = (Element) iter.next();
42 String title = recordEle.elementTextTrim("title"); // 拿到head节点下的子节点title值
43 System.out.println("title:" + title);
44
45 Iterator iters = recordEle.elementIterator("script"); // 获取子节点head下的子节点script
46
47 // 遍历Header节点下的Response节点
48 while (iters.hasNext()) {
49
50 Element itemEle = (Element) iters.next();
51
52 String username = itemEle.elementTextTrim("username"); // 拿到head下的子节点script下的字节点username的值
53 String password = itemEle.elementTextTrim("password");
54
55 System.out.println("username:" + username);
56 System.out.println("password:" + password);
57 }
58 }
59 Iterator iterss = rootElt.elementIterator("body"); ///获取根节点下的子节点body
60 // 遍历body节点
61 while (iterss.hasNext()) {
62
63 Element recordEless = (Element) iterss.next();
64 String result = recordEless.elementTextTrim("result"); // 拿到body节点下的子节点result值
65 System.out.println("result:" + result);
66
67 Iterator itersElIterator = recordEless.elementIterator("form"); // 获取子节点body下的子节点form
68 // 遍历Header节点下的Response节点
69 while (itersElIterator.hasNext()) {
70
71 Element itemEle = (Element) itersElIterator.next();
72
73 String banlce = itemEle.elementTextTrim("banlce"); // 拿到body下的子节点form下的字节点banlce的值
74 String subID = itemEle.elementTextTrim("subID");
75
76 System.out.println("banlce:" + banlce);
77 System.out.println("subID:" + subID);
78 }
79 }
80 } catch (DocumentException e) {
81 e.printStackTrace();
82
83 } catch (Exception e) {
84 e.printStackTrace();
85
86 }
87 }
88
89 /**
90 * @description 将xml字符串转换成map
91 * @param xml
92 * @return Map
93 */
94 public static Map readStringXmlOut(String xml) {
95 Map map = new HashMap();
96 Document doc = null;
97 try {
98 // 将字符串转为XML
99 doc = DocumentHelper.parseText(xml);
100 // 获取根节点
101 Element rootElt = doc.getRootElement();
102 // 拿到根节点的名称
103 System.out.println("根节点:" + rootElt.getName());
104
105 // 获取根节点下的子节点head
106 Iterator iter = rootElt.elementIterator("head");
107 // 遍历head节点
108 while (iter.hasNext()) {
109
110 Element recordEle = (Element) iter.next();
111 // 拿到head节点下的子节点title值
112 String title = recordEle.elementTextTrim("title");
113 System.out.println("title:" + title);
114 map.put("title", title);
115 // 获取子节点head下的子节点script
116 Iterator iters = recordEle.elementIterator("script");
117 // 遍历Header节点下的Response节点
118 while (iters.hasNext()) {
119 Element itemEle = (Element) iters.next();
120 // 拿到head下的子节点script下的字节点username的值
121 String username = itemEle.elementTextTrim("username");
122 String password = itemEle.elementTextTrim("password");
123
124 System.out.println("username:" + username);
125 System.out.println("password:" + password);
126 map.put("username", username);
127 map.put("password", password);
128 }
129 }
130
131 //获取根节点下的子节点body
132 Iterator iterss = rootElt.elementIterator("body");
133 // 遍历body节点
134 while (iterss.hasNext()) {
135 Element recordEless = (Element) iterss.next();
136 // 拿到body节点下的子节点result值
137 String result = recordEless.elementTextTrim("result");
138 System.out.println("result:" + result);
139 // 获取子节点body下的子节点form
140 Iterator itersElIterator = recordEless.elementIterator("form");
141 // 遍历Header节点下的Response节点
142 while (itersElIterator.hasNext()) {
143 Element itemEle = (Element) itersElIterator.next();
144 // 拿到body下的子节点form下的字节点banlce的值
145 String banlce = itemEle.elementTextTrim("banlce");
146 String subID = itemEle.elementTextTrim("subID");
147
148 System.out.println("banlce:" + banlce);
149 System.out.println("subID:" + subID);
150 map.put("result", result);
151 map.put("banlce", banlce);
152 map.put("subID", subID);
153 }
154 }
155 } catch (DocumentException e) {
156 e.printStackTrace();
157 } catch (Exception e) {
158 e.printStackTrace();
159 }
160 return map;
161 }
162
163 public static void main(String[] args) {
164
165 // 下面是需要解析的xml字符串例子
166 String xmlString = "<html>" + "<head>" + "<title>dom4j解析一个例子</title>"
167 + "<script>" + "<username>yangrong</username>"
168 + "<password>123456</password>" + "</script>" + "</head>"
169 + "<body>" + "<result>0</result>" + "<form>"
170 + "<banlce>1000</banlce>" + "<subID>36242519880716</subID>"
171 + "</form>" + "</body>" + "</html>";
172
173 /*
174 * Test2 test = new Test2(); test.readStringXml(xmlString);
175 */
176 Map map = readStringXmlOut(xmlString);
177 Iterator iters = map.keySet().iterator();
178 while (iters.hasNext()) {
179 String key = iters.next().toString(); // 拿到键
180 String val = map.get(key).toString(); // 拿到值
181 System.out.println(key + "=" + val);
182 }
183 }
184
185 }
实例二:
1 /** 2 * 解析包含有DB连接信息的XML文件 3 * 格式必须符合如下规范:
4 * 1. 最多三级,每级的node名称自定义;
5 * 2. 二级节点支持节点属性,属性将被视作子节点;
6 * 3. CDATA必须包含在节点中,不能单独出现。
7 *
8 * 示例1——三级显示:
9 * <db-connections>
10 * <connection>
11 * <name>DBTest</name>
12 * <jndi></jndi>
13 * <url>
14 * <![CDATA[jdbc:mysql://localhost:3306/db_test?useUnicode=true&characterEncoding=UTF8]]>
15 * </url>
16 * <driver>org.gjt.mm.mysql.Driver</driver>
17 * <user>test</user>
18 * <password>test2012</password>
19 * <max-active>10</max-active>
20 * <max-idle>10</max-idle>
21 * <min-idle>2</min-idle>
22 * <max-wait>10</max-wait>
23 * <validation-query>SELECT 1+1</validation-query>
24 * </connection>
25 * </db-connections>
26 *
27 * 示例2——节点属性:
28 * <bookstore>
29 * <book category="cooking">
30 * <title lang="en">Everyday Italian</title>
31 * <author>Giada De Laurentiis</author>
32 * <year>2005</year>
33 * <price>30.00</price>
34 * </book>
35 *
36 * <book category="children" title="Harry Potter" author="J K. Rowling" year="2005" price="$29.9"/>
37 * </bookstore>
38 *
39 * @param configFile
40 * @return
41 * @throws Exception
42 */
43 public static List<Map<String, String>> parseDBXML(String configFile) throws Exception {
44 List<Map<String, String>> dbConnections = new ArrayList<Map<String, String>>();
45 InputStream is = Parser.class.getResourceAsStream(configFile);
46 SAXReader saxReader = new SAXReader();
47 Document document = saxReader.read(is);
48 Element connections = document.getRootElement();
49
50 Iterator<Element> rootIter = connections.elementIterator();
51 while (rootIter.hasNext()) {
52 Element connection = rootIter.next();
53 Iterator<Element> childIter = connection.elementIterator();
54 Map<String, String> connectionInfo = new HashMap<String, String>();
55 List<Attribute> attributes = connection.attributes();
56 for (int i = 0; i < attributes.size(); ++i) { // 添加节点属性
57 connectionInfo.put(attributes.get(i).getName(), attributes.get(i).getValue());
58 }
59 while (childIter.hasNext()) { // 添加子节点
60 Element attr = childIter.next();
61 connectionInfo.put(attr.getName().trim(), attr.getText().trim());
62 }
63 dbConnections.add(connectionInfo);
64 }
65
66 return dbConnections;
67 }