之前我写过一篇关于xml解析的文章:http://blog.csdn.net/sdksdk0/article/details/50749326。今天这篇文章主要是进一步加深对xml基础的理解了使用,毕竟基础是很重要的嘛!写的应该会更注重细节的内容。主要内容有xml语法、DOM解析、SAX解析、Xpath,schema约束。

一、xml语法

标签

  1. 有开始标签和结束标签
  2. xml标签名称区分大小写
  3. xml标签一定要正确配对
  4. 中间不能使用空格
  5. 不能以数字开头,可以以下划线或字母开头
  6. 在一个xml文档中,有且仅有一个根标签

属性

  1. 属性值一定要以引号包含,也不能单双引号混用 name="erim"
  2. 一个标签内可以多个属性,但是属性名不能重复,例如不能有两个 id="1" id="2"

注释

<!--xml的注释  -->

文档申明

如果在ide中开发,保存xml文件时会自动按照文档申明的encoding来保存。

 <?xml version="1.0" encoding="utf-8"?>

转义字符

<   &lt;
> &gt;
" &quot;
& &amp;
空格 &nbsp; 写法:&lt;p&gt;段落&lt;/p&gt;

CDATA块

作用,可以让一些需要包含特殊字符的内容,统一进行原样输出。

<![CDATA[
<html><head>head</head><body>body</body></html>
]]>

处理指令

作用:告诉xml解析器如何解析xml内容

<?xml-stylesheet type="text/css"  href="1.css" ?>

完整例子:

<?xml version="1.0" encoding="utf-8"?>
<codes>
<code>
<p>段落</p>
<p>段落</p>
</code>
<code>
<![CDATA[
<html><head>head</head><body>body</body></html>
]]>
</code>
</codes>

二、xml解析的方式

有DOM解析和SAX解析方式。

Dom解析常用工具有:

  1. JAXP (oracle官方)
  2. JDOM
  3. DOM4J(常用)
SAX解析常用工具有:Sax解析工具(oracle官方)
xml解析和sax解析的对比:(面试常考)


三、DOM解析

原理

xml解析器一次性把整个xml文档加载进内存,然后再内存中构建一棵Document的对象树,通过Document对象,得到树的节点对象,通过节点对象访问到xml文档的内容。不适合读取大容量的文件,容易导致内存溢出。

DOM4J工具

需要导包。

1、创建一个xml解析器对象

        SAXReader reader=new SAXReader();

2、读取xml文档,返回Document对象

        Document doc=reader.read(new File("./src/contact.xml"));

