XML 可扩展的标记语言
XML 通用的数据格式标准
在没有XML标准时代
1 数据可以任意格式存储:二进制,文本格式
2 数据的交换和分享出现麻烦
XML 是一种通用的标准格式
1 XML 数据格式标准
2 可以用于文件的格式:XML 格式的文件称为XML 文件
3 XML文件本身是文本文件,非常便于编辑和处理
任何的文本编辑器都可以处理XML文件。
在解析xml之前要导入相应的jar包;
XML 的语法结构:
<?xml version="1.0" encoding="UTF-8"?>
<!-- <?xml> 处理节点。处理指令, 建议在XML中第一行使用!处理节点之前不能用注释! -->
<!-- 注释节点 Comment Node -->
<!-- 标记(标签)tag:<标记名> 称为标记
标记有3种: <标记名>开始标记, </标记名>结束标记, <标记名/>称为自结束标记
XML 中标记必须配对出现 有开始标记一定有结束标记
<标记名/>自结束标记是 无内容的<标记名></标记名>简写形式
<标记名/> == <标记名></标记名> -->
<!-- 元素(Element): 开始标记+内容+结束标记 的整体称为元素
如: <book>老夫子</book> 称为元素
元素的内容:
可以文本节点
可以是其他元素
可以是文本和元素的混合体
可以是元素的嵌套 -->
<!--
文本节点: 元素中出现的文本称为文本节点
-->
<!--
属性:在元素的开始标记上可以定义元素的属性
属性:属性名=“属性值”
属性值必须使用引用
属性是无顺序的。 -->
<!--
格式良好的XML(良构)
1 XML文档只能有一个根元素。
2 元素的嵌套要合理,不能交叉嵌套
如下是错误的
<book>
<authors>
</book>
</authors>
3 标记要配对
-->
<!--
因为XML的标记和内容定义没有约定,可以任意的扩展使用,称为可以扩展的标记语言!
-->
<!--
实体替换:XML的转移字符, 当在文本节点中使用特殊符号时候,需要使用实体符号替换
& = &
< = <
> = >
空格=
-->
<!-- CDATA 段:用于声明大段的文字,可以不进行实体替换 -->
<!-- XML 中的大小写是敏感的。 -->
<books>
<book id="b01" lang="cn">老夫子
<authors>
<author><佚名></author>
<author>V&A</author>
<author><![CDATA[
<p>测试</p>
]]></author>
</authors>
</book>
<book></book>
</books>
下面是java操作xml:
/**
* Java 中 XML 文件的处理
* 1 直接使用文本流处理XML文件。
* 使用BufferedReader读取,使用PrintWriter写出。
* 缺点:无法识别XML语法,不能按照元素进行处理
* 优点:快!
* 2 使用XML API 处理XML文档,W3C 提供了两种标准的XML API
* SAX:
* 优点:支持XML的语法,只支持读取操作,速度快, 占用内存小
* 缺点:不能写XML,使用繁琐
* DOM:支持XML语法,速度没有SAX快,占用内存大,支持读写操作
*
* DOM4j:是第三方提供的API,不是W3C的标准,底层封装了 W3C DOM,
* DOM4j API 简洁方便(比W3C DOM 方便!)
*/
//@Test
public void testSAXAPI(){
//利用SAX API 读取书籍的名字
// 1 打开文件流 Class getResource;
// 2 创建SAX 处理器(过滤器)
// 3 创建SAX API 读取XML文件,并且利用处理器过滤XML文件
// 4 在SAX处理期间,就得到了数据
InputStream in = getClass().getResourceAsStream("books.xml");
DefaultHandler handler = new DefaultHandler(){
boolean foundName = false;
@Override
public void startElement(String uri, String localName,
String qName, Attributes attributes) throws SAXException {
foundName = qName.equals("name");
//读取book元素的id属性
if (qName.equals("book")) {
String id = attributes.getValue("id");
System.out.println("Book ID:"+id);
}
}
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
if (foundName) {
String bookName = new String(ch, start, length);
System.out.println(bookName);
}
}
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
foundName = false;
if(qName.equals("books")){
throw new SAXException("结束了");
}
}
};
//使用 SAXParser 使用handler扫描读取XML文件,
// SAXParser: 需要使用工厂模式创建SAXParser对象
try {
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser parser = factory.newSAXParser();
parser.parse(in, handler);
//parse 方法会从流in中读取XML文档,当遇到XML文档的结构时候,执行handler中适当
// 事件处理方法 startElement endElement 等。
// 异常: IOException 文档读取时候发送IO错误
// SAXException 文档不是格式良好,时候发送
// 解析器抛出 SAX异常结束文件的读取
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* DOM4j API 演示
*/
@Test
public void testReadDoc(){
try {
InputStream in = TestCase.class.getResourceAsStream("books.xml");
SAXReader reader = new SAXReader();
//DOM4j 提供SAXReader,可将流读取为XML Doc
//如果流读取失败,XML 不是良好格式,将出现异常
Document doc = reader.read(in);
in.close();
//显示读取结果
// Dom4j 的几乎所有API都有方法 asXML() 可以显示XML文档数据
System.out.println(doc.asXML());
//在doc中检索 全部的书名
// dom4j 提供了树型结构的导航查询API方法
// getRootElement() 获取文档的根元素
// Element 代表内存中一个元素节点对象
Element root = doc.getRootElement();
//elements() 方法,可以获取一个元素的全部子元素节点
// 重载的 elements(元素名) 获取一个元素的全都指定名称的子元素
//List<Element> list = root.elements();
List<Element> list = root.elements("book");
for(Element e: list){
//element(元素名) 获取一个元素的指定名称的子元素,如果重复,发回第一个子元素
//Element n = e.element("name");
//元素上一个方法 getText() 用于获取当前元素中文本内容
//String name = n.getText();
//getTextTrim() 方法可以获取文本,并且取出前后空白
//name = n.getTextTrim();
//dom4j 提供了更加便捷的API用于直接读取子元素中的文本
String name = e.elementTextTrim("name");
System.out.println(name);
//dom4j 可以读取元素的属性
String id = e.attributeValue("id");
System.out.println("book id:"+id);
//读取元素的全部属性
//List<Attribute> attributes = e.attributes();
}
//修改内存中的DOC对象
Element lastBook = list.get(list.size()-1);
//setText() 方法可以修改元素节点的文本内容
lastBook.element("price").setText("80.00");
System.out.println(doc.asXML());
//添加新元素等
// 1 为根元素增加子元素book, addElement(元素名称) 返回新元素对象。
Element newBook = root.addElement("book");
// 2 增加元素
newBook.addAttribute("id", "B03");
newBook.addAttribute("lang", "CN");
// 2 book增加子name元素,并且为name增加文本内容
newBook.addElement("name").setText("红楼梦");
newBook.addElement("price").setText("88.90");
Element authors = newBook.addElement("authors");
authors.addElement("author").setText("曹雪芹");
//...
System.out.println(doc.asXML());
//写出Document 对象到文件, dom4j 提供的功能
FileOutputStream out = new FileOutputStream("myBooks.xml");
//设置输出格式: createPrettyPrint()创建漂亮的打印格式
OutputFormat format = OutputFormat.createPrettyPrint();
XMLWriter writer = new XMLWriter(out, format);
writer.write(doc);//XML Docuemnt 编码序列化到流
writer.close();
} catch (DocumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
/**
* XML 是数据格式,不仅仅是文件
*
* 读取 写出
* 字符流 无语法支持,繁琐 无语法支持,快 写出大规模的XML,要注意编码和语法结构
* SAX 有语法支持,简便 不能写出 适合大规模的XML读取,占用内存小
* DOM4j 有语法支持,支持读取 有语法支持,写出 适合小规模XML读写,占用内存大
* W3C DOM 可以读 可以写 API非常繁琐,Java业界使用DOM4j替代之
* pull解析 有语法支持,简便 不能写 适合大规模的XML读取,占用内存小
*
* pull解析: 特点是可以任意的暂停继续, 完全可以代替 SAX
*/
//@Test
public void testXmlPull() throws Exception{
InputStream in = new BufferedInputStream(new FileInputStream("myBooks.xml"));
//XmlPullParser 是接口,事例需要使用工厂创建
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
XmlPullParser pullParser = factory.newPullParser();
//将被解析的流交给 pullParser, 不发送解析操作
pullParser.setInput(new InputStreamReader(in, "utf-8"));
//解析获取全部的书名
boolean found = false;
Scanner scanner = new Scanner(System.in);
//COMMENT 遇到了注释
//循环一直持续到 发生文件末尾事件为止
main:
for(int event = pullParser.getEventType();
event !=END_DOCUMENT;
event = pullParser.nextToken()){
//event = START_DOCUMENT COMMENT START_TAG TEXT START_TAG TEXT
switch (event) {
case COMMENT:
System.out.println(pullParser.getText());//抓取注释的文本
break ;
case START_TAG:
//从 XmlPullParser中拉取元素的开始标记名
String name = pullParser.getName();
if(name.equals("book")){
String id = pullParser.getAttributeValue(0);
System.out.println(id);
}
found = name.equals("name");
break;
case TEXT:
if (found) {
//拉取文本
String text = pullParser.getText().trim();
System.out.println(text);
}
break;
case END_TAG:
found = false;
}
}
in.close();
}
/** 静态导入 */
//@Test
public void testStaticImport(){
double x = sin(PI);
System.out.println(x);
}
/**
* w3school.com.cn 中文
* w3schools.com 英文
* xpath 是XML 的一种查询语法
* myBooks.xml
* 抓取全部的 书名 节点的集合
* String xpath = "/books/book/name"
* 在DOM对象上查找,就可以获取全部满足xpath的 Element对象
* dom4j 支持 xpath查找,在内存的Dom对象中查找 子节点
*
* 1 xpath 的语法
* 2 dom4j API 支持xpath 查询
* 1 支持根部绝对路径查询
* doc.selectNodes(xpath) 返回一个集合,包含全部满足条件的节点
* doc.selectSingleNode(xpath) 返回第一个匹配的节点
* 2 支持相对路径查询,从某个元素节点开始执行查询
* 如 Element book 节点
* book.selectNodes(xpath)
* book.selectSingleNode(xpath)
*/
//@Test
public void testXpath() throws Exception{
//打开Dom4j DOM 对象
SAXReader reader = new SAXReader();
Document doc = reader.read(new File("myBooks.xml"));
//selectNodes 是在DOM 上执行xpath查询,将满足条件的元素 都作为返回值返回
String xpath = "/books/book/name";
List<Element> list = doc.selectNodes(xpath);
//
for (Element e : list) {
System.out.println(e.asXML());
}
}
public void testSelectSingleNode(String xpath) throws Exception{
//打开Dom4j DOM 对象
SAXReader reader = new SAXReader();
Document doc = reader.read(new File("myBooks.xml"));
Node node = doc.selectSingleNode(xpath);
System.out.println(node.asXML());
}
public void testSelectNodes(String xpath) throws Exception{
SAXReader reader = new SAXReader();
Document doc = reader.read(new File("myBooks.xml"));
List<Node> list = doc.selectNodes(xpath);
for (Node node : list) {
System.out.println(node.asXML());
}
}
@Test
public void testXPath() throws Exception{
//testSelectSingleNode("/books");
//testSelectNodes("/books/book");
//testSelectNodes("//.");
//XPATH 可以理解为 一层一层的过滤
// "//" 代表所有节点, //author 所有节点中名字为author的节点。
//testSelectNodes("//author");//查询结果节点是Element类型
//查询所有节点中的 id属性节点
//testSelectNodes("//@id");//查询结果节点是Attribute类型
// DOM 节点的分类关系
/* Node 节点
* |-- Document 文档节点
* | |-- 只能包含一个根元素
* |-- Element 元素节点
* | |-- 可以包含其他节点和文本
* |-- Comment 注释节点
* |-- Text 文本节点
* |-- Attribute 属性节点
*/
//testSelectNodes("/books/book[1]");
//testSelectNodes("/books/book[last()]");
//testSelectNodes("/books/book[1]/name");
//testSelectNodes("/books/book[last()]/name");
//testSelectNodes("/books/book[1]/authors/author[1]");
//testSelectNodes("/books/book[1]/authors/athor[1]");
//book有id属性被查询出来
//testSelectNodes("/books/book[@id]");
//testSelectNodes("/books/book[@id and price>85 and position()=1]");
testSelectNodes("//*[.>85]");
// /*/* 与 /books/book 区别
}