1、单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,*,XML,基础,1,XML,文档,DTD,样式表,解析树,XML,解析器,呈现代理程序,处理代理程序,显示服务,Xml,的数据传输,2,XML,XML,即可扩展标记语言(,Extensible Markup Language,),是一种平台无关的表示数据的方法。简单地说,使用,XML,创建的数据可以被任何应用程序在任何平台上读取。甚至可以通过手动编码来编辑和创建,XML,文档。其原因是,,XML,与,HTML,一样,都是建立在相同的基于标记技术基础之上。,3,XML(Extensible Markup Lan
2、guage),是一种可扩展的置标语言。,XML,来源于,SGML,(标准通用置标语言),但,XML,是它的简化,但保留了其精华。,W3C,于,1998,年,2,月批准了,XML,的,1.0,版本。成为一个国际标准。,置标指计算机所能理解的信息符号,通过此种标记,计算机之间可以处理包含各种信息的文章等。,4,XMl,的特点,XML,文档是一个自我描述的数据集合,XML,的优点,自我描述性,可移植性,以树结构描述数据,提供可用于数据库的功能,XML,的缺点,数据存取慢,缺少数据库的功能,在生产环境中将失效,5,文档格式定义,DTD,XML,的优点在于它允许您定义自己的有意义的标记,因此您可以最大程
3、度地定制文档。但,XML,就是,XML,(可扩展),而人就是人(疯狂的人),这可能很快就会无法控制。解决方案是,DTD,,它指定了,XML,文档的标记。简而言之,,DTD,指定:可以在文档中存在的元素、那些元素可以具有的属性、在元素内部元素的层次结构以及元素在整个文档中出现的顺序。,目的:确保文档有效,6,DTD,(,Document Type Definition,,文档格式定义)。对于想利用,XML,文件来交换信息的实体来说,他们之间必须有一个约定,即编写,XML,文件可以用哪些标记,母元素中能够包括哪些子元素,各个元素出现的顺序,元素中的属性怎样定义等。这样他们在用,XML,交换数据时才
4、能够畅通无阻,这种约定称为,DTD,。可以把,DTD,看作编写,XML,文件的模板。对于同行业之间的,XML,数据交换,有一个固定的,DTD,将会方便很多。比如说,如果网上的各大电子商场的,XML,网页都遵循同一个,DTD,时,那么我们就可以轻松地依据这个,DTD,编写一个应用程序,去网上将我们感兴趣的东西自动抓回来。,7,格式正确的,XML,文档是满足以下三个基本结构需求的文档:,有一个包含所有其它元素的父(或根)元素,每个开始标记都有结束标记,所有元素都正确嵌套的,8,DTD,的第一行定义了,XML,文档的父元素:,person,。,person,元素有两个子元素:,firstname,和
5、,lastname,。,第二和第三行包含了元素属性,#PCDATA,,它表明,firstname,和,lastname,元素可能包含经过语法分析的字符数据(在这种情况下是文本)。,DTD,文件的最后一行描述了一个空标记:,nothing,。,从清单,3,中的,DTD,可以看出,任何阅读我们的,XML,文档的人(以及对它进行语法分析的语法分析器)都知道,person,元素仅包含两个文本元素:,firstname,和,lastname,。此外,,DTD,规定,在整个文档中,,firstname,元素必须在,lastname,元素之前出现,。,9,Jane Fung,10,DTD,中的内容,虽然,D
6、TD,不是必需的,但它们确实带来方便。,DTD,适合三个基本用途。它能:,对标记编制文档,加强标记参数内部的一致性,使,XML,语法分析器能够确认文档,如果不对,XML,文档进行,DTD,定义,文档就无法由,XML,语法解析器进行确认。,11,XML解析,读取,XML,文档并将文档分解为可进行分析的几个元素的过程,处理,XML,文档,解析器检查,XML,文档的有效性和格式规范,创建解析树并将其传递给呈现代理程序,呈现代理程序将显示此解析树,解析器将创建一系列对象,用于显示与,XML,文档关联的样式表,解析器,12,1.DOM,2.SAX,3.JDOM,4.DOM4J,解析器概述,13,文档对象
7、模型,dom,基于树和节点的文档对象模型(,Document Object Module,)称为,DOM,,,DOM,采用建立树形结构的方式访问。,DOM,解析器把,XML,文档转化为一个包含其内容的树,并可以对树进行遍历。用,DOM,解析模型的优点是编程容易,开发人员只需要调用建树的指令,然后利用,navigation APIs,访问所需的树节点来完成任务。可以很容易的添加和修改树中的元素。然而由于使用,DOM,解析器的时候需要处理整个,XML,文档,所以对性能和内存的要求比较高,尤其是遇到很大的,XML,文件的时候。由于它的遍历能力,,DOM,解析器常用于,XML,文档需要频繁的改变的服务
8、中。,14,1,。,W3C,制定的一套跨平台和语言标准,表示文档的内容和模型,2,。用,Level(,级别)的形式代替版本。,Level1,定义了文档中内容的功能查找方法。,Level2,提供了对,XML,,,HTML,和,CSS,等内容模型的模块选项。,Level3,制定中,为特定类型提供更多的工具如,XML,的验证公交等,3,。基于对象的将,XML,文档表示为树,4,。在内存中解析和存储,XML,文档,5,。允许随机访问文档的不同部分,6,。,DOM,解析器把,XML,文档转化为一个包含其内容的树,并可以对树进行遍历,15,树模型,每个项目都表示一个节点,每个终端项目都表示一个叶节点,直接
9、上级节点表示父节点,任何上级节点都表示祖先节点,从树的一个部分可以到达树的任何其他部分,文档对象模型采用的模式,树模式,16,请看下列,“,department.xml,”,XML,文档:,约瑟夫,joe,玛丽,mary,17,DOM,中,“,department.xml,”,的结构如下:,Department,Student,Name:,约瑟夫,E-mail:joe,Student,E-mail:,mary,Name:,玛丽,18,DOM,解析函数,得到文档模型的根元素,Element root=doc.,getDocumentElement,();,元素,Element,的函数:,Stri
10、ng,getTagName,()-,得到标签的名字,String,getAttribute,(,“,unit,”,)-,得到元素的,unit,属性值,节点,Node,的函数:,NodeList,getChildNodes,()-,得到子节点的集合,Node,getFirstChild,()-,得到第一个子节点,Node,getLastChild,()-,得到最后一个子节点,19,DOM,解析函数,节点,Node,的函数:,Node,getNextSibling,()-,得到下一个兄弟节点,Node,getPreviousSibling,()-,得到前一个兄弟结点,Node,getParentN
11、ode,()-,得到父节点,NamedNodeMap,getAttributes,()-,得到所有的属性集合,String,getNodeName,()-,得到当前节点的名字,String,getNodeValue,()-,得到当前节点的值,NodeList,的函数,int,getLength,()-,得到集合长度,Node item(int index)-,得到集合中的一个元素,20,要将,XML,文档读入,DOM,,请执行下列步骤:,获得一个新,DocumentBuilderFactory,实例,使用,DocumentBuilderFactory,构建,DocumentBuilder,使用
12、,DocumentBuilder,中的,parse(),方法解析给定的文件,将已解析的文档存储在,Document,对象中,使用,getElementsByTagName(),方法从文档获得元素,使用,DOM,解析,XML,文档,21,使用,DOM,解析,XML,文档,DOM,文档是使用,Transformer,类写入输出结果,采用两个参数,即,DOMSource,和,StreamResult,DOMSource,对象以,DOM,树形式来保存源树。,StreamResult,对象保存转换结果,将,XML,数据写入输出结果的步骤如下:,创建文档对象,创建,TransformerFactory,程
13、序的一个实例,使用,TransformerFactory,创建,Transformer,类的一个实例,使用,Transform,方法将源树处理至输出结果中,22,写,XML,文档函数,DocumentBuilder,的函数:,Document doc=builder.,newDocument,();-,新建一个模型,Document,的函数:,Element,createElement,(String name),建立一个元素,Text,createTextNode,(String data)-,创建一个文本节点,Node,的函数:,Node,appendChild,(Node child)-
14、,添加一个子节点,Element,的函数:,void,setAttribute,(String name,String value)-,设置元素的一个属性和属性值,23,DOM,解析演示,MyXMLReader.java,MyXMLWriter.java,24,DOM,最适用的情形,在结构上修改,XML,文档时,在内存中与其他应用程序共享文档时,DOM,的缺点,将整个文档存储在内存中,方法命名惯例不符合,Java,编程惯例,25,SAX,基于事件的,XML,简单,API,(,Simple API for XML,)称为,SAX,,,SAX,采用的事件模型。,SAX,解析器在解析,XML,文档的
15、时候可以触发一系列的事件,当发现给定的,tag,的时候,它可以激活一个回调方法,告诉该方法制定的标签已经找到。,SAX,对内存的要求通常会比较低,因为它让开发人员自己来决定所要处理的,tag,。特别是当开发人员只需要处理文档中所包含的部分数据时,,SAX,这种扩展能力得到了更好的体现。但用,SAX,解析器的时候编码工作会比较困难,而且很难同时访问同一个文档中的多处不同数据。,26,1,。,SAX(Simple API for XML),基于事件驱动,使用回调机制将重要事件通知给客户端应用程序,2,。,SAX,的结构,简单,SAX,应用程序的组件包括:,应用程序,创建一个解析器和一个文档处理程序
16、,告诉解析器使用哪个文档处理程序,告诉解析器处理文档,解析器,将重要事件通知给文档处理程序,文档处理程序,处理通知,27,解析器,文档处理程序,new DocumentHanlder(),new Parser(),new DocumentHanlder(),Parse(),应用程序,startDocument,startElement,characters,endElement,endDocument,简单,SAX,的组件,28,用于,XML,解析的,Java API,可使用,SAX,的普通,API,作为,javax.xml,包实现,易于安装且快速,更具一致性,使用,Factory,设计模式创
17、建要解析的对象,29,SAXParser,类中可用的方法如下:,SAXParser,方法,说明,getParser(),返回,SAX org.xml.sax.Parser,对象。,getProperty(),返回指定属性的值。,setProperty(),设置指定值的属性。,getXMLReader(),返回,SAX org.xml.sax.XMLReader,对象。,isNamespaceAware(),指明是否配置解析器以了解名字空间。,isValidating(),指明是否配置解析器以验证,XML,文档。,30,SAXParserHandler,类,解释如何捕获和响应各个事件,start
18、Document(),和,endDocument(),事件是在文档的起始处和结束处被激发的,startElement(),和,endElement(),事件是在遇到起始标记和结束标记时被激发的,characters(),事件是在遇到字符数据时被激发的,使用,SAX,解析,XML,文档的步骤如下:,创建,SAXParserFactory,的实例,创建,SAXParser,的实例,创建,SAXParserHandler,类,使用,parse(),方法解析,XML,文档,31,SAX,解析演示,SaxXMLReader.java,演示,32,SAX,最适用的情形,在需要解析大型文档时,在只需一个信息
19、子集时,SAX,的缺点,不能对文档进行随机访问,只读,只遍历文档一次,33,JDOM,JDOM,:,Jason Hunter,和,Brett McLaughlin,开发的项目,,JDOM,的设计目标就是在读和创建,XML,时简化,DOM,,取代,DOM,。,微软的,MSXML,解析器:微软已经给我们提供了一个,XML,语法解析器,即一个叫做,MSXML.DLL,的动态链接库(,C,语言),34,jdom,包的结构包括:,org.jdom,包含了所有的,xml,文档要素的,java,类,org.jdom.adapters,包含了与,dom,适配的,java,类,org.jdom.filter,包
20、含了,xml,文档的过滤器类,org.jdom.input,包含了读取,xml,文档的类,org.jdom.output,包含了写入,xml,文档的类,org.jdom.transform,包含了将,jdom xml,文档接口转换为其他,xml,文档接口,org.jdom.xpath,包含了对,xml,文档,xpath,操作的类,35,DOM4J,DOM4J,:一个易用的、开源的库,用于,XML,,,XPath,和,XSLT,。它应用于,Java,平台,采用了,Java,集合框架并完全支持,DOM,,,SAX,和,JAXP,。,36,DOM4J,包的结构包括:,Attribute Attrib
21、ute,定义了,XML,的属性,Branch Branch,为能够包含子节点的节点如,XML,元素,(Element),和文档,(Docuemnts),定义了一个公共的行为,CDATACDATA,定义了,XML CDATA,区域,CharacterData CharacterData,是一个标识借口,标识基于字符的节点。如,CDATA,,,Comment,Text.Comment Comment,定义了,XML,注释的行为,Document,定义了,XML,文档,DocumentType DocumentType,定义,XML DOCTYPE,声明,Element Element,定义,XML
22、,元素,ElementHandler ElementHandler,定义了,Element,对象的处理器,ElementPath,被,ElementHandler,使用,用于取得当前正在处理的路径层次信息,Entity Entity,定义,XML entity,37,DOM4J,包的结构包括:,Node Node,为所有的,dom4j,中,XML,节点定义了多态行为,NodeFilter NodeFilter,定义了在,dom4j,节点中产生的一个滤镜或谓词的行为(,predicate,),ProcessingInstruction ProcessingInstruction,定义,XML,处
23、理指令,.Text,定义,XML,文本节点,.Visitor Visitor,用于实现,Visitor,模式,.XPathXPath,在分析一个字符串后会提供一个,XPath,表达式,38,读取并解析,XML,文档:,读写,XML,文档主要依赖于,org.dom4j.io,包,其中提供,DOMReader,和,SAXReader,两类不同方式,而调用方式是一样的。这就是依靠接口的好处。,/,从文件读取,XML,,输入文件名,返回,XML,文档,public Document read(String fileName)throws MalformedURLException,DocumentEx
24、ception,SAXReader reader=new SAXReader();,Document document=reader.read(new File(fileName);,return document;,取得,Root,节点,public Element getRootElement(Document doc),return doc.getRootElement();,39,遍历,XML,树,DOM4J,提供至少,3,种遍历节点的方法:,1),枚举,(Iterator)/,枚举所有子节点,for(Iterator i=root.elementIterator();i.hasNex
25、t();),Element element=(Element)i.next();,/do something,/,枚举名称为,foo,的节点,for(Iterator i=root.elementIterator(foo);i.hasNext();),Element foo=(Element)i.next();,/do something,/,枚举属性,for(Iterator i=root.attributeIterator();i.hasNext();),Attribute attribute=(Attribute)i.next();,/do something,40,遍历,XML,树,2
26、),递归,递归也可以采用,Iterator,作为枚举手段,但文档中提供了另外的做法,public void treeWalk(),treeWalk(getRootElement();,public void treeWalk(Element element),for(int i=0,size=element.nodeCount();i size;i+),Node node=element.node(i);,if(node instanceof Element),treeWalk(Element)node);,else /do something.,41,遍历,XML,树,3)Visitor,模
27、式,了解设计模式的人都知道,,Visitor,是,GOF,设计模式之一。其主要原理就是两种类互相保有对方的引用,并且一种作为,Visitor,去访问许多,Visitable,。我们来看,DOM4J,中的,Visitor,模式,(,快速文档中没有提供,),只需要自定一个类实现,Visitor,接口即可。,public class MyVisitor extends VisitorSupport,public void visit(Element element),System.out.println(element.getName();,public void visit(Attribute a
28、ttr),System.out.println(attr.getName();,调用:,root.accept(new MyVisitor(),注意,这个,Visitor,是自动遍历所有子节点的。如果是,root.accept(MyVisitor),,将遍历子节点。我第一次用的时候,认为是需要自己遍历,便在递归中调用,Visitor,,结果可想而知。,42,4.,创建,XML,public Document createDocument(),Document document=DocumentHelper.createDocument();,Element root=document.addE
29、lement(root);,Element author1=,root.addElement(author).addAttribute(name,James),.addAttribute(location,UK).addText(James Strachan);,Element author2=root.addElement(author).addAttribute(name,Bob),.addAttribute(location,US).addText(Bob McWhirter);,return document;,43,5.,文件输出,一个简单的输出方法是将一个,Document,或任何
30、的,Node,通过,write,方法输出,FileWriter out=new FileWriter(foo.xml);,document.write(out);,美化输出或缩减格式,可以用,XMLWriter,类,public void write(Document document)throws IOException,XMLWriter writer=new XMLWriter(new FileWriter(output.xml),);writer.write(document);writer.close();,/,美化格式,OutputFormat format=OutputForma
31、t.createPrettyPrint();,writer=new XMLWriter(System.out,format);,writer.write(document);,/,缩减格式,format=OutputFormat.createCompactFormat();,writer=new XMLWriter(System.out,format);,writer.write(document);,44,回顾总结四种解析器,JDOM,和,DOM,在性能测试时表现不佳,在测试,10M,文档时内存溢出。在小文档情况下还值得考虑使用,DOM,和,JDOM,。,SAX,表现较好,这要依赖于它特定的
32、解析方式。一个,SAX,检测即将到来的,XML,流,但并没有载入到内存(当然当,XML,流被读入时,会有部分文档暂时隐藏在内存中)。,DOM4J,是这场测试的获胜者,目前许多开源项目中大量采用,DOM4J,,例如大名鼎鼎的,Hibernate,也用,DOM4J,来读取,XML,配置文件。如果不考虑可移植性,那就采用,DOM4J,吧!,45,总结,解析是读取文档并将文档分解为能够进行分析的几个元素的过程,XML,处理器更常用的名称为解析器,这是因为它只解析,XML,和为应用程序提供其所需的任何信息,XML,解析器使用的两种基本,API,为,DOM,和,SAX,DOM,表示文档对象模型。它定义了一
33、组,java,接口,用于创建、访问和操纵,XML,及,HTML,文档的内部结构,SAX,表示,“,用于,XML,的简单,API,”,。,SAX,提供一种用于解析,XML,文档的事件驱动模型,所有支持,XML,的关系数据库和一些中间件产品都使用对象,-,关系映射,46,课后习题,1,熟练掌握一种格式的,xml,的读写,推荐(,org,.dom4j.*,)掌握,dom sax,*2,创建,xml,文件,里面存放,student,对象的信息,包括:,name,,,age,。,student,的属性(,attribute,)包括班级(,class,id),要求:,有方法,addStudent,(,Document doc,,,Student student,)可以向此文档加入,student,对象,getStudent,(,Document doc,,,int id,)可以根据,id,读取某个,Student,。,47,