xml学习体会
一、XML简介
HTML用于显示的。XML被设计的宗旨是描述数据的。
- XML的标签是用户自行定义的。
- XML是可扩展标记语言。
1、XML的作用
描述有关系和层次结构的数据
2、XML的应用
a、描述数据
b、作为配置文件
注:在Java开发中,传统的配置文件是properties文件。
扩展名必须是properties,文件中的内容是以key=value的形式存在的。
例:db.properties;user=root;password=root;#url=... 注释
二、XML的语法
1、XML文档声明
必须出现在第1行。
语法:<?xml version="1.0"?> 注意:?与xml之间不能有空格
*version可以称为属性:取值固定1.0
*encoding属性:说明xml文档采用的编码。默认为utf-8
注意:保存到磁盘上使用的编码要与XML声明中的编码一致。否则出现错误
standalone:说明该xml文档是否独立存在。
2、元素
- 必须有结束标签。
- 如果没有主题内容,标签<tag1></tag1>可以写为<tag1/>
- 必须合理嵌套
- 一个XML文档中,有且只有一个根元素
- XML不会忽略文档中出现的空格、回车换行、制表符。
- 命名规范:只能包含字母、数字、下划线、减号和英文句点。
- 严格区分大小写;
元素的属性名不能重复
属性的取值必须用引号引起来(单或双)
属性可以用子元素的形式来替代。
4、注释
语法:<!--这是注释-->
注意:
声明前不能有注释
注释必须合理嵌套
5、CDATA区
CDATA:Character Data字符数据
作用: 把元素等看做普通字符串
语法:<![CDATA[内容]]>
6、XML中的特殊字符
要在元素内容中显示特殊字符本身,需要使用替代符号
& &
作用:用来指挥软件如何解析XML文档。
语法:<?开头 ?>结尾
常用的指令:xml-stylesheet引入样式
DTD:Document Type Definition文档类型定义
作用:约束XML编写
DTD文件保存到磁盘上时必须使用utf-8
a、直接在XML文档中编写(没有编码要求)
语法:
<!DOCTYPE 根元素名称[
//DTD定义
]>
b、在单独的文件中编写(文件的扩展名是dtd,且保存时必须使用utf-8编码)
引入外部定义的DTD文档:
1、 DTD文档在本地:
<!DOCTYPE 根元素名称 SYSTEM "DTD文档的存放路径">
2、 DTD文档在公共网络上:
<!DOCTYPE 根元素名称 PUBLIC "DTD名称" "DTD的URL">
2、DTD语法细节(能看懂DTD)
*a、定义元素
语法:<!ELEMENT 元素名称 使用规则>
使用规则:
- (#PCDATA):Parsed Character Data 表明该元素的主体内容是普通字符串
- EMPTY:表明该元素是空元素
- ANY:用于指示元素的主体内容为任意类型。
- (子元素):指示该元素有哪些孩子,如果子元素用逗号分开,说明必须按照声明顺序去编写XML文档,如果子元素用“|”分开,说明任选其一
- 可以使用*、?、+说明元素出现的次数
?:0次或一次
+:至少一次
什么都没有:有且必须一次
*b、定义属性
语法:
1、<!ATTLIST 元素名称
属性名1 属性值类型 设置说明
属性名2 属性值类型 设置说明>
2、属性值类型:
CDATA:取值是普通字符数据
ENUMERATED (DTD没有此关键字):表示枚举,只能从枚举列表中任选其一,如(鸡肉|牛肉|猪肉|鱼肉)
ID:表示属性的取值不能重复
3、设置说明:
#REQUIRED:该属性是必须的
#IMPLIED:可选的属性
#FIXED:属性的取值为一个固定值。 #FIXED "固定值"
直接值:表示属性的取值为该默认值
c、定义实体(了解)
1、引用实体:
特点:在DTD中定义实体,在XML中使用
语法:<!ENTITY 实体名称 "内容">
在XML中如何引用实体:
&实体名称;
2、参数实体:
特点:在DTD中定义实体,在DTD中使用
语法:<!ENTITY % 实体名称 "内容">
在DTD中如何使用:
%实体名称;
xml 入门 dtd
xml dtd的格式:
<?xml version="1.0" encoding="UTF-8"?>
<!ELEMENT classroom (className,grade,students)>
<!ATTLIST classroom id ID #REQUIRED>
<!ELEMENT className (#PCDATA)>
<!ELEMENT grade (#PCDATA)>
<!ELEMENT students (student+)>
<!ELEMENT student (id,name,age)>
<!ELEMENT id (#PCDATA)>
<!ELEMENT name (#PCDATA)>
<!ELEMENT age (#PCDATA)>
相应的xml文件:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE classroom SYSTEM "classroom.dtd">
<!--<!DOCTYPE classroom PUBLIC "http://www.zizhu.com/classroom">-->
<classroom id="p1">
<className>2010计算机应用技术</className>
<grade>2010</grade>
<students>
<student>
<id>11</id>
<name>zizhu8</name>
<age>20</age>
</student>
<student>
<id>12</id>
<name>zizhu3</name>
<age>20</age>
</student>
</students>
</classroom>
用 dom4j 解析 XML
dom4j API 包含一个解析 XML 文档的工具。本文中将使用这个解析器创建一个示例 XML 文档。清单 1 显示了这个示例 XML 文档,catalog.xml。
<?xml version="1.0" encoding="UTF-8"?> <catalog> <!--An XML Catalog--> <?target instruction?> <journal title="XML Zone" publisher="IBM developerWorks"> <article level="Intermediate" date="December-2001"> <title>Java configuration with XML Schema</title> <author> <firstname>Marcello</firstname> <lastname>Vitaletti</lastname> </author> </article> </journal> </catalog> |
然后使用同一个解析器修改 catalog.xml,清单 2 是修改后的 XML 文档,catalog-modified.xml。
<?xml version="1.0" encoding="UTF-8"?> <catalog> <!--An XML catalog--> <?target instruction?> <journal title="XML Zone" publisher="IBM developerWorks"> <article level="Introductory" date="October-2002"> <title>Create flexible and extensible XML schemas</title> <author> <firstname>Ayesha</firstname> <lastname>Malik</lastname> </author> </article> </journal> </catalog> |
与 W3C DOM API 相比,使用 dom4j 所包含的解析器的好处是 dom4j 拥有本地的 XPath 支持。DOM 解析器不支持使用 XPath 选择节点。
本文包括以下几个部分:
- 预先设置
- 创建文档
- 修改文档
这个解析器可以从 http://dom4j.org 获取。通过设置使dom4j-1.4/dom4j-full.jar
能够在 classpath 中访问,该文件中包括 dom4j 类、XPath 引擎以及 SAX 和 DOM 接口。如果已经使用了 JAXP 解析器中包含的 SAX 和 DOM 接口,向 classpath 中增加dom4j-1.4/dom4j.jar
。 dom4j.jar
包括 dom4j 类和 XPath 引擎,但是不含 SAX 与 DOM 接口。
本节讨论使用 dom4j API 创建 XML 文档的过程,并创建示例 XML 文档 catalog.xml。
使用 import 语句导入 dom4j API 类:
import org.dom4j.Document; import org.dom4j.DocumentHelper; import org.dom4j.Element; |
使用 DocumentHelper
类创建一个文档实例。 DocumentHelper
是生成 XML 文档节点的 dom4j API 工厂类。
Document document = DocumentHelper.createDocument(); |
使用 addElement()
方法创建根元素 catalog
。 addElement()
用于向 XML 文档中增加元素。
Element catalogElement = document.addElement("catalog"); |
在 catalog
元素中使用 addComment()
方法添加注释“An XML catalog”。
catalogElement.addComment("An XML catalog"); |
在 catalog
元素中使用 addProcessingInstruction()
方法增加一个处理指令。
catalogElement.addProcessingInstruction("target","text"); |
在 catalog
元素中使用 addElement()
方法增加 journal
元素。
Element journalElement = catalogElement.addElement("journal"); |
使用 addAttribute()
方法向 journal
元素添加 title
和publisher
属性。
journalElement.addAttribute("title", "XML Zone"); journalElement.addAttribute("publisher", "IBM developerWorks"); |
向 article
元素中添加 journal
元素。
Element articleElement=journalElement.addElement("article"); |
为 article
元素增加 level
和 date
属性。
articleElement.addAttribute("level", "Intermediate"); articleElement.addAttribute("date", "December-2001"); |
向 article
元素中增加 title
元素。
Element titleElement=articleElement.addElement("title"); |
使用 setText()
方法设置 article
元素的文本。
titleElement.setText("Java configuration with XML Schema"); |
在 article
元素中增加 author
元素。
Element authorElement=articleElement.addElement("author"); |
在 author
元素中增加 firstname
元素并设置该元素的文本。
Element firstNameElement=authorElement.addElement("firstname"); firstNameElement.setText("Marcello"); |
在 author
元素中增加 lastname
元素并设置该元素的文本。
Element lastNameElement=authorElement.addElement("lastname"); lastNameElement.setText("Vitaletti"); |
可以使用 addDocType()
方法添加文档类型说明。
document.addDocType("catalog", null,"file://c:/Dtds/catalog.dtd"); |
这样就向 XML 文档中增加文档类型说明:
<!DOCTYPE catalog SYSTEM "file://c:/Dtds/catalog.dtd"> |
如果文档要使用文档类型定义(DTD)文档验证则必须有 Doctype。
XML 声明 <?xml version="1.0" encoding="UTF-8"?>
自动添加到 XML 文档中。
清单 3 所示的例子程序 XmlDom4J.java 用于创建 XML 文档 catalog.xml。
import org.dom4j.Document; import org.dom4j.DocumentHelper; import org.dom4j.Element; import org.dom4j.io.XMLWriter; import java.io.*; public class XmlDom4J{ public void generateDocument(){ Document document = DocumentHelper.createDocument(); Element catalogElement = document.addElement("catalog"); catalogElement.addComment("An XML Catalog"); catalogElement.addProcessingInstruction("target","text"); Element journalElement = catalogElement.addElement("journal"); journalElement.addAttribute("title", "XML Zone"); journalElement.addAttribute("publisher", "IBM developerWorks"); Element articleElement=journalElement.addElement("article"); articleElement.addAttribute("level", "Intermediate"); articleElement.addAttribute("date", "December-2001"); Element titleElement=articleElement.addElement("title"); titleElement.setText("Java configuration with XML Schema"); Element authorElement=articleElement.addElement("author"); Element firstNameElement=authorElement.addElement("firstname"); firstNameElement.setText("Marcello"); Element lastNameElement=authorElement.addElement("lastname"); lastNameElement.setText("Vitaletti"); document.addDocType("catalog", null,"file://c:/Dtds/catalog.dtd"); try{ XMLWriter output = new XMLWriter( new FileWriter( new File("c:/catalog/catalog.xml") )); output.write( document ); output.close(); } catch(IOException e){System.out.println(e.getMessage());} } public static void main(String[] argv){ XmlDom4J dom4j=new XmlDom4J(); dom4j.generateDocument(); }} |
这一节讨论了创建 XML 文档的过程,下一节将介绍使用 dom4j API 修改这里创建的 XML 文档。
这一节说明如何使用 dom4j API 修改示例 XML 文档 catalog.xml。
使用 SAXReader 解析 XML 文档 catalog.xml:
SAXReader saxReader = new SAXReader(); Document document = saxReader.read(inputXml); |
SAXReader
包含在 org.dom4j.io 包中。
inputXml
是从 c:/catalog/catalog.xml 创建的 java.io.File。使用 XPath 表达式从article
元素中获得level
节点列表。如果level
属性值是“Intermediate”则改为“Introductory”。
List list = document.selectNodes("//article/@level" ); Iterator iter=list.iterator(); while(iter.hasNext()){ Attribute attribute=(Attribute)iter.next(); if(attribute.getValue().equals("Intermediate")) attribute.setValue("Introductory"); } |
获取 article
元素列表,从 article
元素中的 title
元素得到一个迭代器,并修改title
元素的文本。
list = document.selectNodes("//article" ); iter=list.iterator(); while(iter.hasNext()){ Element element=(Element)iter.next(); Iterator iterator=element.elementIterator("title"); while(iterator.hasNext()){ Element titleElement=(Element)iterator.next(); if(titleElement.getText().equals("Java configuration with XML Schema")) titleElement.setText("Create flexible and extensible XML schema"); }} |
通过和 title
元素类似的过程修改 author
元素。
清单 4 所示的示例程序 Dom4JParser.java 用于把 catalog.xml 文档修改成 catalog-modified.xml 文档。
import org.dom4j.Document; import org.dom4j.Element; import org.dom4j.Attribute; import java.util.List; import java.util.Iterator; import org.dom4j.io.XMLWriter; import java.io.*; import org.dom4j.DocumentException; import org.dom4j.io.SAXReader; public class Dom4JParser{ public void modifyDocument(File inputXml){ try{ SAXReader saxReader = new SAXReader(); Document document = saxReader.read(inputXml); List list = document.selectNodes("//article/@level" ); Iterator iter=list.iterator(); while(iter.hasNext()){ Attribute attribute=(Attribute)iter.next(); if(attribute.getValue().equals("Intermediate")) attribute.setValue("Introductory"); } list = document.selectNodes("//article/@date" ); iter=list.iterator(); while(iter.hasNext()){ Attribute attribute=(Attribute)iter.next(); if(attribute.getValue().equals("December-2001")) attribute.setValue("October-2002"); } list = document.selectNodes("//article" ); iter=list.iterator(); while(iter.hasNext()){ Element element=(Element)iter.next(); Iterator iterator=element.elementIterator("title"); while(iterator.hasNext()){ Element titleElement=(Element)iterator.next(); if(titleElement.getText().equals("Java configuration with XML Schema")) titleElement.setText("Create flexible and extensible XML schema"); } } list = document.selectNodes("//article/author" ); iter=list.iterator(); while(iter.hasNext()){ Element element=(Element)iter.next(); Iterator iterator=element.elementIterator("firstname"); while(iterator.hasNext()){ Element firstNameElement=(Element)iterator.next(); if(firstNameElement.getText().equals("Marcello")) firstNameElement.setText("Ayesha"); } } list = document.selectNodes("//article/author" ); iter=list.iterator(); while(iter.hasNext()){ Element element=(Element)iter.next(); Iterator iterator=element.elementIterator("lastname"); while(iterator.hasNext()){ Element lastNameElement=(Element)iterator.next(); if(lastNameElement.getText().equals("Vitaletti")) lastNameElement.setText("Malik"); } } XMLWriter output = new XMLWriter( new FileWriter( new File("c:/catalog/catalog-modified.xml") )); output.write( document ); output.close(); } catch(DocumentException e) { System.out.println(e.getMessage()); } catch(IOException e){ System.out.println(e.getMessage()); } } public static void main(String[] argv){ Dom4JParser dom4jParser=new Dom4JParser(); dom4jParser.modifyDocument(new File("c:/catalog/catalog.xml")); } } |
这一节说明了如何使用 dom4j 中的解析器修改示例 XML 文档。这个解析器不使用 DTD 或者模式验证 XML 文档。如果 XML 文档需要验证,可以解释用 dom4j 与 JAXP SAX 解析器。
XML的三种方式(DOM,SAX,PULL)
DOM方式解析xml是先把xml文档都读到内存中,然后再用DOM API来访问树形结构,并获取数据的,但是这样一来,如果xml文件很大呢?手机CPU处理能力当然不能与PC机器比,因此在处理效率方面就相对差了,当然这是对于其他方式处理xml文档而言。
既然涉及到事件,就有事件源,事件处理器。在SAX接口中,事件源是org.xml.sax包中的XMLReader,它通过parser()方法 来解析XML文档,并产生事件。事件处理器是org.xml.sax包中ContentHander、DTDHander、ErrorHandler,以 及EntityResolver这4个接口
需要XmlReader 以及DefaultHandler来配合解析xml。
PULL方式也是基于事件驱动的,读取xml回调方法返回的是数字。
读取到xml的声明返回 START_DOCUMENT
读取到xml的结束返回 END_DOCUMENT
读取到xml的开始标签返回 START_TAG
读取到xml的结束标签返回 END_TAG
读取到xml的文本返回 TEXT
package per.lx.xml_parser;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import android.app.Activity;
import android.os.Bundle;
import android.util.Xml;
import android.widget.TextView;
public class XMLParserTestActivity extends Activity {
private static final String DOM = "DOM parser";
private static final String SAX = "SAX parser";
private static final String PULL = "PULL parser";
private String parserType = DOM;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
List<SearchInfo> infos = null;
if (DOM.equals(parserType)) {
infos = parserByDOM("search.xml");
} else if (SAX.equals(parserType)) {
infos = parserBySAX("search.xml");
} else if (PULL.equals(parserType)) {
infos = parserByPULL("search.xml");
}
TextView search = (TextView) findViewById(R.id.search);
StringBuilder infoBuilder = new StringBuilder();
infoBuilder.append(" " + parserType + "\n\n");
for (int i = 0; i < infos.size(); i++) {
infoBuilder.append(" name : " + infos.get(i).getName() + "\n");
infoBuilder.append(" age : " + infos.get(i).getAge() + "\n");
infoBuilder.append(" introduction : " + infos.get(i).getIntroduction() + "\n");
infoBuilder.append(" url : " + infos.get(i).getUrl() + "\n");
infoBuilder.append("\n");
}
search.setText(infoBuilder.toString());
}
public static class SearchInfo implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private String name;
private int age;
private String introduction;
private String url;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getIntroduction() {
return introduction;
}
public void setIntroduction(String introduction) {
this.introduction = introduction;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
}
private static final String SEARCH = "search";
private static final String NAME = "name";
private static final String AGE = "age";
private static final String INTRODUCTION = "introduction";
private static final String URL = "url";
/**
* DOM parse
*
* @param fileName
* @return
*/
private List<SearchInfo> parserByDOM(String fileName) {
List<SearchInfo> infos = new ArrayList<SearchInfo>();
try {
// 加载xml文档
DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
InputStream inputStream = getResources().getAssets().open(fileName);
// 找到根节点---searchs
NodeList nodes = builder.parse(inputStream).getDocumentElement().getElementsByTagName(SEARCH);
// 遍历根节点searchs下的所有子节点
for (int i = 0; i < nodes.getLength(); i++) {
SearchInfo info = new SearchInfo();
Element searchElement = (Element) nodes.item(i);
info.setName(searchElement.getAttribute(NAME));
info.setAge(Integer.parseInt(searchElement.getAttribute(AGE)));
Element introduction = (Element) searchElement.getElementsByTagName(INTRODUCTION).item(0);
info.setIntroduction(introduction.getFirstChild().getNodeValue());
Element url = (Element) searchElement.getElementsByTagName(URL).item(0);
info.setUrl(url.getFirstChild().getNodeValue());
infos.add(info);
}
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
}
return infos;
}
/**
* SAX parse
*
* @param fileName
* @return
*/
private List<SearchInfo> parserBySAX(String fileName) {
List<SearchInfo> infos = null;
try {
SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
XMLReader reader = parser.getXMLReader();
SearchHander hander = new SearchHander();
reader.setContentHandler(hander);
reader.parse(new InputSource(getAssets().open(fileName)));
infos = hander.getSearchInfos();
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return infos;
}
private class SearchHander extends DefaultHandler {
private SearchInfo info;
private List<SearchInfo> infos = new ArrayList<SearchInfo>();
private boolean isIntroduction = false;
private boolean isURL = false;
public List<SearchInfo> getSearchInfos() {
return infos;
}
// 开始读取标签
public void startElement(String uri, String localName, String qName, Attributes attributes) {
String tagName = localName.length() != 0 ? localName : qName;
tagName = tagName.toLowerCase().trim();
// 读取的是Search标签开始,则实例化SearchInfo
if (tagName.equals(SEARCH)) {
info = new SearchInfo();
info.setName(attributes.getValue(NAME));
info.setAge(Integer.parseInt(attributes.getValue(AGE)));
}
// 读取其他节点
if (tagName.equals(INTRODUCTION)) {
isIntroduction = true;
} else if (tagName.equals(URL)) {
isURL = true;
}
}
// 结束标签
public void endElement(String uri, String localName, String qName) {
String tagName = localName.length() != 0 ? localName : qName;
tagName = tagName.toLowerCase().trim();
// 读取的是Search标签结束,则把search添加进集合中
if (tagName.equals(SEARCH)) {
infos.add(info);
}
// 读取其他节点
if (tagName.equals(INTRODUCTION)) {
isIntroduction = false;
} else if (tagName.equals(URL)) {
isURL = false;
}
}
// 读取到节点内容时的回调
public void characters(char[] ch, int start, int length) {
if (isIntroduction) {
info.setIntroduction(new String(ch, start, length));
} else if (isURL) {
info.setUrl(new String(ch, start, length));
}
}
}
/**
* Pull parse
*
* @param fileName
* @return
*/
private List<SearchInfo> parserByPULL(String fileName) {
List<SearchInfo> infos = new ArrayList<SearchInfo>();
XmlPullParser xmlParser = Xml.newPullParser();
InputStream inputStream = null;
try {
inputStream = getResources().getAssets().open(fileName);
xmlParser.setInput(inputStream, "utf-8");
int evtType = xmlParser.getEventType();
SearchInfo info = null;
while (evtType != XmlPullParser.END_DOCUMENT) {
switch (evtType) {
case XmlPullParser.START_TAG:
String tag = xmlParser.getName();
// 如果是search标签开始,则实例化对象
if (tag.equalsIgnoreCase(SEARCH)) {
info = new SearchInfo();
// 取出search标签中的属性值
info.setName(xmlParser.getAttributeValue(null, NAME));
info.setAge(Integer.parseInt(xmlParser.getAttributeValue(null, AGE)));
} else if (info != null) {
if (tag.equalsIgnoreCase(INTRODUCTION)) {
info.setIntroduction(xmlParser.nextText());
} else if (tag.equalsIgnoreCase(URL)) {
info.setUrl(xmlParser.nextText());
}
}
break;
case XmlPullParser.END_TAG:
// 如果遇到search标签结束,则把search对象添加进集合中
if (xmlParser.getName().equalsIgnoreCase(SEARCH) && info != null) {
infos.add(info);
info = null;
}
break;
default:
break;
}
// 如果xml没有结束,则导航到下一个river节点
evtType = xmlParser.next();
}
} catch (IOException e) {
e.printStackTrace();
} catch (XmlPullParserException e) {
e.printStackTrace();
}
return infos;
}
}
search.xml
<?xml version="1.0" encoding="utf-8"?>
<searchs>
<search
name="google" age="14" >
<introduction>Hi, This is google search!</introduction>
<url>http://www.google.com</url>
</search>
<search
name="baidu" age="12" >
<introduction>Hi, This is baidu search!</introduction>
<url>http://www.baidu.com</url>
</search>
<search
name="biying" age="3" >
<introduction>Hi, This is biying search!</introduction>
<url>http://www.biying.com</url>
</search>
</searchs>
DOM4J_xpath 操作简介
1、DOM4J简介
DOM4J是 dom4j.org 出品的一个开源 XML 解析包。DOM4J应用于 Java 平台,采用了 Java 集合框架并完全支持 DOM,SAX 和 JAXP。
DOM4J 使用起来非常简单。只要你了解基本的 XML-DOM 模型,就能使用。
Dom:把整个文档作为一个对象。
DOM4J 最大的特色是使用大量的接口。它的主要接口都在org.dom4j里面定义:
Attribute | 定义了 XML 的属性。 |
Branch | 指能够包含子节点的节点。如XML元素(Element)和文档(Docuemnts)定义了一个公共的行为 |
CDATA | 定义了 XML CDATA 区域 |
CharacterData | 是一个标识接口,标识基于字符的节点。如CDATA,Comment, Text. |
Comment | 定义了 XML 注释的行为 |
Document | 定义了XML 文档 |
DocumentType | 定义 XML DOCTYPE 声明 |
Element | 定义XML 元素 |
ElementHandler | 定义了Element 对象的处理器 |
ElementPath | 被 ElementHandler 使用,用于取得当前正在处理的路径层次信息 |
Entity | 定义 XML entity |
Node | 为dom4j中所有的XML节点定义了多态行为 |
NodeFilter | 定义了在dom4j 节点中产生的一个滤镜或谓词的行为(predicate) |
ProcessingInstruction | 定义 XML 处理指令 |
Text | 定义 XML 文本节点 |
Visitor | 用于实现 Visitor模式 |
XPath | 在分析一个字符串后会提供一个 XPath 表达式 |
接口之间的继承关系如下:
interface java.lang.Cloneable
interface org.dom4j.Node
interface org.dom4j.Attribute
interface org.dom4j.Branch
interface org.dom4j.Document
interface org.dom4j.Element
interface org.dom4j.CharacterData
interface org.dom4j.CDATA
interface org.dom4j.Comment
interface org.dom4j.Text
interface org.dom4j.DocumentType
interface org.dom4j.Entity
interface org.dom4j.ProcessingInstruction
2、XML文档操作1
2.1、读取XML文档:
读写XML文档主要依赖于org.dom4j.io包,有DOMReader和SAXReader两种方式。因为利用了相同的接口,它们的调用方式是一样的。
Java代码
public static Document load(String filename) { Document document = null; try { SAXReader saxReader = new SAXReader(); document = saxReader.read(new File(filename)); //读取XML文件,获得document对象 } catch (Exception ex) { ex.printStackTrace(); } return document;
}
或Java代码 public static Document load(URL url) { Document document = null; try { SAXReader saxReader = new SAXReader(); document = saxReader.read(url); //读取XML文件,获得document对象 } catch (Exception ex) { ex.printStackTrace(); } return document; }
//读取指定的xml文件之后返回一个Document对象,这个对象代表了整个XML文档,用于各种Dom运算。执照XML文件头所定义的编码来转换。
2.2、获取根节点 根节点是xml分析的开始,任何xml分析工作都需要从根开始
Xml xml = new Xml();
Doument dom = xml.load(path + "/" + file);
Element root = dom.getRootElement();
2.3、新增一个节点以及其下的子节点与数据 Element menuElement = root.addElement("menu");
Element engNameElement = menuElement.addElement("engName");
engNameElement.setText(catNameEn);
Element chiNameElement = menuElement.addElement("chiName");
chiNameElement.setText(catName);
2.4、 写入XML文件 注意文件操作的包装类是乱码的根
Java代码 public static boolean doc2XmlFile(Document document, String filename) { boolean flag = true; try { XMLWriter writer = new XMLWriter( new OutputStreamWriter(new FileOutputStream(filename),"UTF-8")); writer.write(document); writer.close(); } catch (Exception ex) { flag = false; ex.printStackTrace(); } System.out.println(flag); return flag; }
Dom4j通过XMLWriter将Document对象表示的XML树写入指定的文件,并使用OutputFormat格式对象指定写入的风格和编码方法。调用OutputFormat. createPrettyPrint()方法可以获得一个默认的pretty print风格的格式对象。对OutputFormat对象调用setEncoding()方法可以指定XML文件的编码方法。
2. 5、 遍历xml节点 对Document对象调用getRootElement()方法可以返回代表根节点的Element对象。拥有了一个Element对象后,可以对该对象调用elementIterator()方法获得它的子节点的Element对象们的一个迭代器。使用(Element)iterator.next()方法遍历一个iterator并把每个取出的元素转化为Element类型。
2.6、创建xml文件 public static void main(String args[]){
String fileName="c:/text.xml";
Document document=DocumentHelper.createDocument();//建立document对象,用来操作xml文件
Element booksElement=document.addElement("books");//建立根节点
booksElement.addComment("This is a test for dom4j ");//加入一行注释
Element bookElement=booksElement.addElement("book");//添加一个book节点
bookElement.addAttribute("show","yes");//添加属性内容
Element titleElement=bookElement.addElement("title");//添加文本节点
titleElement.setText("ajax in action");//添加文本内容
try{
XMLWriter writer=new XMLWriter(new FileWriter(new File(fileName))); writer.write(document); writer.close();
}catch(Exception e){
e.printStackTrace();
}
}
2.7、修改节点属性 public static void modifyXMLFile() {
String oldStr = "c:/text.xml";
String newStr = "c:/text1.xml";
Document document = null;
//修改节点的属性
try {
SAXReader saxReader = new SAXReader(); // 用来读取xml文档
document = saxReader.read(new File(oldStr)); // 读取xml文档
List list = document.selectNodes("/books/book/@show");// 用xpath查找节点book的属性
Iterator iter = list.iterator();
while (iter.hasNext()) {
Attribute attribute = (Attribute) iter.next();
if (attribute.getValue().equals("yes"))
attribute.setValue("no");
}
} catch (Exception e) {
e.printStackTrace();
}
//修改节点的内容
try {
SAXReader saxReader = new SAXReader(); // 用来读取xml文档
document = saxReader.read(new File(oldStr)); // 读取xml文档
List list = document.selectNodes("/books/book/title");// 用xpath查找节点book的内容
Iterator iter = list.iterator();
while (iter.hasNext()) {
Element element = (Element) iter.next();
element.setText("xxx");// 设置相应的内容
}
} catch (Exception e) {
e.printStackTrace();
}
try {
XMLWriter writer = new XMLWriter(new FileWriter(new File(newStr)));
writer.write(document);
writer.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
2.8、删除节点 public static void removeNode() {
String oldStr = "c:/text.xml";
String newStr = "c:/text1.xml";
Document document = null;
try {
SAXReader saxReader = new SAXReader();// 用来读取xml文档
document = saxReader.read(new File(oldStr));// 读取xml文档
List list = document.selectNodes("/books/book");// 用xpath查找对象
Iterator iter = list.iterator();
while (iter.hasNext()) {
Element bookElement = (Element) iter.next();
// 创建迭代器,用来查找要删除的节点,迭代器相当于指针,指向book下所有的title节点
Iterator iterator = bookElement.elementIterator("title");
while (iterator.hasNext()) {
Element titleElement = (Element) iterator.next();
if (titleElement.getText().equals("ajax in action")) {
bookElement.remove(titleElement);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
try {
XMLWriter writer = new XMLWriter(new FileWriter(new File(newStr)));
writer.write(document);
writer.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
2、XML文档操作2 2.1、Document对象相关 1、读取XML文件,获得document对象. SAXReader reader = new SAXReader(); Document document = reader.read(new File("input.xml")); 2、解析XML形式的文本,得到document对象. String text = "<members></members>"; Document document = DocumentHelper.parseText(text); 3、主动创建document对象. Document document = DocumentHelper.createDocument(); Element root = document.addElement("members");// 创建根节点 2.2、节点相关 1、获取文档的根节点. Element rootElm = document.getRootElement(); 2、取得某节点的单个子节点. Element memberElm=root.element("member");// "member"是节点名 3.取得节点的文字 String text=memberElm.getText();
String text=root.elementText("name");这个是取得根节点下的name字节点的文字.
4.取得某节点下指定名称的所有节点并进行遍历. Java代码 List nodes = rootElm.elements("member"); for (Iterator it = nodes.iterator(); it.hasNext();) { Element elm = (Element) it.next(); // do something }
5.对某节点下的所有子节点进行遍历. Java代码 for(Iterator it=root.elementIterator();it.hasNext();){ Element element = (Element) it.next(); // do something }
6.在某节点下添加子节点.
Element ageElm = newMemberElm.addElement("age");
7.设置节点文字.
ageElm.setText("29");
8.删除某节点.
parentElm.remove(childElm); // childElm是待删除的节点,parentElm是其父节点
9.添加一个CDATA节点.
Element contentElm = infoElm.addElement("content");
contentElm.addCDATA(diary.getContent());
2.3、属性相关.
1.取得节点的指定的属性
Element root=document.getRootElement();
Attribute attribute=root.attribute("size"); // 属性名name
2.取得属性的文字
String text=attribute.getText();
String text2=root.element("name").attributeValue("firstname");
//这个是取得根节点下name字节点的firstname属性的值.
3.遍历某节点的所有属性
Element root=document.getRootElement();
for(Iterator it=root.attributeIterator();it.hasNext();){
Attribute attribute = (Attribute) it.next();
String text=attribute.getText();
System.out.println(text);
}
4.设置某节点的属性和文字.
newMemberElm.addAttribute("name", "sitinspring");
5.设置属性的文字
Attribute attribute=root.attribute("name");
attribute.setText("sitinspring");
6.删除某属性
Attribute attribute=root.attribute("size");// 属性名name
root.remove(attribute);
2.4、将文档写入XML文件.
1.文档中全为英文,不设置编码,直接写入.
XMLWriter writer = new XMLWriter(new FileWriter("output.xml"));
writer.write(document);
writer.close();
2.文档中含有中文,设置编码格式再写入.
OutputFormat format = OutputFormat.createPrettyPrint();
format.setEncoding("GBK"); // 指定XML编码
XMLWriter writer = new XMLWriter(new FileWriter("output.xml"),format);
writer.write(document);
writer.close();
2.5、字符串与XML的转换
1.将字符串转化为XML
String text = "<members> <member>sitinspring</member> </members>";
Document document = DocumentHelper.parseText(text);
2.将文档或节点的XML转化为字符串.
SAXReader reader = new SAXReader();
Document document = reader.read(new File("input.xml"));
Element root=document.getRootElement();
String docXmlText=document.asXML();
String rootXmlText=root.asXML();
Element memberElm=root.element("member");
String memberXmlText=memberElm.asXML();
3、dom4j的事件处理模型涉及的类和接口:
3.1、类:SAXReader
public voidaddHandler(String path,ElementHandler handler)
当解析到path指定的路径时,将调用参数handler指定的处理器。针对不同的节点可以添加多个handler实例。或者调用默认的Handler setDefaultHandler(ElementHandler handler);
3.2、接口ElementHandler
public void onStart(ElementPath path)
该方法在解析到元素的开始标签时被调用。
public voidonEnd(ElementPath path)
该方法在解析到元素的结束标签时被调用
3.3、接口:ElementPath(假设有参数:ElementPath path)
public voidaddHandler(String path,ElementHandler)
该方法与SAXReader类中的addHandler()方法的作用相同。路径path可以是绝对路径(路径以/开头),也可以是相对路径(假设是当前路径的子节点路径)。
public voidremoveHandler(String path)
移除指定路径上的ElementHandler实例。路径可以是相对路径,也可以是绝对路径。
public StringgetPath()
该方法得到当前节点的路径。该方法返回的是完整的绝对路径
public ElementgetCurrent()
该方法得到当前节点。
3.3、Element类
getQName() | 元素的QName对象 |
getNamespace() | 元素所属的Namespace对象 |
getNamespacePrefix() | 元素所属的Namespace对象的prefix |
getNamespaceURI() | 元素所属的Namespace对象的URI |
getName() | 元素的local name |
getQualifiedName() | 元素的qualified name |
getText() | 元素所含有的text内容,如果内容为空则返回一个空字符串而不是null |
getTextTrim() | 元素所含有的text内容,其中连续的空格被转化为单个空格,该方法不会返回null |
attributeIterator() | 元素属性的iterator,其中每个元素都是Attribute对象 |
attributeValue() | 元素的某个指定属性所含的值 |
elementIterator() | 元素的子元素的iterator,其中每个元素都是Element对象 |
element() | 元素的某个指定(qualified name或者local name)的子元素 |
elementText() | 元素的某个指定(qualified name或者local name)的子元素中的text信息 |
getParent | 元素的父元素 |
getPath() | 元素的XPath表达式,其中父元素的qualified name和子元素的qualified name之间使用"/"分隔 |
isTextOnly() | 是否该元素只含有text或是空元素 |
isRootElement() | 是否该元素是XML树的根节点 |
3.4、类DocumentHelper
DocumentHelper 是用来生成生成 XML 文档的工厂类
4、通过xpath查找指定的节点
采用xpath查找需要引入jaxen-xx-xx.jar,否则会报java.lang.NoClassDefFoundError: org/jaxen/JaxenException异常。
List list=document.selectNodes("/books/book/@show");
4.1、 xpath语法
1、选取节点
XPath 使用路径表达式在 XML 文档中选取节点,节点是沿着路径或者 step 来选取的。
常见的路径表达式:
表达式 | 描述 |
nodename | 选取当前节点的所有子节点 |
/ | 从根节点选取 |
// | 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置 |
. | 选取当前节点 |
.. | 选取当前节点的父节点 |
@ | 选取属性 |
实例
路径表达式 | 结果 |
bookstore | 选取 bookstore 元素的所有子节点 |
/bookstore | 选取根元素 bookstore |
bookstore/book | 选取bookstore 下名字为 book的所有子元素。 |
//book | 选取所有 book 子元素,而不管它们在文档中的位置。 |
bookstore//book | 选取bookstore 下名字为 book的所有后代元素,而不管它们位于 bookstore 之下的什么位置。 |
//@lang | 选取所有名为 lang 的属性。 |
2、谓语(Predicates)
谓语用来查找某个特定的节点或者包含某个指定的值的节点。
谓语被嵌在方括号中。
实例
常见的谓语的一些路径表达式:
路径表达式 | 结果 |
/bookstore/book[1] | 选取属于 bookstore 子元素的第一个 book 元素。 |
/bookstore/book[last()] | 选取属于 bookstore 子元素的最后一个 book 元素。 |
/bookstore/book[last()-1] | 选取属于 bookstore 子元素的倒数第二个 book 元素。 |
/bookstore/book[position()<3] | 选取最前面的两个属于 bookstore 元素的子元素的 book 元素。 |
//title[@lang] | 选取所有拥有名为 lang 的属性的 title 元素。 |
//title[@lang='eng'] | 选取所有 title 元素,要求这些元素拥有值为 eng 的 lang 属性。 |
/bookstore/book[price>35.00] | 选取所有 bookstore 元素的 book 元素,要求book元素的子元素 price 元素的值须大于 35.00。 |
/bookstore/book[price>35.00]/title | 选取所有 bookstore 元素中的 book 元素的 title 元素,要求book元素的子元素 price 元素的值须大于 35.00 |
3、选取未知节点
XPath 通配符可用来选取未知的 XML 元素。
通配符 | 描述 |
* | 匹配任何元素节点 |
@* | 匹配任何属性节点 |
node() | 匹配任何类型的节点 |
实例
路径表达式 | 结果 |
/bookstore/* | 选取 bookstore 元素的所有子节点 |
//* | 选取文档中的所有元素 |
//title[@*] | 选取所有带有属性的 title 元素。 |
4、选取若干路径
通过在路径表达式中使用“|”运算符,您可以选取若干个路径。
实例
路径表达式 | 结果 |
//book/title | //book/price | 选取所有 book 元素的 title 和 price 元素。 |
//title | //price | 选取所有文档中的 title 和 price 元素。 |
/bookstore/book/title|//price | 选取所有属于 bookstore 元素的 book 元素的 title 元素,以及文档中所有的 price 元素。 |
5、XPath 轴
轴可定义某个相对于当前节点的节点集。
轴名称 | 结果 |
ancestor | 选取当前节点的所有先辈(父、祖父等) |
ancestor-or-self | 选取当前节点的所有先辈(父、祖父等)以及当前节点本身 |
attribute | 选取当前节点的所有属性 |
child | 选取当前节点的所有子元素。 |
descendant | 选取当前节点的所有后代元素(子、孙等)。 |
descendant-or-self | 选取当前节点的所有后代元素(子、孙等)以及当前节点本身。 |
following | 选取文档中当前节点的结束标签之后的所有节点。 |
namespace | 选取当前节点的所有命名空间节点 |
parent | 选取当前节点的父节点。 |
preceding | 选取文档中当前节点的开始标签之前的所有节点。 |
preceding-sibling | 选取当前节点之前的所有同级节点。 |
self | 选取当前节点。 |
6、路径
Ø 位置路径表达式
位置路径可以是绝对的,也可以是相对的。
绝对路径起始于正斜杠( / ),而相对路径不会这样。在两种情况中,位置路径均包括一个或多个步,每个步均被斜杠分割:
Ø 绝对位置路径:
/step/step/...
Ø 相对位置路径:
step/step/...
每个步均根据当前节点集之中的节点来进行计算。
Ø 步(step)包括:
轴(axis):定义所选节点与当前节点之间的树关系
节点测试(node-test):识别某个轴内部的节点
零个或者更多谓语(predicate):更深入地提炼所选的节点集
步的语法:轴名称::节点测试[谓语]
实例
例子 | 结果 |
child::book | 选取所有属于当前节点的子元素的 book 节点 |
attribute::lang | 选取当前节点的 lang 属性 |
child::* | 选取当前节点的所有子元素 |
attribute::* | 选取当前节点的所有属性 |
child::text() | 选取当前节点的所有文本子节点 |
child::node() | 选取当前节点的所有子节点 |
descendant::book | 选取当前节点的所有 book 后代 |
ancestor::book | 选择当前节点的所有 book 先辈 |
ancestor-or-self::book | 选取当前节点的所有book先辈以及当前节点(假如此节点是book节点的话) |
child::*/child::price | 选取当前节点的所有 price 孙。 |
7、XPath 运算符
运算符 | 描述 | 实例 | 返回值 |
| | 计算两个节点集 | //book | //cd | 返回所有带有 book 和 ck 元素的节点集 |
+ | 加法 | 6 + 4 | 10 |
- | 减法 | 6 - 4 | 2 |
* | 乘法 | 6 * 4 | 24 |
div | 除法 | 8 div 4 | 2 |
= | 等于 | price=9.80 | 如果 price 是 9.80,则返回 true。 如果 price 是 9.90,则返回 fasle。 |
!= | 不等于 | price!=9.80 | 如果 price 是 9.90,则返回 true。 如果 price 是 9.80,则返回 fasle。 |
< | 小于 | price<9.80 | 如果 price 是 9.00,则返回 true。 如果 price 是 9.90,则返回 fasle。 |
<= | 小于或等于 | price<=9.80 | 如果 price 是 9.00,则返回 true。 如果 price 是 9.90,则返回 fasle。 |
> | 大于 | price>9.80 | 如果 price 是 9.90,则返回 true。 如果 price 是 9.80,则返回 fasle。 |
>= | 大于或等于 | price>=9.80 | 如果 price 是 9.90,则返回 true。 如果 price 是 9.70,则返回 fasle。 |
or | 或 | price=9.80 or price=9.70 | 如果 price 是 9.80,则返回 true。 如果 price 是 9.50,则返回 fasle。 |
and | 与 | price>9.00 and price<9.90 | 如果 price 是 9.80,则返回 true。 如果 price 是 8.50,则返回 fasle。 |
mod | 计算除法的余数 | 5 mod 2 | 1 |
读取和保存XML方法简单总结
read xml
1.dom4j
SAXReader sax = new SAXReader();
sax.setEncoding("UTF-8");//记得与XML文件实际的编码一致.
Document document = saxReader.read(inputXml);//inputXml文件路径.
2.jdom
SAXBuilder buider = new SAXBuilder();
Document document = saxReader.read(inputXml);//inputXml是FILE的对象.
save xml
1.dom4j方法1
OutputFormat format = OutputFormat.createPrettyPrint();
fomat.setEncoding("UTF-8");
//outXmlPath是保存XML的文件全路径
XMLWrite write = new XMLWriter(new FileWrite(outXmlPath),format);
writer.write(document);
writer.close();
2.dom4j方法2
//outXmlPath是保存XML的文件全路径
XMLWriter writer = new XMLWriter(new OutputStreamWriter(new FileOutputStream
(outXmlPath),"UTF-8"));
writer.write(document);
writer.close();