示例代码:

	public static void main(String[] args) {

		try {
//1、创建一个xml解析器对象
SAXReader reader=new SAXReader();
//2、读取xml文档,返回Document对象
Document doc=reader.read(new File("./src/contact.xml"));
System.out.println(doc); } catch (DocumentException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}

Dom4j读取xml文件

节点:

Iterator  Element.nodeIterator();  //获取当前标签节点下的所有子节点

示例代码:

                   //用nodeIterator(),得到当前节点下的所有子节点对象
Iterator<Node> it=doc.nodeIterator();
while(it.hasNext()){
Node node=it.next();
String name=node.getName();
System.out.println(name); //继续取出其下面的子节点
//只有标签节点才有子节点
if(node instanceof Element){
Element elem=(Element) node;
Iterator<Node> it2=elem.nodeIterator();
while(it2.hasNext()){
Node n2=it2.next();
System.out.println(n2.getName());
}
}
}

标签:

 Element  Document.getRootElement();  //获取xml文档的根标签
Element Element.element("标签名");//指定名称的第一个子标签
Iterator<Element> iterator = list.iterator();

示例代码:

public void test3() throws DocumentException {
SAXReader reader=new SAXReader();
Document doc=reader.read(new File("./src/contact.xml")); Element rootElem=doc.getRootElement();
String name=rootElem.getName(); System.out.println(name);
//得到当前标签下指定名称的第一个子标签
//Element contactElem=rootElem.element("contact");
//System.out.println(contactElem.getName()); //得到当前标签下指定名称的所有子标签
Iterator<Element> it=rootElem.elementIterator("contact");
while(it.hasNext()){
Element elem=it.next();
System.out.println(elem.getName());
}
List<Element> list=rootElem.elements();
//遍历List的方法:普通for,增强for,迭代器
for(int i=0;i<list.size();i++){
Element e=list.get(i);
System.out.println(e.getName());
}
Iterator<Element> iterator = list.iterator();
while(it.hasNext()){
Element elem=it.next();
System.out.println(elem.getName());
} //想要获取更深层次的标签,只能一层层的读取
Element nameElem=doc.getRootElement().element("contact").element("name");
System.out.println(nameElem.getName()); }

属性:

		String   Element.attributeValue("属性名") //获取指定名称的属性值
Attribute: Element.attribute("属性名");//获取指定名称的属性对象
Attribute.getName() //获取属性名称
Attibute.getValue() //获取属性值
List<Attribute> Element.attributes(); //获取所有属性对象
Iterator<Attribute> Element.attibuteIterator(); //获取所有属性对象

示例代码:

//获取属性,先获取属性所在的标签对象,然后才能获取属性
Element contactElem=doc.getRootElement().element("contact");
String idValue=contactElem.attributeValue("id");
System.out.println(idValue); //得到属性对象
Attribute idAttr=contactElem.attribute("id");
System.out.println(idAttr.getName()+"="+idAttr.getValue()); //得到所有属性的对象,使用List
List<Attribute> list=contactElem.attributes();
for (Attribute attribute : list) {
System.out.println(attribute.getName()+"="+attribute.getValue());
}
//使用迭代器
Iterator<Attribute> it=contactElem.attributeIterator();
while(it.hasNext()){
Attribute attr=it.next();
System.out.println(attr.getName()+"="+attr.getValue());
}

文本:

Element.getText();  //获取当前标签的文本
Element.elementText("标签名") //获取当前标签的指定名称的子标签的文本内容

示例代码:

	public void test5() throws DocumentException{
SAXReader reader=new SAXReader();
Document doc=reader.read(new File("./src/contact.xml")); //空格和换行也是有内容的 //获取文本,要先获取标签,再获取标签上的文本
Element nameElem=doc.getRootElement().element("contact").element("name"); String text=nameElem.getText();
System.out.println(text); String text2=doc.getRootElement().element("contact").elementText("name");
System.out.println(text2); }

Dom4j修改xml文档

写出内容到xml文档

new XMLWriter(OutputStream,OutputFormat)

writer(Document)

	<pre name="code" class="java">                     Document doc=new SAXReader().read(new File(".src/contact.xml"));

		              //指定文件输出位置
FileOutputStream out=new FileOutputStream("D:/contact.xml");
//创建写出对象
//紧凑的
OutputFormat format=OutputFormat.createCompactFormat();
OutputFormat format1=OutputFormat.createPrettyPrint(); //影响了xml文档保存时的编码和xml文档申明的编码,使用该方法生成的xml避免了乱码问题
format.setEncoding("utf-8"); XMLWriter writer=new XMLWriter(out,format); writer.write(doc);
writer.close();

修改xml文档的API

增加:

DocumentHelper.createDocument()
addElement("contact"); addAttribute("id", "001");
//增加一个标签
Element rootElem=doc.addElement("contactList");
Element contactElem=rootElem.addElement("contact");
contactElem.addElement("name"); //增加属性
contactElem.addAttribute("id", "001");
contactElem.addAttribute("name", "aa");

修改: setValue(),setText()

Element contactElem=doc.getRootElement().element("contact");

		//得到属性对象
Attribute idAttr=contactElem.attribute("id");
//修改属性值
idAttr.setValue("003"); Element contactElem1=doc.getRootElement().element("contact");
contactElem1.addAttribute("id", "004"); //修改文本
Element nameElem=doc.getRootElement().element("contact").element("name");
nameElem.setText("锤子");

删除: deatch()

//删除标签对象
/*Element ageElem=doc.getRootElement().
element("contact").element("age");
ageElem.detach();*/
//ageElem.getParent().remove(ageElem); //删除属性
Element contactElem=(Element) doc.getRootElement().elements().get(0); Attribute idAttr=contactElem.attribute("id");
idAttr.detach();

四、XPATH

当使用dom4j查询比较深的层次的时候非常麻烦。可以快速查找信息。 主要用于快速获取节点对象。

XPath使用一个紧凑的、非XML语法方便使用在uri和XML属性值的XPath。XPath操作基于XML文档的逻辑结构,而不是其表面的语法。Xpath的名字来自其使用的符号在URL路径通过一个XML文档的层次结构导航。 除了用于定位,XPath还设计有一个真子集,可用于匹配(测试一个节点是否符合一个模式);使用XPath进行XSLT。

XPath模型的XML文档的节点树。有不同类型的节点,包括元素节点、属性节点和文本节点。XPath定义了一个方法来计算每个节点类型字符串值。某些类型的节点也有名字。XPath完全支持XML命名空间的XML名称] [。因此,一个节点的名称被建模为一个地方的部分和一个可能的空命名空间URI;这就是所谓的扩展名。在[ 5数据模型]中详细描述了数据模型。

  1. 导包:jaxen-1.1-beta.jar
  2. 使用xpath的方法:

    List selectNodes();//查询多个节点对象 Node selectSingleNode("xpath表达式");//查询一个节点对象

xpath的语法

  1. / ,绝对路径 ,表示从xml的跟位置开始或者子元素(一个层次结构)
  2. // ,相对路径,表示不分任何层次结构的选择元素
  3. *,通配符,表示匹配所有元素
  4. [],条件,表示选择什么条件下的元素
  5. @,属性,表示选择属性节点
  6. and ,关系,表示条件的与关系(等价于&)
  7. text(),文本,表示选择文本内容

示例代码:
public static void main(String[] args) throws DocumentException {
Document doc = new SAXReader().read(new File("./src/contact.xml")); String xpath = "";
xpath="/contactList";
xpath="/contactList/contact";
xpath="//contact/name";
xpath="//name"; //通配符
xpath="/contactList/*";
xpath="/contactList//*"; //条件
xpath="//contact[@id]";
//第二个contact标签
xpath="//contact[2]";
xpath="//contact[last()]"; //属性
xpath="//@id"; //选取的是id属性节点对象,返回Attribute对象
xpath="//contact[not(@id)]";
//选取id属性为002d contact标签
xpath="//contact[@id='002']";
xpath="//contact[@id='001' and @name='aa']"; //选取文本内容
xpath="//name/text()"; //返回Text对象
xpath="//contact/name[text()='张三']"; List<Node> list = doc.selectNodes(xpath);
for (Node node : list) {
System.out.println(node);
} }

五、SAX解析


原理

读取加载处理都是一部分一部分的进行的,对内存要求比较低。

AX解析允许在读取文档的时候,即对文档进行处理,而不必等到整个文档装载完才会文档进行操作。

SAX采用事件处理的方式解析XML文件,利用 SAX 解析 XML 文档,涉及两个部分:解析器和事件处理器: 解析器可以使用JAXP的API创建,创建出SAX解析器后,就可以指定解析器去解析某个XML文档。 解析器采用SAX方式在解析某个XML文档时,它只要解析到XML文档的一个组成部分,都会去调用事件处理器的一个方法,解析器在调用事件处理器的方法时,会把当前解析到的xml文件内容作为方法的参数传递给事件处理器。 事件处理器由程序员编写,程序员通过事件处理器中方法的参数,就可以很轻松地得到sax解析器解析到的数据,从而可以决定如何对数据进行处理

核心API

  1. SAXParser:用于读取和解析xml文件
  2. parse()方法,用于解析xml文件。parse(File f,DefaultHandler dh)方法,解析xml文件。

  3. 参数1:File:表示读取xml文件

  4. 参数2:DefaultHandloer:SAX事件处理程序
                    void startDocument()  :  在读到文档开始时调用
void endDocument() :在读到文档结束时调用
void startElement(String uri, String localName, String qName, Attributes attributes) :读到开始标签时调用
void endElement(String uri, String localName, String qName) :读到结束标签时调用
void characters(char[] ch, int start, int length) : 读到文本内容时调用

示例代码:


</pre><pre name="code" class="java">public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {
SAXParser parser=SAXParserFactory.newInstance().newSAXParser(); MyDefalutHandler3 handler=new MyDefalutHandler3();
parser.parse(new File("./src/contact.xml"), handler); List<Contact> list=handler.getList();
for (Contact contact : list) {
System.out.println(contact);
} }
public class MyDefalutHandler3 extends DefaultHandler {

	private List<Contact> list = new ArrayList<Contact>();

	public List<Contact> getList() {
return list;
} private Contact contact;
private String curTag;
// 开始标签
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
curTag=qName;
// 读取到contact的开始标签创建Contact对象
if ("contact".equals(qName)) {
contact = new Contact(); // 设置id值
contact.setId(attributes.getValue("id")); }
} // 文本内容
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
//当前文本内容
String content=new String(ch,start,length); if("name".equals(curTag)){
contact.setName(content);
}
if("age".equals(curTag)){
contact.setAge(content);
}
if("phone".equals(curTag)){
contact.setPhone(content);
}
if("email".equals(curTag)){
contact.setEmail(content);
}
if("qq".equals(curTag)){
contact.setQq(content);
}
} // 结束标签
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
// 读到contact的结束标签则放入list中
curTag=null;
if ("contact".equals(qName)) {
list.add(contact);
}
} }

