xml 是数据传输的一种格式,Android 中的布局文件、设置文件等都采用它来表示。Android 中对 xml 文件的解析也有多种方式,下面介绍常用的 3 种方式: Dom 、 SAX 和 dom4j。
先看一个简单的 xml 文件:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<书 出版社="骏马">
<书名>如何成功</书名>
<作者>uniapp</作者>
<售价>666</售价>
</书>
<书>
<书名>如何成功1</书名>
<作者>uniapp</作者>
<售价>1991</售价>
</书>
</书架>
1 Dom解析方式
Dom 解析通过 Document 类将整个 xml 文件一次读入内存,然后通过操作 Document 实例的属性实现对 xml 文件中元素的增删改查,具体代码如下:
/**
* 查看所有元素名称
* */
private void printAllElement(Node node){
if (Node.ELEMENT_NODE==node.getNodeType()){
System.out.println(node.getNodeName());
}
NodeList ns = node.getChildNodes();
for (int i = 0; i < ns.getLength(); i++) {
node = ns.item(i);
printAllElement(node);
}
}
/**
* 更新元素
* */
private void updateElement() throws ParserConfigurationException, SAXException, IOException, TransformerException {
Document doc = getDocument();
NodeList ns = doc.getElementsByTagName("售价");
Element el = (Element) ns.item(0);
el.setTextContent("666");
writeBackToXml(doc);
}
/**
* 删除节点
* */
private void deleteElement() throws ParserConfigurationException, SAXException, IOException, TransformerException {
Document doc = getDocument();
NodeList ns = doc.getElementsByTagName("售价");
for (int i = 0; i < ns.getLength(); i++) {
Node node = ns.item(i);
if ("111".equals(node.getTextContent())){
node.getParentNode().removeChild(node);
}
}
writeBackToXml(doc);
}
/**
* 插入元素节点
* */
private void addElement() throws ParserConfigurationException, SAXException, IOException, TransformerException {
Document doc = getDocument();
NodeList nl = doc.getElementsByTagName("书");
int l = nl.getLength();
System.out.print("\n长度" + l + "\n");
Node n = nl.item(0);
Element element = doc.createElement("售价");
element.setTextContent("888");
n.appendChild(element);
writeBackToXml(doc);
}
/**
* 将 Doc 写入新文件
* */
private void writeBackToXml(Document doc) throws TransformerException {
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer();
transformer.transform(new DOMSource(doc), new StreamResult("./app/src/main/java/test/DTD.xml"));
}
/**
* 获取 Doc 对象
* */
private Document getDocument() throws ParserConfigurationException, SAXException, IOException {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder build = factory.newDocumentBuilder();
Document document = build.parse("./app/src/main/java/test/DTD.xml");
return document;
}
2 SAX解析
SAX 对 xml 文件采用边读边解析的方式,就像我们用眼睛读文章一样,一行一行的进行。相比 Dom 方式产生的瞬时内存峰值,SAX 对内存的消耗比较平稳。它通过解析类提供对外接口,具体实现:
public class SaxDemo {
@Test
public void main() throws ParserConfigurationException, SAXException, IOException{
//工厂类实例
SAXParserFactory fac = SAXParserFactory.newInstance();
//创建解析器
SAXParser parser = fac.newSAXParser();
//解析文档
XMLReader reader = parser.getXMLReader();
reader.setContentHandler(new MyDefultHandle());
reader.parse("./app/src/main/java/test/DTD.xml");
}
}
class MyDefultHandle extends DefaultHandler{
@Override
public void startDocument() throws SAXException {
super.startDocument();
System.out.println("文档开始");
}
@Override
public void endDocument() throws SAXException {
super.endDocument();
System.out.println("文档结束");
}
private boolean isPrice = false;
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
super.startElement(uri, localName, qName, attributes);
System.out.println("元素开始: " + qName);
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
super.endElement(uri, localName, qName);
if ("售价".equals(qName)){
isPrice = false;
}
System.out.println("元素结束: " + qName);
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
super.characters(ch, start, length);
if (isPrice){
System.out.println("内容: " + new String(ch, start, length));
}
}
}
3 Dom4j 解析
Dom4j 解析是第三开源库给出的解析方式,结合了 Dom 和 SAX 双方的优点,对 xml 文件逐步读入内存,并且可以采用面向对象的方式访问节点。代码如下:
/**
* 读取属性值
* */
public void readAttr() throws DocumentException {
Document doc = getDocument();
List<Element> list = doc.getRootElement().elements("书");
for (int i = 0; i < list.size(); i++) {
Element el = (Element) list.get(i);
Attribute att = el.attribute("出版社");
System.out.print("结果: " + att.getName() + att.getValue());
}
}
/**
* 读取节点
* */
public void read() throws DocumentException {
/**
* 不能越级获取值
* */
Document doc = getDocument();
org.dom4j.Element el = doc.getRootElement();
Element firstEl = el.element("书");
Element firstBookEl = firstEl.element("书名");
String name = firstBookEl.getText();
System.out.println("书名: " + name);
}
public void update() throws DocumentException, IOException {
Document doc = getDocument();
List<Element> list = doc.getRootElement().elements("书");
Element element = list.get(0);
Element priceEl = element.element("售价");
priceEl.setText("888元");
XMLWriter writer = new XMLWriter(new FileOutputStream("./app/src/main/java/test/Dom4j3.xml"));
writer.write(doc);
}
/**
* 删除节点
* */
public void deletePrice() throws Exception{
SAXReader reader = new SAXReader();
Document doc = reader.read("./app/src/main/java/test/Dom4j1.xml");
Element el = (Element) doc.getRootElement().elements("书").get(1);
Element elPrice = (Element) el.elements("售价").get(1);
elPrice.getParent().remove(elPrice);
XMLWriter writer = new XMLWriter(new FileOutputStream("./app/src/main/java/test/Dom4j2.xml"));
writer.write(doc);
writer.close();
}
/**
* 增加节点
* */
public void addEl() throws DocumentException, IOException {
Document doc = getDocument();
Element el = (Element) doc.getRootElement().elements("书").get(1);
el.addElement("售价").setText("6.66元");
XMLWriter writer = new XMLWriter(new FileOutputStream("./app/src/main/java/test/Dom4j1.xml"));
writer.write(doc);
writer.close();
}
private Document getDocument() throws DocumentException {
SAXReader reader = new SAXReader();
return reader.read("./app/src/main/java/test/DTD.xml");
}
结合以上三种解析方式的特点,我们可以得出结论:如果 xml 文件很小,可以选择面向对象的 Dom 或者 dom4j 方式;反之可以选择 SAX 方式,一面实际内存不足造成闪退。
网友评论