XML Extensible Markup language: 可扩展的标记语言
1:文档格式
1: 开始标签必须有一个对应的结束标签
2:空元素必须关闭
3:所有标签都区分大小写
4:所有标签都必须合理嵌套
5:所有标签的属性值都必须用 双引号 或者单引号 括起来 如<student name="zhangsan" age='18'> 哪怕不是字符串也必须加上单引号
2:文档标记
A:XML 声明 --DTD:定义xml文件中元素和属性的规则及相互关系
外部DTD的引用:使用 PUBLIC 关键字来引用
类型为: <!PUBLIC 根元素的名称 PUBLIC" DTD的名称 " " 外部DTD文件的URL ">
B:文档类型声明
C:元素 元素内容包括 子元素字符数据字符引用实体引用CDATA字段:以 <![CDATA[ 内容 ]]>格式 主要是嵌入 java代码 如下:
<span > </span><pre name="code" class="html"><span > </span><?xml version="1.0">
<span > </span><java>
<span > </span><![CDATA[
<span> </span>if(a>b && c<d)
<span> </span>max=a;
<span > </span>]]>
D:注释
<span > </span><?xml-stylesheet href="hello.css" type="text/css" ?> <!-- xml-stylesheet 叫做处理指令的目标 指令必须在声明后 第一个元素前 -->
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">
</span>
3 一个xml 文档中可以包含许多元素和属性,我们使用其他人的文档或者在文档中引用DTD文件时,有可能碰到名称相同的元素,为了区分就需要引用命名空间
1:声明名称空间
第一种形式: <元素名 xmlns:prefixname="URL"> 例如: <hr xmlns:hr="http://www.sunxin.org/hr">
第二种形式:<hr xmlns="http://www.sunxin.org/hr">
2:名称空间在元素中的使用
如果不通节点下的子元素名称相同,在不通节点下使用不影响名称区分 例如:
4 XML 文档的解析
DOM:文档对象模型 W3C 推荐的处理xml 文件解析的标准接口
SAX: Simple Api for Xml
这两种只定义了接口,如果想利用 DOM 或者 SAX 访问 xml 还需要一个实现了 DOM 或者SAX 的解析器 Apache的 Xerces 提供了 这两种的调用接口,访问xml 的话
只需要在应用程序中构造一个解析器实现类的对象
如:
<span > </span>org.xml.sax.XMLReader reader = new org.apache.xerces.parsers.SAXParser();
<span > </span>FileInputStream fis = new FileInputStream("user.xml");
<span > </span>InputSource in = new InputSource(fis);
<span > </span>reader.setContentHandler(new MyContentHandler());
<span > </span>reader.parse(in);
1: 使用DOM 解析XML
a: DOM 解析模型
核心概念就是节点,定义了一个 Node 接口,表示文档树中的一个节点,并且从这个接口派生出更多的具体接口
如: Document :表示整个文档
Element : 表示XML 中的元素
Attr: 表示元素属性
String: getNodeName() -- 返回节点名称getNodeType() -- 返回节点类型 getNodeValue() -- 返回节点值hasChildNodes()-- 是否有子节点
b: DOM 解析器工厂
在 javax.xml.parsers 包中,定义了 DOM 解析器工厂类 DocumentBuilderFactory ,用于产生DOM 解析器,这是个抽象类,提供静态方法 newInstance()
这样采用JAXP 编程可以任意更换解析器,newInstance() 通过下面三种途径找到解析器厂商给出的工厂类
(1) : 利用 System.setProperty("javax.xml.parsers.DocumentBuilderFactory","org.apache.xerces.jaxp.DocumentBuilderFactoryImpl");
注意 ---- 不要在程序中直接设置解析工厂类 不然后期更换需要修改程序
(2): java.exe 中 通过 java -Djavax.xml.parsers.DocumentBuilderFactory=oracle.xml.jaxp.JXDocumentBuilderFactoryDOMTest
(3): 可以在 jdk 的 jre/lib 下建立 文件 jaxp.properties 配置要使用的工厂类
java x.xml.parsers.DocumentBuilderFactory=org.apache.xerces.jaxp.DocumentBuilderFactoryImpl 后期只需要修改这个配置文件即可
创建过程为:
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); // 得到具体厂商的工厂类
DocumentBuilder db = factory.newDocumentBuilder(); // 得到具体厂商的DOM 解析器对象
Document d = db.parse(File f) // 获取整个文档的Document 对象 参数也可传 InputStream
// 注意javax.xml.parsers 中定义了一个错误类 FactoryConfigurationError 类和异常类 ParserConfigurationException 来抓取错误信息或异常
节点类型以及在DOM API中对应的接口图:
c: DOM 解析文档实例
(1) 文档节点:文档树的根节点,也是文档中处理其他节点的父节点 但并不是根元素,因为xml中指令 注释等可以出现在根元素以外,根元素只是
文档节点的子节点。所以 Document 中有个方法为 Element e = Document.getDocumentElement()
同时还有创建各种节点的方法
1:创建 元素属性 Attr createAttrbute(String name)
2: 创建节点 Element creeateElement(String name)
对节点操作的方法:
1:Element getElementById(String elementID) 通过给定的ID来查找对应的元素
2: NodeList getElementByTagName(String name) 通过给定的name 返回所有的 元素集合
(2) 元素节点Element : 唯一能够拥有属性的节点类型 通常其拥有子元素和文本节点
String getAttribute(String name) 返回该元素的值
Attr getArributeNode(String name) 通过属性的名称得到属性的节点 删除为 remove
(3) 文本节点 Text: 只包含文本内容的节点
例如: 如果在 student节点上调用getChildNodes() 返回的NodeList 包含五个节点, 空白 换行 空格3个 4)属性节点 Attr:代表了元素的属性
解析例子 -- 第一个实例:--------------------------------------------------------------------------------
XML 文件:
<?xml version="1.0" encoding="GB2312"?>
<?xml-stylesheet type="text/xsl" href="student.xsl"?>
<students>
<student sn="1">
<name>张三</name>
<age>12</age>
</student>
<student sn="2">
<name>李四</name>
<age>13</age>
</student>
<student sn="3">
<name>王五</name>
<age>14</age>
</student>
<student sn="4">
<name>赵六</name>
<age>15</age>
</student>
</students>
package com.tide.servlet;
import java.io.IOException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
public class Test {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
DocumentBuilderFactory df = DocumentBuilderFactory.newInstance();System.out.println(df.getClass().getName());// 解析器工厂类
try {
// 获取解析器工厂类的实例
DocumentBuilder db = df.newDocumentBuilder();System.out.println(db.getClass().getName()); // dom解析器类名
Document d = (Document) db.parse("test.xml"); // 这里解析XML 文档
NodeList nl = d.getElementsByTagName("student");
int len = nl.getLength();
for(int m = 0;m<len;m++){
Element el = (Element) nl.item(m);
Node node_name = (Node) el.getElementsByTagName("name").item(0);
Node node_age = (Node) el.getElementsByTagName("age").item(0);
String name = node_name.getFirstChild().getNodeValue();
String age = node_age.getFirstChild().getNodeValue();
System.out.println(name+" -- "+age);
}
} catch (ParserConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SAXException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
第一个实例:-------------------------------------------------------------------------------- end
第二个实例: 添加 删除 和修改节点
public class Test2 {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
DocumentBuilderFactory df = DocumentBuilderFactory.newInstance();
try{
DocumentBuilder db = df.newDocumentBuilder();
Document d = db.parse("test.xml");
//------------- 添加节点 创建一个学生信息的各元素点
Element elstu = d.createElement("student");
Element slname = d.createElement("name");
Element slage = d.createElement("age");
// 创建 student 元素的sn 属性节点
Attr attr = d.createAttribute("sn");
attr.setValue("5");
elstu.setAttributeNode(attr); // 为 stu 元素添加sn 的属性节点
// 创建代表学生信息的文本节点
Text tName = d.createTextNode("孙七");
Text tAge = d.createTextNode("17");
//将文本节点添加为对应的元素的子节点上 name = 孙七
slname.appendChild(tName);
slage.appendChild(tAge);
// 将 name age 添加为student 节点的子节点上
elstu.appendChild(slname);
elstu.appendChild(slage);
// 获取文档根元素
Element elRoot = d.getDocumentElement();
// 将 student 节点添加为 根元素的子节点
elRoot.appendChild(elstu);
NodeList list = d.getElementsByTagName("student");
// 删除节点
Node del = list.item(0);
del.getParentNode().removeChild(del);
// 修改节点 注意:NodeList 是动态的,前面删除后 索引为0 的节点是原来索引为1 的节点
Element update = (Element) list.item(0);
Node updateAge = update.getElementsByTagName("age").item(0);
updateAge.getFirstChild().setNodeValue("50");
// 输出信息
for(int m = 0;m<list.getLength();m++){
Element el = (Element) list.item(m);
System.out.println("编号: "+el.getAttribute("sn"));
Node nodeName = el.getElementsByTagName("name").item(0);
String name = nodeName.getFirstChild().getNodeValue();
Node nodeAge = el.getElementsByTagName("age").item(0);
String age = nodeAge.getFirstChild().getNodeValue();
System.out.println("姓名:"+name);
System.out.println("年龄:"+age);
System.out.println("------------");
}
}catch(Exception e){
e.printStackTrace();
}
}
}
结果为 : 张三被删除 李四年龄为改为 50 新增了孙七
// 如果要将输出结果保存到 xml 的话 需要XSL 转换 注意 这里的XSL转换是没有使用任何 XSLT 样式表的恒等转换,即直接输出复制源到对象中
// 首先 利用文档节点 创建一个 DOM 输出源
DOMSource source = new DOMSource(d);
StreamResult result = new StreamResult(new File("test22.xml"));
// 得到转换器工厂类的实例
TransformerFactory fac = TransformerFactory.newInstance();
// 创建一个新的转换器 将DOM 输入源内容复制到结果文档中
Transformer tf = fac.newTransformer();
tf.transform(source, result);
第二个实例 -----------------------------------------------------------------------------------------end
后期有 SAX 解析器工厂来解析 xml 和 JDOM 解析xml 以及 dom4j 来进行解析 dom4j 性能优越且灵活性较大 Hibernate 就是用的 dom4j 解析 下期将重点讲解 dom4j 解析