六、schema约束

XML Schema 也是一种用于定义和描述 XML 文档结构与内容的模式语言,其出现是为了克服 DTD 的局限性

XML Schema 文件自身就是一个XML文件,但它的扩展名通常为.xsd。支持名称空间。 一个XML Schema文档通常称之为模式文档(约束文档),遵循这个文档书写的xml文件称之为实例文档。

和XML文件一样,一个XML Schema文档也必须有一个根结点,但这个根结点的名称为schema。

编写了一个XML Schema约束文档后,通常需要把这个文件中声明的元素绑定到一个URI地址上,在XML Schema技术中有一个专业术语来描述这个过程,即把XML Schema文档声明的元素绑定到一个名称空间上,以后XML文件就可以通过这个URI(即名称空间)来告诉解析引擎,xml文档中编写的元素来自哪里,被谁约束。

学习目标:不需要我们编写xsd 重点:根据xsd编写出xml文档。 难点:在xml中引入xsd约束

基本操作步骤:

a、根据xsd文件,找到根元素

<?xml version="1.0" encoding="UTF-8"?>
<书架> </书架>

b、根元素来在哪个名称空间 使用xmlns关键字来声明名称空间。

<?xml version="1.0" encoding="UTF-8"?>
<tf:书架 xmlns:tf="http://www.tianfang1314.cn"> </tf:书架>

