XML 简介
XML(EXtensible Markup Language) 指可扩展标记语言,是一种标记语言类似 HTML。设计宗旨是传输数据,而非显示数据,是 W3C 的推荐标准。  
树结构

对应的标准 XML 文件为:  
1  | 
  | 
名称解释
- 声明
第一行为XML的声明,包含XML的版本version,字符编码集encoding,是否独立standalone。注意:这三个声明顺序不能颠倒。 version
版本,基本上都是 1.0 版本。encoding
编码,常用编码utf-8standalone
表示该XML是不是独立的,如果是yes,则表示这个XML文档是独立的,不能引用外部的DTD规范文件;如果是no,则该XML文档不是独立的,表示可以用外部的DTD规范文档。一般情况下不设置。- 根元素
bookstore:表示根元素。 - 元素 
elementbook:表示为元素,可以并列多个。title, author, year, price:也是元素,它们是book的子元素。只是book元素没有值,而title它们每个元素有一个对应值。 - 文本 
text<title lang="en">Everyday Italian</title>:元素title的文本为Everyday Italian。 - 属性 
attributecategory, lang:表示为元素的属性,每个元素可以有多个属性,用空格分开。Android中布局文件就是典型的多属性无文本方案。 - 属性的名称和值
属性:lang="en"。属性的名称为:lang,对应的值为:en。 
DOM 简介
XML DOM (XML Document Object Model) 定义了访问和操作 XML 文档的标准方法,是 W3C(万维网联盟) 的推荐标准。DOM 把 XML 文档作为树结构来查看。能够通过 DOM 树来访问所有元素。可以修改或删除它们的内容,并创建新的元素。元素,它们的文本,以及它们的属性,都被认为是节点。
名称解释 - 节点
XML 文档中的每个成分都是一个节点(Node),DOM 是这样规定的:  
- 整个文档是一个文档节点
 - 每个 
XML标签是一个元素节点 - 包含在 
XML元素中的文本是文本节点 - 每一个 
XML属性是一个属性节点 - 注释属于注释节点
 
在上面的 XML 中,根节点是 <bookstore>,文档中的所有其他节点都被包含在 <bookstore> 中。根节点有四个 <book> 节点,第一个 <book> 节点有四个节点:<title>, <author>, <year>, <price>,其中每个节点都包含一个文本节点:"Harry Potter", "J K. Rowling", "2005", "29.99"。  
注意:在
DOM处理中一个普遍的错误是,认为元素节点包含文本。实际上元素是一个节点,文本是另外一个节点;只不过,元素节点的文本是存储在文本节点中的。
在这个例子中:<year>2005</year>,元素节点 <year>,拥有一个值为 "2005" 的文本节点。所以 "2005" 不是 <year> 元素节点的值!
节点树
XML DOM 把 XML 文档视为一种树结构,这种树结构被称为节点树 (node-tree)。可通过这棵树访问所有节点,可以修改或删除它们的内容,也可以创建新的元素。
节点树中的节点彼此之间都有等级关系,父、子和同级节点用于描述这种关系。父节点拥有子节点,位于相同层级上的子节点称为同级节点(兄弟或姐妹)。  
- 在节点树中,顶端的节点成为根节点
 - 根节点之外的每个节点都有一个父节点
 - 节点可以有任何数量的子节点
 - 叶子是没有子节点的节点
 - 同级节点是拥有相同父节点的节点
 

因为 XML 数据是按照树的形式进行构造的,所以可以在不了解树的确切结构且不了解其中包含的数据类型的情况下,对其进行遍历。  
节点信息
nodeName 属性
nodeName 属性规定节点的名称:  
nodeName是只读的- 元素节点的 
nodeName与标签名相同 - 属性节点的 
nodeName是属性的名称 - 文本节点的 
nodeName永远是#text - 文档节点的 
nodeName永远是#document 
nodeValue 属性
nodeValue 属性规定节点的值:  
- 元素节点的 
nodeValue是undefined - 文本节点的 
nodeValue是文本自身 - 属性节点的 
nodeValue是属性的值 
常见 nodeName 和 nodeValue 的对应关系:
| 节点类型 | nodeName 的返回值 | 
nodeValue 的返回值 | 
|---|---|---|
| Document | #document | null | 
| Element | element name | null | 
| Attr | 属性名称 | 属性值 | 
| Comment | #comment | 注释文本 | 
| Text | #text | 节点内容 | 
表中可以看出,基本只有属性节点的
nodeValue有意义。
nodeType 属性
nodeType 属性规定节点的类型:
nodeType是只读的
常见节点类型:
| 元素类型 | 节点类型 | 
|---|---|
| 元素 | 1 | 
| 属性 | 2 | 
| 文本 | 3 | 
| 注释 | 8 | 
| 文档 | 9 | 
常见 API
node.getNodeType():获取节点的类型node.getNodeName():获取节点的名称node.getTextContent():获取节点的文本node.getNodeValue():常用于属性节点获取属性值node.getNextSibling():获取同级下一个节点node.getPreviousSibling():获取同级上一个节点node.getParentNode():获取父节点
DOM 对 XML 文件增删改查
源文件
1  | 
  | 
读
1  | String filePath = "***\***.xml";  | 
查找
1  | /**  | 
添加
1  | // 找到 <item app:color="?attr/colorAccent"/>,在它后面添加新元素  | 
注意:写入时需要设置缩进字符,否则新加节点不会缩进。
ts.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");  
修改
1  | // 将名称为 integer, 属性为 name="abc_config_activityDefaultDur"  | 
删除
1  | // 将 <integer name="design_snackbar_text_max_lines"> 第一个匹配的元素删掉  | 
写
1  | String filePath = "***\***.xml";  | 
增删改查后的 XML 文件
1  | 
  | 
遍历 XML 所有节点
1  | // 获取根节点,遍历所有节点  | 
流程简析:
- 获取根节点 
document.getFirstChild();,并打印根节点名称和属性 - 递归遍历所有节点 
traverseNodeTree - 只关心是元素的节点,所以先做节点类型判断 
node.getNodeType() == Node.ELEMENT_NODE - 获取元素节点的名称 
node.getNodeName(),元素节点的文本node.getNodeValue() - 获取元素节点的所有属性 
node.getAttributes() - 属性节点获取名称 
node.getNodeName(),获取属性值node.getNodeValue() 
standalone 和 indent 的问题
在写 xml 文件时遇到了如下问题,源文件:  
1  | 
  | 
出现 standalone 以及第一行不缩进
1  | <resources>  | 
解决缩进,但是还是存在 standalone
缩进解决方案:ts.setOutputProperty(OutputKeys.INDENT, "yes");,生成结果为:  
1  | 
  | 
果然有效!再来去掉 standalone  
去掉 standalone 后缩进失效
去掉 standalone 解决方案,生成 DOMSource 前加入 document.setXmlStandalone(true);,生成结果为:  
1  | 
第一行缩进失效???且看下面的终极方案。
同时去掉 standalone 和解决缩进
终极方案(XML Indent and no standalone):
1  | ts.setOutputProperty(OutputKeys.INDENT, "yes");  | 
生成结果为:
1  |