目录

  • ​​解析​​
  • ​​PULL 解析​​
  • ​​SAX 解析​​
  • ​​DOM 解析​​
  • ​​序列化生成 XML 文档​​
  • ​​SAX、DOM、PULL比较​​

解析

将要解析的数据

<persons>
<person id="1">
<name>zhangsan</name>
<age>22</age>
</person>
<person id="2">
<name>wanger</name>
<age>24</age>
</person>
<person id="3">
<name>lisi</name>
<age>26</age>
</person>
<person id="4">
<name>zhaoliu</name>
<age>28</age>
</person>
</persons>

PULL 解析

// 类似 SAX解析,基于事件流,允许主动从解析器中获取事件,可主动结束解析(跳出 while)

/**
* 1. 通过解析器工厂获取 PULL 解析器:
* 2. 设置 XML 文件的编码格式
* 3. 获取当前事件类型:返回为整型值
* 4. while 循环判断事件类型:END_DOCUMENT、START_TAG、END_TAG
* 5. 获取当前结点名:getName();获取下一节点文本:nextText()
* 6. 注意最后将指针移至下一节点,并返回该节点的事件类型 next()
*
* PS 事件类型主要有五个:
* START_DOCUMENT: XML 头文件的事件类型
* END_DOCUMENT: XML 文件尾的事件类型
* START_TAG: 开始节点的事件类型
* END_TAG: 结束节点的事件类型
* TEXT: 文本节点的事件类型
*/

private List<Person> pullParseXML(String result) {

List<Person> persons = null;
Person person = null;

try {
XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser();
parser.setInput(new StringReader(result));

// 当前事件类型
int eventType = parser.getEventType();

// 直到文档末尾才停止解析
while (eventType != XmlPullParser.END_DOCUMENT) {

switch (eventType) {

case XmlPullParser.START_DOCUMENT:
persons = new ArrayList<>();
break;

case XmlPullParser.START_TAG:
if ("person".equals(parser.getName())) {
person = new Person();
person.setId(parser.getAttributeValue(0));
} else if ("name".equals(parser.getName())) {
person.setName(parser.nextText());
} else if ("age".equals(parser.getName())) {
person.setAge(parser.nextText());
}
break;

case XmlPullParser.END_TAG:
if ("person".equals(parser.getName())) {
persons.add(person);
person = null;
}
break;
}

// 通过 next() 方法触发下一事件
eventType = parser.next();
}
return persons;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}

// 调用方式,下同
List<Person> persons = pullParseXML(HttpTool.doGet("http://10.0.2.2:8080/xml.xml"));

SAX 解析

// 基于事件流,会自动将事件推入事件处理器进行处理,不能控制主动结束解析

/**
* 1. 通过解析器工厂获取 SAX 解析器
* 2. 通过 DefaultHandler 处理类解析
*/

private List<Person> saxParseXML(String result) {
try {
SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
PersonHandler handler = new PersonHandler();
parser.parse(new ByteArrayInputStream(result.getBytes()), handler);

// 处理类返回集合
return handler.getPersons();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}

class PersonHandler extends DefaultHandler {

private List<Person> persons;
private Person person;

@Override
public void startDocument() throws SAXException {
persons = new ArrayList<>();
}

// 分别记录当前解析到的标签名、值
private String currentTag, currentValue;
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
if ("person".equals(qName)) {
person = new Person();

for (int i = 0; i < attributes.getLength(); i++) {
if ("id".equals(attributes.getQName(i))) {
person.setId(attributes.getValue(i));
}
}
}

// 设置当前标签名
currentTag = qName;
}

@Override
public void characters(char[] ch, int start, int length) throws SAXException {
currentValue = new String(ch, start, length);
if (null != currentValue && !TextUtils.isEmpty(currentValue) && !"\n".equals(currentValue)) {
if ("name".equals(currentTag)) {
person.setName(currentValue);
} else if ("age".equals(currentTag)) {
person.setAge(currentValue);
}
}
currentTag = null;
currentValue = null;
}

@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if ("person".equals(qName)) {
persons.add(person);
person = null;
}
}

public List<Person> getPersons() {
return persons;
}
}

DOM 解析

/** 解析时会将整个文档加载进内存,极占内存资源,不推荐用(移动端) */

private List<Person> domParseXML(String result) {
try {
List<Person> persons = new ArrayList<>();

// 加载文档
Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new ByteArrayInputStream(result.getBytes()));

// 根元素节点
Element documentElement = document.getDocumentElement();

// 标签为 person 的节点集合
NodeList nodeList = documentElement.getElementsByTagName("person");
for (int i = 0; i < nodeList.getLength(); i++) {

Person person = new Person();

// 若当前节点是元素
if (nodeList.item(i).getNodeType() == Document.ELEMENT_NODE) {
Element personElement = (Element) nodeList.item(i);

// 元素的属性值
person.setId(personElement.getAttribute("id"));

// person 元素下的子元素集
NodeList childNodeList = personElement.getChildNodes();
for (int j = 0; j < childNodeList.getLength(); j++) {
if (childNodeList.item(j).getNodeType() == Document.ELEMENT_NODE) {
if ("name".equals(childNodeList.item(j).getNodeName())) {
person.setName(childNodeList.item(j).getFirstChild().getNodeValue());
} else if ("age".equals(childNodeList.item(j).getNodeName())) {
person.setAge(childNodeList.item(j).getFirstChild().getNodeValue());
}
}
}
}

persons.add(person);
person = null;
}

return persons;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}

xml使用_List

序列化生成 XML 文档

/** 序列化创建元素或属性 */

XmlSerializer xmlSerializer = Xml.newSerializer();

FileOutputStream fos = new FileOutputStream(new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/demo.xml"));

xmlSerializer.setOutput(fos, "UTF-8");

xmlSerializer.startDocument("UTF-8", true);

xmlSerializer.startTag(null, "persons");

xmlSerializer.startTag(null, "person").attribute(null, "id", "1");
xmlSerializer.startTag(null, "name").text("zhangsan").endTag(null, "name");
xmlSerializer.startTag(null, "age").text("27").endTag(null, "age");
xmlSerializer.endTag(null, "person");

xmlSerializer.startTag(null, "person").attribute(null, "id", "2");
xmlSerializer.startTag(null, "name").text("zhaoliu").endTag(null, "name");
xmlSerializer.startTag(null, "age").text("29").endTag(null, "age");
xmlSerializer.endTag(null, "person");

xmlSerializer.startTag(null, "person").attribute(null, "id", "3");
xmlSerializer.startTag(null, "name").text("wangwu").endTag(null, "name");
xmlSerializer.startTag(null, "age").text("26").endTag(null, "age");
xmlSerializer.endTag(null, "person");

xmlSerializer.startTag(null, "person").attribute(null, "id", "4");
xmlSerializer.startTag(null, "name").text("lisi").endTag(null, "name");
xmlSerializer.startTag(null, "age").text("24").endTag(null, "age");
xmlSerializer.endTag(null, "person");
xmlSerializer.endTag(null, "persons");

xmlSerializer.endDocument();

xml使用_android_02

SAX、DOM、PULL比较

  1. sax、pull 占用内存比 dom 少,适合Android开发
  2. sax 基于事件驱动,每解析一类xml就需要创建新的对应的处理类
    dom 遵循 W3C 规范,广为熟知和运用
    pull 简洁性高
  3. dom 可随机访问xml中任意一个节点,sax 和 pull 采用的是流式解析
  4. sax、pull 解析方式是同步的,即解析器读到哪就对哪里进行处理
    dom 则是逐字逐句进行解析,并先将xml加载进内存全部读完后再操作