c、名称空间和哪个xsd文件对应

<?xml version="1.0" encoding="UTF-8"?>
<tf:书架 xmlns:tf="http://www.tianfang1314.cn"
schemaLocation="http://www.tianfang1314.cn book.xsd"> </tf:书架>

d、schemaLocation来自一个标准的名称空间:固定写法

<?xml version="1.0" encoding="UTF-8"?>
<tf:书架 xmlns:tf="http://www.tianfang1314.cn"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.tianfang1314.cn book.xsd"> </tf:书架>


总结:
XML现在已经成为一种通用的数据交换格式,它的平台无关性,语言无关性,系统无关性,给数据集成与交互带来了极大的方便。xml是一种重要的知识点,需要多练习才能进一步的掌握。其实这些东西说难不难,说易烨不易,主要是很多细节上面的东西,希望可以多查看帮助文档来进一步了解,常用的几种格式要掌握,如果想要进进一步加强理解可以查看:http://blog.csdn.net/sdksdk0/article/details/50749326

源码地址:

大话XML解析的更多相关文章

  1. xml解析技术

    本文总结Dom,sax解析,  使用Java作为工具解析xml文档. 1 Dom 综述:Dom解析xml通常也称为xmlDom (和htmlDom技术差不多),将xml文档封装成树,好处就是xml中的 ...

  2. Duilib源码分析(三)XML解析器—CMarkup

    上一节介绍了控件构造器CDialogBuilder,接下来将分析其XML解析器CMarkup: CMarkup:xml解析器,目前内置支持三种编码格式:UTF8.UNICODE.ASNI,默认为UTF ...

  3. JSON解析和XML解析对比

    JSON解析和XML解析是较为普遍的两种解析方式,其中JSON解析的市场分额更大.本文系统的分析两种解析方式的区别,为更好地处理数据作准备.由于目前阶段主要是做移动开发,所以本文所描述的JSON解析和 ...

  4. 【Android】实现XML解析的几种技术

    本文介绍在Android平台中实现对XML的三种解析方式. XML在各种开发中都广泛应用,Android也不例外.作为承载数据的一个重要角色,如何读写XML成为Android开发中一项重要的技能. 在 ...

  5. 定位和xml解析和gson解析加上拉加载,下拉刷新

    这里的上拉加载,下拉刷新用到是依赖包 Mainactivity,xml解析和定位 package com.exmple.autolayout; import java.util.List; impor ...

  6. tinyxml一个优秀的C++ XML解析器

    读取和设置xml配置文件是最常用的操作,试用了几个C++的XML解析器,个人感觉TinyXML是使用起来最舒服的,因为它的API接口和Java的十分类似,面向对象性很好. TinyXML是一个开源的解 ...

  7. PERL/LEX/YACC技术实现文本解析--XML解析

    继周六的p_enum.pl后,再来一篇说说我用perl做的lex,yacc工具.之前说了,我学习lex和yacc的最初动机是为了做个C语言解释器的SHELL:但后来工作中的实际需要也是制作perl版l ...

  8. 基本XML解析---编写

    #import "ViewController.h" #import "DDXML.h" @interface ViewController () @end @ ...

  9. iOS-数据解析XML解析的多种平台介绍

    在iPhone开发中,XML的解析有很多选择,iOS SDK提供了NSXMLParser和libxml2两个类库,另外还有很多第三方类库可选,例如TBXML.TouchXML.KissXML.Tiny ...

