XML 指可扩展标记语言
XML 被设计用来传输和存储数据
XML 需要自定义标签
XML 必须有一个跟元素,该元素是其他元素的父元素
XML 对大小写敏感
XML 把数据从 HTML 分离
XML 简化数据共享
XML 简化数据传输
XML 简化平台的变更
XML 使您的数据更有用
XML 用于创建新的 Internet 语言
所有 XML 元素都须有关闭标签
XML 标签对大小写敏感
XML 必须正确地嵌套
XML 文档必须有根元素
在 XML 中,空格会被保留
XML 以 LF 存储换行
XML 的属性值须加引号
实体引用
在 XML 中,有 5 个预定义的实体引用:
< | < | 小于 |
---|---|---|
> | > | 大于 |
& | & | 和号 |
' | ' | 单引号 |
" | " | 引号 |
常用的解析XML的方式有三种,分别为:
DOM
DOM解析XML在J2EE中比较常见,在DOM解析过程中,是先把XML文件全部读取到内存中,然后使用DOM的API遍历所有数据,检索想要的数据
这种做法的缺点是耗费内存,对于像手机这类的移动设备来说,较大的XML文件显然不适合使用DOM解析。
这种做法的优点是比较直观,在XML文件比较小的时候可以使用
Pull
PULL提供了开始元素和结束元素。当某个元素开始时,可以调用parser.nextText()从XML文档中提取所有字符数据,当解析到一个文档结束时,自动生成EndDocument事件
SAX
SAX是一个解析速度快并且占用内存少的xml解析器,非常适合用于Android等移动设备。
SAX解析XML文件采用的是事件驱动,也就是说,它并不需要解析完整个文档。
在按内容顺序解析文档的过程中,SAX会判断当前读到的字符是否合法XML语法中的某部分,如果符合就会触发事件。
DOM方式写XML文件大致可归纳为如下几步:
利用DocumentBuilderFactory创建一个DocumentBuilderFactory实例
利用DocumentBuilderFactory创建DocumentBuilder
利用DocumentBuilder创建Document文件
创建根节点
将根节点添加到Document中
利用循环将数据添加到Document中
使用TransformerFactory创建一个TransformerFactory对象
使用TransformerFactory对象创建一个新的事务
创建DOMSource
创建文件
示例代码:
public class MainActivity extends Activity {
private List list = new ArrayList();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
addData();
try {
// 利用DocumentBuilderFactory创建一个DocumentBuilderFactory实例
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
// 利用DocumentBuilderFactory创建DocumentBuilder
DocumentBuilder builder = factory.newDocumentBuilder();
// 利用DocumentBuilder创建Document文件
Document document = builder.newDocument();
// 创建根节点
Element rootElement = document.createElement("students");
// 将根节点添加到Document中
document.appendChild(rootElement);
// 利用循环将数据添加到Document中
for (int i = 0; i < list.size(); i++) {
int id = list.get(i).getId();
String name = list.get(i).getName();
int age = list.get(i).getAge();
String sex = list.get(i).getSex();
Element studentElement = document.createElement("student");
studentElement.setAttribute("id", id + "");
Element nameElement = document.createElement("name");
nameElement.setTextContent(name);
Element ageElement = document.createElement("age");
ageElement.setTextContent(age + "");
Element sexElement = document.createElement("sex");
sexElement.setTextContent(sex);
studentElement.appendChild(nameElement);
studentElement.appendChild(ageElement);
studentElement.appendChild(sexElement);
rootElement.appendChild(studentElement);
}
// 创建TransformerFactory实例
TransformerFactory tf = TransformerFactory.newInstance();
// 创建事务对象
Transformer transformer = tf.newTransformer();
// 创建DOMSource
DOMSource source = new DOMSource(document);
// 创建文件存放在 /data/data/cn.xxx.xxx(当前包)/files
FileOutputStream fos = openFileOutput("Dom.xml", Context.MODE_PRIVATE);
PrintWriter pw = new PrintWriter(fos);
StreamResult result = new StreamResult(pw);
// 使用事务的transform方法写入文件
transformer.transform(source, result);
} catch (ParserConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (TransformerConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (TransformerException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private void addData() {
list.add(new Student(1, "刘德华", 50, "男"));
list.add(new Student(2, "郭富城", 60, "男"));
list.add(new Student(3, "林志玲", 40, "女"));
list.add(new Student(4, "高圆圆", 40, "女"));
list.add(new Student(5, "张学友", 53, "男"));
list.add(new Student(6, "孙燕姿", 30, "女"));
}
}
创建的XML文件:
<?xml version="1.0" encoding="UTF-8"?>
<students>
<student id="1">
<name>刘德华</name>
<age>50</age>
<sex>男</sex>
</student>
<student id="2">
<name>郭富城</name>
<age>60</age>
<sex>男</sex>
</student>
<student id="3">
<name>林志玲</name>
<age>40</age>
<sex>女</sex>
</student>
<student id="4">
<name>高圆圆</name>
<age>40</age>
<sex>女</sex>
</student>
<student id="5">
<name>张学友</name>
<age>53</age>
<sex>男</sex>
</student>
<student id="6">
<name>孙燕姿</name>
<age>30</age>
<sex>女</sex>
</student>
</students>
DOM方式读XML文件大致可归纳为如下几步:
利用DocumentBuilderFactory创建一个DocumentBuilderFactory实例
利用DocumentBuilderFactory创建DocumentBuilder
使用openFileInput来读取XML文件
调用DocumentBuilder的parse()方法完成解析XML,这步执行完成之后,XML暂存在内存中
通过DocumentBuilder的getDocumentElement()方法获取XML的根节点
通过根节点的getElementsByTagName()方法获取根节点中所有子节点列表
通过循环+getElementsByTagName获取子节点列表中需要读取的节点
示例代码:
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
FileInputStream fis = openFileInput("Dom.xml");
Document document = builder.parse(fis);
Element rootElement = document.getDocumentElement();
NodeList element = rootElement.getElementsByTagName("student");
for (int i = 0; i < element.getLength(); i++) {
Element node = (Element) element.item(i);
String id = node.getAttribute("id");
String name = node.getElementsByTagName("name").item(0).getTextContent();
int age = Integer.parseInt(node.getElementsByTagName("age").item(0).getTextContent());
String sex = node.getElementsByTagName("sex").item(0).getTextContent();
Log.d("TTTT", "id=" + id + ",name=" + name + ",age=" + age + ",sex=" + sex);
}
} catch (ParserConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (FileNotFoundException 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();
}
}
}
PULL提供了开始元素和结束元素。当某个元素开始时,可以调用parser.nextText()从XML文档中提取所有字符数据,当解析到一个文档结束时,自动生成EndDocument事件。
类和接口 | 功能 |
---|---|
XmlPullParser | 该解析器是一个在org.xmlpull.v1中定义的解析功能的接口。 |
XmlSerializer | 它是一个接口,定义了XML信息集的序列。 |
XmlPullParserFactory | 这个类用于在XMPULL V1 API中创建XML Pull解析器。 |
XmlPullParserException | 抛出单一的XML pull解析器相关的错误。 |
PULL提供了开始元素和结束元素。
当某个元素开始时,可以调用parser.nextText()从XML文档中提取所有字符数据,当解析到一个文档结束时,自动生成EndDocument事件。
如:开始元素和结束元素事件,使用parser.next()可以进入下一个元素并触发相应事件。事件将作为数值代码被发送,因此可以使用一个switch对感兴趣的事件进行处理。当元素开始解析时,调用parser.nextText()方法可以获取下一个Text类型元素的值。
START_DOCUMENT
读取到xml时的声明
END_DOCUMENT
结束时返回
START_TAG
开始标签时返回
END_TAG
结束标签时返回
示例代码:
public class MainActivity extends Activity {
private List list = new ArrayList();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dataInList();
try {
FileOutputStream fos = openFileOutput("pull.xml", MODE_PRIVATE);
XmlSerializer xmlSerializer = Xml.newSerializer();
xmlSerializer.setOutput(fos, "UTF-8");
xmlSerializer.startTag(null, "students");
for (Student student : list) {
xmlSerializer.startTag(null, "student");
xmlSerializer.attribute(null, "id", student.getId() + "");
xmlSerializer.startTag(null, "name");
xmlSerializer.text(student.getName());
xmlSerializer.endTag(null, "name");
xmlSerializer.startTag(null, "age");
xmlSerializer.text(student.getAge() + "");
xmlSerializer.endTag(null, "age");
xmlSerializer.startTag(null, "sex");
xmlSerializer.text(student.getSex());
xmlSerializer.endTag(null, "sex");
xmlSerializer.endTag(null, "student");
}
xmlSerializer.endTag(null, "students");
xmlSerializer.endDocument();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private void dataInList() {
list.add(new Student(1, "张一", 10, "男"));
list.add(new Student(2, "张二", 20, "女"));
list.add(new Student(3, "张三", 30, "男"));
list.add(new Student(4, "张四", 40, "女"));
list.add(new Student(5, "张五", 50, "男"));
list.add(new Student(6, "张六", 60, "女"));
}
}
利用pull解析XML文件需要下面几个步骤:
通过XMLPullParserFactory获取XMLPullParser对象。
通过XMLPullParser对象设置输入流。
通过parser.next(),持续的解析XML文件直到文件的尾部。
示例代码:
public class MainActivity extends Activity {
private List studentList = new ArrayList();
private Student student = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
try {
FileInputStream fis = openFileInput("pull.xml");
// 1.使用android提供的Xml类new一个XmlPullerParser,即new一个XmlPull解析器
XmlPullParser xmlPullParser = Xml.newPullParser();
// 2.然后设置需要解析的xml文件,第一个参数为输入流,第二个参数为字符编码
xmlPullParser.setInput(fis, "UTF-8");
// 3.触发事件,当这个方法遇到某个字符符合XML语法,就会触发这个语法所代表的数字
int event = xmlPullParser.getEventType();
// 4.XML文件的第一行为开始文档事件START_DOCUMENT,最后一行为结束文档事件END_DOCUMENT,我们需要不断读取xml文件的内容
while (event != xmlPullParser.END_DOCUMENT) {
// 5.我们对这个事件进行处理,我们感兴趣的是这个元素
switch (event) {
case XmlPullParser.START_TAG:// 6.如果这个事件是开始元素(例如)事件
if (xmlPullParser.getName().equals("student")) {
student = new Student();
// 7.使用解析器得到当前元素的属性,即id
int id = Integer.parseInt(xmlPullParser.getAttributeValue(0));
student.setId(id);
} else if (xmlPullParser.getName().equals("name")) {
// 8.如果当前元素为开始标签,下一个元素为文本,就会返回这个文本
student.setName(xmlPullParser.nextText());
} else if (xmlPullParser.getName().equals("age")) {
// 8.如果当前元素为开始标签,下一个元素为文本,就会返回这个文本
student.setAge(Integer.parseInt(xmlPullParser.nextText()));
} else if (xmlPullParser.getName().equals("sex")) {
// 8.如果当前元素为开始标签,下一个元素为文本,就会返回这个文本
student.setSex(xmlPullParser.nextText());
}
break;
case XmlPullParser.END_TAG:// 9.如果这个事件是结束元素(例如)事件
if ("student".equals(xmlPullParser.getName())) {
studentList.add(student);
}
break;
}
event = xmlPullParser.next();
}
for (Student student : studentList) {
Log.d("TTTT", "id:" + student.getId() + ",name:" + student.getName() + ",age:" + student.getAge()
+ ",sex:" + student.getSex());
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (XmlPullParserException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
SAX是一个解析速度快并且占用内存少的xml解析器,非常适合用于Android等移动设备。SAX解析XML文件采用的是事件驱动,也就是说,它并不需要解析完整个文档。
在按内容顺序解析文档的过程中,SAX会判断当前读到的字符是否合法XML语法中的某部分,如果符合就会触发事件。
所谓事件,其实就是一些回调(callback)方法,这些方法(事件)定义在ContentHandler接口。
下面是一些ContentHandler接口常用的方法:
startDocument()
当遇到文档的开头的时候,调用这个方法,可以在其中做一些预处理的工作。
endDocument()
和上面的方法相对应,当文档结束的时候,调用这个方法,可以在其中做一些善后的工作。
startElement(String namespaceURI, String localName, String qName, Attributes atts)
当读到一个开始标签的时候,会触发这个方法。
namespaceURI
命名空间
localName
不带命名空间前缀的标签名
qName
带命名空间前缀的标签名
atts
通过atts可以得到所有的属性名和相应的值
endElement(String uri, String localName, String name)
这个方法和上面的方法相对应,在遇到结束标签的时候,调用这个方法。
characters(char[] ch, int start, int length)
这个方法用来处理在XML文件中读到的内容,第一个参数为文件的字符串内容,后面两个参数是读到的字符串在这个数组中的起始位置和长度,使用new String(ch,start,length)就可以获取内容。
要注意的是SAX中一个重要的特点就是它的流式处理,当遇到一个标签的时候,它并不会纪录下以前所碰到的标签,也就是说,在startElement()方法中,所有你所知道的信息,就是标签的名字和属性,至于标签的嵌套结构,上层标签的名字,是否有子元属等等其它与结构相关的信息,都是不得而知的,都需要你的程序来完成。这使得SAX在编程处理上没有DOM来得那么方便。
public class MainActivity extends Activity {
private List list = new ArrayList();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dataInList();
try {
FileOutputStream fos = openFileOutput("sax.xml", MODE_PRIVATE);
SAXTransformerFactory saxTransformerFactory = (SAXTransformerFactory) SAXTransformerFactory.newInstance();
TransformerHandler transformerHandler = saxTransformerFactory.newTransformerHandler();
Transformer transformer = transformerHandler.getTransformer();
// 设置XML的格式
transformer.setOutputProperty(OutputKeys.INDENT, "yes"); // 是否缩进
transformer.setOutputProperty(OutputKeys.ENCODING, "utf-8"); // 字符集
transformer.setOutputProperty(OutputKeys.VERSION, "1.0"); // 版本号
transformerHandler.setResult(new StreamResult(fos));
transformerHandler.startDocument();
AttributesImpl attributesImpl = new AttributesImpl();
attributesImpl.clear();
transformerHandler.startElement("", "", "students", attributesImpl);
for (Student student : list) {
attributesImpl.clear();
attributesImpl.addAttribute("", "", "id", "", student.getId() + "");
transformerHandler.startElement("", "", "student", attributesImpl);
attributesImpl.clear();
transformerHandler.startElement("", "", "name", attributesImpl);
transformerHandler.characters(student.getName().toCharArray(), 0, student.getName().length());
transformerHandler.endElement("", "", "name");
attributesImpl.clear();
transformerHandler.startElement("", "", "age", attributesImpl);
transformerHandler.characters((student.getAge() + "").toCharArray(), 0,
(student.getAge() + "").length());
transformerHandler.endElement("", "", "age");
attributesImpl.clear();
transformerHandler.startElement("", "", "sex", attributesImpl);
transformerHandler.characters(student.getSex().toCharArray(), 0, student.getSex().length());
transformerHandler.endElement("", "", "sex");
transformerHandler.endElement("", "", "student");
}
transformerHandler.endElement("", "", "students");
transformerHandler.endDocument();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (TransformerConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SAXException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private void dataInList() {
list.add(new Student(1, "张一", 10, "男"));
list.add(new Student(2, "张二", 20, "女"));
list.add(new Student(3, "张三", 30, "男"));
list.add(new Student(4, "张四", 40, "女"));
list.add(new Student(5, "张五", 50, "男"));
list.add(new Student(6, "张六", 60, "女"));
}
}
解析SAX我们通常会创建一个继承自DefaultHandler,并重写父类的几个方法
public void setDocumentLocator(Locator locator)
设置一个可以定位文档内容事件发生位置的定位器对象
public void startDocument()throws SAXException
用于处理文档解析开始事件
public void startElement(String namespacesURI , String localName , String qName , Attributes atts) throws SAXException
处理元素开始事件,从参数中可以获得元素所在名称空间的uri,元素名称,属性类表等信息
public void endElement(String namespacesURI , String localName , String qName) throws SAXException
处理元素结束事件,从参数中可以获得元素所在名称空间的uri,元素名称等信息
public void characters(char[] ch , int start , int length) throws SAXException
处理元素的字符内容,从参数中可以获得内容
在android中使用SAX是有迹可循的,完全可以按照下面的方法就可以轻松找到xml里的tag,然后得到想要的内容。具体实现步骤如下:
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser parser = factory.newSAXParser();
XMLReader reader = parser.getXMLReader();
RSSHandler handler = new RSSHandler();
reader.setContentHandler(handler);
parser.parse(is);
示例代码:
MainActivity.java
public class MainActivity extends Activity {
private List list = new ArrayList();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
try {
FileInputStream fis = openFileInput("sax.xml");
MyXMLHandler handler = new MyXMLHandler();
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser parser = factory.newSAXParser();
parser.parse(fis, handler);
fis.close();
ArrayList list = (ArrayList) handler.getList();
for (Student student : list) {
Log.d("TTTT", "id:" + student.getId() + ",name:" + student.getName() + ",age:" + student.getAge()
+ ",sex:" + student.getSex());
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} 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();
}
}
}
MyXMLHandler.java
public class MyXMLHandler extends DefaultHandler {
private ArrayList list;
private Student student;
private String tagName;
public List getList() {
return list;
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
// TODO Auto-generated method stub
super.characters(ch, start, length);
// Log.d("TTTT", "根据tagName获取标签的内容");
if (tagName != null) {
String data = new String(ch, start, length);
if (tagName.equals("name")) {
student.setName(data);
} else if (tagName.equals("age")) {
student.setAge(Integer.valueOf(data.trim()));
} else if (tagName.equals("sex")) {
student.setSex(data);
}
}
}
@Override
public void endDocument() throws SAXException {
// TODO Auto-generated method stub
super.endDocument();
Log.d("TTTT", "解析XML结束");
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
// TODO Auto-generated method stub
super.endElement(uri, localName, qName);
if (localName.equals("student")) {
list.add(student);
}
tagName = null;
}
@Override
public void startDocument() throws SAXException {
// TODO Auto-generated method stub
super.startDocument();
list = new ArrayList();
Log.d("TTTT", "解析XML开始");
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
// TODO Auto-generated method stub
super.startElement(uri, localName, qName, attributes);
Log.d("TTTT", "读取标签");
this.tagName = localName;
if ("student".equals(tagName)) {
student = new Student();
student.setId(Integer.parseInt(attributes.getValue(0)));
Log.d("TTTT", "id:" + attributes.getValue(0));
}
}
}