随机推荐

  1. Python面向对象——重写与Super

    1本文的意义 如果给已经存在的类添加新的行为,采用继承方案 如果改变已经存在类的行为,采用重写方案 2图解继承.重写与Super 注:上面代码层层关联.super()可以用到任何方法里进行调用,本文只 ...

  2. 关于python 使用腾讯云OCR 通用印刷体识别

    腾讯的python SDK没有通用印刷体识别,所以参考了别人识别网上图片的方式:https://www.cnblogs.com/semishigure/p/7690789.html 但是咱们使用的基本 ...

  3. java基本数据类型的包装类

    基本类型对应的包装类 byte(Byte).short(Short).int(Integer).long(Long).float(Float).double(Double).char(Characte ...

  4. [LeetCode] The Maze 迷宫

    There is a ball in a maze with empty spaces and walls. The ball can go through empty spaces by rolli ...

  5. 解决IOS移动端 Safari流浪器 onclick无法触发的问题

    在移动端布局的时候, 在底部有一个button, 页面超过两屏, 是一个可滚动的的网页, 当运行在移动端Safari浏览器上的时候, 向下滑动页面, 浏览器的头部和尾部会自动隐藏, 这样可视区域就会变 ...

  6. 属性添加get和set方法

    出错信息: Struts Problem Report Struts has detected an unhandled exception: Messages: File: com/myHibern ...

  7. [HNOI 2016]序列

    Description 题库链接 给你一个长度为 \(n\) 的序列 \(A\) ,给出 \(q\) 组询问.每次询问 \([l,r]\) ,求该区间内所有的子序列中最小值的和. \(1\leq n, ...

  8. 洛谷P3233 [HNOI2014]世界树

    虚树= = #include<cstdio> #include<cstdlib> #include<algorithm> #include<cstring&g ...

  9. UVA - 11992:Fast Matrix Operations

    线段树,注意tag优先级 #include<cstdio> #include<cstdlib> #include<algorithm> #include<cs ...

  10. 【Codeforces Round 418】An impassioned circulation of affection DP

                                                            C. An impassioned circulation of affection   ...