a我考网

 找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 234|回复: 4

[JAVA] 2011年计算机等考二级JAVA学习精华整理(80)

[复制链接]
发表于 2012-7-31 22:04:26 | 显示全部楼层 |阅读模式
 3.8 Java与XML联合编程之DOM篇  DOM是Document Object Model的缩写,即文档对象模型。前面说过,XML将数据组织为一颗树,所以DOM就是对这颗树的一个对象描叙。通俗的说,就是通过解析XML文档,为XML文档在逻辑上建立一个树模型,树的节点是一个个对象。我们通过存取这些对象就能够存取XML文档的内容。! N" f6 z2 Q5 v. i4 b! h% m  X
  下面我们来看一个简单的例子,看看在DOM中,我们是如何来操作一个XML文档的。+ n$ V& F) t* t
  这是一个XML文档,也是我们要操作的对象:
0 [$ Q# u' T' }+ |9 V4 @- G6 J4 _  Good-bye serialization, hello Java!9 v1 F. `4 P6 w0 ~" g
  下面,我们需要把这个文档的内容解析到一个个的Java对象中去供程序使用,利用JAXP,我们只需几行代码就能做到这一点。首先,我们需要建立一个解析器工厂,以利用这个工厂来获得一个具体的解析器对象:! t7 q5 B- V2 s" B' Z1 i
  DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();& [9 ~; V* d; B( m2 [
  我们在这里使用DocumentBuilderFacotry的目的是为了创建与具体解析器无关的程序,当DocumentBuilderFactory类的静态方法newInstance()被调用时,它根据一个系统变量来决定具体使用哪一个解析器。又因为所有的解析器都服从于JAXP所定义的接口,所以无论具体使用哪一个解析器,代码都是一样的。所以当在不同的解析器之间进行切换时,只需要更改系统变量的值,而不用更改任何代码。这就是工厂所带来的好处。这个工厂模式的具体实现,可以参看下面的类图。; q- N, z( l$ l7 u8 M# A
  DocumentBuilder db = dbf.newDocumentBuilder();' p$ |% u4 d+ T
  当获得一个工厂对象后,使用它的静态方法newDocumentBuilder()方法可以获得一个DocumentBuilder对象,这个对象代表了具体的DOM解析器。但具体是哪一种解析器,微软的或者IBM的,对于程序而言并不重要。
5 h; P. m4 s5 @4 z  然后,我们就可以利用这个解析器来对XML文档进行解析了:
1 L" e. i. _" k* [, y" n  Document doc = db.parse("c:/xml/message.xml");$ i& [1 t) U/ r
  DocumentBuilder的parse()方法接受一个XML文档名作为输入参数,返回一个Document对象,这个Document对象就代表了一个XML文档的树模型。以后所有的对XML文档的操作,都与解析器无关,直接在这个Document对象上进行操作就可以了。而具体对Document操作的方法,就是由DOM所定义的了。, D- A# t8 |6 L4 g3 p# U$ S( y
  Jaxp支持W3C所推荐的DOM 2。如果你对DOM很熟悉,那么下面的内容就很简单了:只需要按照DOM的规范来进行方法调用就可以。当然,如果你对DOM不清楚,也不用着急,后面我们会有详细的介绍。在这儿,你所要知道并牢记的是:DOM是用来描叙XML文档中的数据的模型,引入DOM的全部原因就是为了用这个模型来操作XML文档的中的数据。DOM规范中定义有节点(即对象)、属性和方法,我们通过这些节点的存取来存取XML的数据。
回复

使用道具 举报

 楼主| 发表于 2012-7-31 22:04:27 | 显示全部楼层

2011年计算机等考二级JAVA学习精华整理(80)

 从上面得到的Document对象开始,我们就可以开始我们的DOM之旅了。使用Document对象的getElementsByTagName()方法,我们可以得到一个NodeList对象,一个Node对象代表了一个XML文档中的一个标签元素,而NodeList对象,观其名而知其意,所代表的是一个Node对象的列表:  NodeList nl = doc.getElementsByTagName("message");
/ c( B7 L5 h$ V  我们通过这样一条语句所得到的是XML文档中所有标签对应的Node对象的一个列表。然后,我们可以使用NodeList对象的item()方法来得到列表中的每一个Node对象:7 b" @# T/ M$ L# X8 Z) i
  Node my_node = nl.item(0);
" n" o% N! c  _! p  当一个Node对象被建立之后,保存在XML文档中的数据就被提取出来并封装在这个Node中了。在这个例子中,要提取Message标签内的内容,我们通常会使用Node对象的getNodeValue()方法:) m" u$ y; |0 r5 V: K* [2 a
  String message = my_node.getFirstChild().getNodeValue();2 f" ]+ k+ S$ ^4 G
  请注意,这里还使用了一个getFirstChild()方法来获得message下面的第一个子Node对象。虽然在message标签下面除了文本外并没有其它子标签或者属性,但是我们坚持在这里使用getFirseChild()方法,这主要和W3C对DOM的定义有关。W3C把标签内的文本部分也定义成一个Node,所以先要得到代表文本的那个Node,我们才能够使用getNodeValue()来获取文本的内容。# S; n! ]) u0 A' P# f4 l5 u- X& f; {' J
  现在,既然我们已经能够从XML文件中提取出数据了,我们就可以把这些数据用在合适的地方,来构筑应用程序。
+ \; I, c) b$ i4 M1 e% V  下面的内容,我们将更多的关注DOM,为DOM作一个较为详细的解析,使我们使用起来更为得心应手。
9 k0 ]$ W- u' i6 x9 v- h# w  DOM详解
6 P6 t! s- D: @8 s5 b  1.基本的DOM对象
. y3 v% }0 Q  _# B) R+ M. s3 n2 ~  DOM的基本对象有5个:Document,Node,NodeList,Element和Attr。下面就这些对象的功能和实现的方法作一个大致的介绍。
, U4 g. F+ w) l' l0 N1 V! _  Document对象代表了整个XML的文档,所有其它的Node,都以一定的顺序包含在Document对象之内,排列成一个树形的结构,程序员可以通过遍历这颗树来得到XML文档的所有的内容,这也是对XML文档操作的起点。我们总是先通过解析XML源文件而得到一个Document对象,然后再来执行后续的操作。此外,Document还包含了创建其它节点的方法,比如createAttribut()用来创建一个Attr对象。它所包含的主要的方法有:
+ H" \6 Q$ E- h! a, i! T  createAttribute(String):用给定的属性名创建一个Attr对象,并可在其后使用setAttributeNode方法来放置在某一个Element对象上面。0 a3 U" l8 t, I8 P
  createElement(String):用给定的标签名创建一个Element对象,代表XML文档中的一个标签,然后就可以在这个Element对象上添加属性或进行其它的操作。
% ^+ }( Y( i& g/ |- n9 T  createTextNode(String):用给定的字符串创建一个Text对象,Text对象代表了标签或者属性中所包含的纯文本字符串。如果在一个标签内没有其它的标签,那么标签内的文本所代表的Text对象是这个Element对象的唯一子对象。) Y5 N6 [) \) s" N- l
  getElementsByTagName(String):返回一个NodeList对象,它包含了所有给定标签名字的标签。
9 k* n7 }8 `$ r% m  getDocumentElement():返回一个代表这个DOM树的根节点的Element对象,也就是代表XML文档根元素的那个对象。- p/ s* i- P! v1 y. b( d: R
  Node对象是DOM结构中最为基本的对象,代表了文档树中的一个抽象的节点。在实际使用的时候,很少会真正的用到Node这个对象,而是用到诸如Element、Attr、Text等Node对象的子对象来操作文档。Node对象为这些对象提供了一个抽象的、公共的根。虽然在Node对象中定义了对其子节点进行存取的方法,但是有一些Node子对象,比如Text对象,它并不存在子节点,这一点是要注意的。Node对象所包含的主要的方法有:2 K9 c! w' t9 c- B% d2 C" N
  appendChild(org.w3c.dom.Node):为这个节点添加一个子节点,并放在所有子节点的最后,如果这个子节点已经存在,则先把它删掉再添加进去。
8 [/ _. K6 [! w0 G* R- J0 B  getFirstChild():如果节点存在子节点,则返回第一个子节点,对等的,还有getLastChild()方法返回最后一个子节点。
- d( e2 C. g* u/ Z* S* S  getNextSibling():返回在DOM树中这个节点的下一个兄弟节点,对等的,还有getPreviousSibling()方法返回其前一个兄弟节点。
+ ]' Q2 u0 b1 n; f" s" T  getNodeName():根据节点的类型返回节点的名称。
9 ]# }% B0 ?# C9 @# F1 m8 ]  getNodeType():返回节点的类型。
+ Y) d0 e$ g& M. {  getNodeValue():返回节点的值。: m( k$ ~$ n+ Y5 E# s
  hasChildNodes():判断是不是存在有子节点。
: ~7 y0 V' p4 q8 K! E' g+ h  hasAttributes():判断这个节点是否存在有属性。" ]! g% a, Q$ v, R! t9 c
  getOwnerDocument():返回节点所处的Document对象。
+ C" C  b' [7 }, G% e  insertBefore(org.w3c.dom.Node new,org.w3c.dom.Node ref):在给定的一个子对象前再插入一个子对象。
$ c' z+ v6 B; M( u& t  removeChild(org.w3c.dom.Node):删除给定的子节点对象。
! x! p. O( i+ a$ _8 [0 Z, ]- W  replaceChild(org.w3c.dom.Node new,org.w3c.dom.Node old):用一个新的Node对象代替给定的子节点对象。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2012-7-31 22:04:28 | 显示全部楼层

2011年计算机等考二级JAVA学习精华整理(80)

  NodeList对象,顾名思义,就是代表了一个包含了一个或者多个Node的列表。可以简单的把它看成一个Node的数组,我们可以通过方法来获得列表中的元素:; s! B* I1 E9 f+ ^7 `4 h
  GetLength():返回列表的长度。4 P) q6 F& c& x! r8 e- r
  Item(int):返回指定位置的Node对象。
& j9 T7 o9 u1 f% E  Element对象代表的是XML文档中的标签元素,继承于Node,亦是Node的最主要的子对象。在标签中可以包含有属性,因而Element对象中有存取其属性的方法,而任何Node中定义的方法,也可以用在Element对象上面。
/ B* N4 [, t* i. P  getElementsByTagName(String):返回一个NodeList对象,它包含了在这个标签中其下的子孙节点中具有给定标签名字的标签。/ a, ?4 _% s0 N4 q2 l$ v6 ]
  getTagName():返回一个代表这个标签名字的字符串。
$ T+ y8 E& ]6 U( }  getAttribute(String):返回标签中给定属性名称的属性的值。在这儿需要主要的是,应为XML文档中允许有实体属性出现,而这个方法对这些实体属性并不适用。这时候需要用到getAttributeNodes()方法来得到一个Attr对象来进行进一步的操作。
* T3 j7 F/ _4 h  getAttributeNode(String):返回一个代表给定属性名称的Attr对象。
: {' B$ ~7 B/ b2 s6 h  Attr对象代表了某个标签中的属性。Attr继承于Node,但是因为Attr实际上是包含在Element中的,它并不能被看作是Element的子对象,因而在DOM中Attr并不是DOM树的一部分,所以Node中的getparentNode(),getpreviousSibling()和getnextSibling()返回的都将是null。也就是说,Attr其实是被看作包含它的Element对象的一部分,它并不作为DOM树中单独的一个节点出现。这一点在使用的时候要同其它的Node子对象相区别。% n2 }/ J# X5 Q& A
  需要说明的是,上面所说的DOM对象在DOM中都是用接口定义的,在定义的时候使用的是与具体语言无关的IDL语言来定义的。因而,DOM其实可以在任何面向对象的语言中实现,只要它实现了DOM所定义的接口和功能就可以了。同时,有些方法在DOM中并没有定义,是用IDL的属性来表达的,当被映射到具体的语言时,这些属性被映射为相应的方法。" X5 Q- c6 k! `+ p
  2.DOM实例
0 n- t3 |9 [7 j$ x  有了上面的介绍,相信你对DOM理解的更多了吧。下面的例子将让你对DOM更加熟悉起来。
: {* ~. N* ~* z- b  b* J$ j  先说说这个例子到底要做的是什么吧,我们希望在一个名为link.xml文件中保存了一些URL地址,通过一个简单的程序,我们可以通过DOM把这些URL读出并显示出来,也可以反过来向这个XML文件中写入加入的URL地址。很简单,却很实用,也足够来例示DOM的绝大部分用法了。* m/ C. T( x% h3 s3 g+ o. H
  XML文件本身不复杂,就不给出它的DTD了。link.xml:
: {( \! |' l2 z7 \  JSP Insider$ u3 I; ~8 U9 z4 M( H
  http://www.jspinsider.com& ?7 Z6 e6 j5 W2 A3 E  v
  JSP Insider/ b1 Z0 }1 O, i' g- a
  2
$ p) z' r; k6 K  P  1
) h% m3 P; q0 }: c5 I$ F  2001
) R: D- V) q+ R9 F' l( N  A JSP information site.
3 w! v* h) O/ l# b& A1 N  The makers of Java
+ Q) [3 w9 |. j  http://java.sun.com' @) M3 D2 H5 F, }5 K& p' `
  Sun Microsystems
0 d0 M/ r0 W& Q  3
, `8 r) n, s- h, E& o/ R4 r  1
0 g4 e2 l  Z0 E8 _& }  20018 B# m5 Z; a* R0 {7 m
  Sun Microsystem's website.
9 C) c4 _( d7 N  The standard JSP container1 L' C- j: {' N! K
  http://jakarta.apache.org
: x' ^  {8 s- S) v  Apache Group1 a) d  j/ Q; r2 w
  4" n  K# m6 u9 h
  1
3 B. _' `" T" @) g& r  2001
" f. n- R: \: U9 c# i' T$ K( u  Some great software.
/ `# w9 `( \+ h  N  第一个程序我们称为xmldisplay.java,具体的程序清单可以在附件中找到。主要的功能就是读取这个XML文件中各个节点的内容,然后在格式化输出在System.out上,我们来看看这个程序:
- \: p% a+ [2 |* V$ m7 ?  import javax.xml.parsers.*;
  w, C  q8 l3 c  import org.w3c.dom.*;
回复 支持 反对

使用道具 举报

 楼主| 发表于 2012-7-31 22:04:29 | 显示全部楼层

2011年计算机等考二级JAVA学习精华整理(80)

这是引入必要的类,因为在这里使用的是Sun所提供的XML解析器,因而需要引入java.xml.parsers包,其中包含了有DOM解析器和SAX解析器的具体实现。org.w3c.dom包中定义了w3c所制定的DOM接口。  DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
! I! M- o2 @3 [* |0 w  DocumentBuilder builder=factory.newDocumentBuilder();
$ l7 p+ v# P" D4 z. Q1 I+ B, ~  Document doc=builder.parse("links.xml");
- W, u2 o5 Y) j( }( }  doc.normalize();# C( C* I1 d. X
  除了上面讲到的,还有一个小技巧,对Document对象调用normalize(),可以去掉XML文档中作为格式化内容的空白而映射在DOM树中的不必要的Text Node对象。否则你得到的DOM树可能并不如你所想象的那样。特别是在输出的时候,这个normalize()更为有用。
( ^: @# V# V: e# ~  NodeList links =doc.getElementsByTagName("link");% p" S. h4 {0 @
  刚才说过,XML文档中的空白符也会被作为对象映射在DOM树中。因而,直接调用Node方法的getChildNodes方法有时候会有些问题,有时不能够返回所期望的NodeList对象。解决的办法是使用Element的getElementByTagName(String),返回的NodeLise就是所期待的对象了。然后,可以用item()方法提取想要的元素。% p! A* A9 h3 t8 z

  u) z3 Q5 O- M3 v% W  O' V  for (int i=0;i
回复 支持 反对

使用道具 举报

 楼主| 发表于 2012-7-31 22:04:30 | 显示全部楼层

2011年计算机等考二级JAVA学习精华整理(80)

我们希望在上面的XML文件中加入一个新的link节点,因而首先还是要读入links.xml文件,构建一个DOM树,然后再对这个DOM树进行修改(添加节点),最后把修改后的DOM写回到links.xml文件中:  DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();; M) c0 ?6 \. }* |2 L
  DocumentBuilder builder=factory.newDocumentBuilder();1 q0 e1 t& M; W  \
  Document doc=builder.parse("links.xml");
6 ^. ^, n/ x4 y9 |$ q3 v2 h! b1 h  doc.normalize();" N. Y0 \' {" |# T
  //---取得变量----2 \3 l: W' V0 D0 i
  String text="Hanzhong's Homepage";
+ C% D6 ^* P4 f0 @  String url="www.hzliu.com";3 Z2 K) U# B7 h+ z- l
  String author="Hzliu Liu";7 p6 o. q7 N# O( `
  String discription="A site from Hanzhong Liu, give u lots of suprise!!!";; P" u( @: ?4 S1 P
  为了看清重点,简化程序,我们把要加入的内容硬编码到记忆String对象中,而实际操作中,往往利用一个界面来提取用户输入,或者通过JDBC从数据库中提取想要的内容。9 \+ P  a' s9 ~* @. O4 F
  Text textseg;) j( V2 N( o5 }' u+ c* p  H5 s
  Element link=doc.createElement("link");
0 X1 @: \# m) A+ q; l- r- F4 ~  首先应该明了的是,无论什么类型的Node,Text型的也好,Attr型的也好,Element型的也好,它们的创建都是通过Document对象中的createXXX()方法来创建的(XXX代表具体要创建的类型),因此,我们要向XML文档中添加一个link项目,首先要创建一个link对象:# y5 o. e3 n3 {0 [
  Element linktext=doc.createElement("text");( i+ L& W. b  Z% Q
  textseg=doc.createTextNode(text);6 T: J/ O/ ]7 _/ b. \3 u
  linktext.appendChild(textseg);; `! p6 v; ^6 f+ z) H" @
  link.appendChild(linktext);
. C! d. Q! Q! t, O  Element linkurl=doc.createElement("url");6 y& j: q- @, v% z- @: X% u
  textseg=doc.createTextNode(url);
: D! z' _% W( u. `1 w# i  linkurl.appendChild(textseg);, _6 y1 m' \7 v& `
  link.appendChild(linkurl);. i* \2 t$ H7 U1 C! {/ o1 J& S
  Element linkauthor=doc.createElement("author");( U- J6 P+ l( j; J) p# G
  textseg=doc.createTextNode(author);
2 m& v% w" B; s0 |$ r! H  linkauthor.appendChild(textseg);
7 w! H1 i: q: U: @9 q8 w5 G  link.appendChild(linkauthor);% w! D  q) J5 w3 N1 X- C4 C
  java.util.Calendar rightNow = java.util.Calendar.getInstance();
* N8 I$ M, [. ^8 N% }7 x5 `/ P  String day=Integer.toString(rightNow.get(java.util.Calendar.DAY_OF_MONTH));) i8 |# h% U  o# a. x  f: O% \8 f
  String month=Integer.toString(rightNow.get(java.util.Calendar.MONTH));$ |/ @' j0 ?) v' x+ a$ T# S& f
  String year=Integer.toString(rightNow.get(java.util.Calendar.YEAR));
' A4 i' n# F4 y- b4 l6 j2 _; k' p  Element linkdate=doc.createElement("date");, e; s. \5 G$ U& K2 Y  O! k8 @  ]
  Element linkdateday=doc.createElement("day");
8 A$ ^0 ~) {/ _; [- o9 G7 I  textseg=doc.createTextNode(day);
+ ]( k* t; D6 U3 n4 p) r) ~$ g  linkdateday.appendChild(textseg);
8 N1 n+ g/ l# f( E/ r& B7 A( |  Element linkdatemonth=doc.createElement("month");
! V+ |8 u8 U7 K5 F  textseg=doc.createTextNode(month);. f4 g& x/ o- z  E  J
  linkdatemonth.appendChild(textseg);/ v7 T+ U3 E& d' f8 P' ~
  Element linkdateyear=doc.createElement("year");- F! u9 E' t# k# x$ q) ?% u6 J' M
  textseg=doc.createTextNode(year);
% L2 }: f- \5 s4 Y) s, f* g  linkdateyear.appendChild(textseg);
& }7 q8 \6 @. [. `6 f) l  linkdate.appendChild(linkdateday);" x$ b! e2 ?% g
  linkdate.appendChild(linkdatemonth);
& n3 ]* z1 L* Z/ L% P3 c  linkdate.appendChild(linkdateyear);
' a3 w9 b+ Z" F7 W# H; A6 q  link.appendChild(linkdate);
8 w' T, a$ g8 @8 ^% ^9 W  }  Element linkdiscription=doc.createElement("description");. S* y7 }4 r4 X* O+ f& {
  textseg=doc.createTextNode(discription);
( P4 o; K- I3 K1 l$ B  linkdiscription.appendChild(textseg);
5 q1 B% w7 U! N3 x& R$ V3 k  h  link.appendChild(linkdiscription);
+ p; h2 b+ F3 f# E  创建节点的过程可能有些千篇一律,但需要注意的地方是,对Element中所包含的text(在DOM中,这些text也是代表了一个Node的,因此也必须为它们创建相应的node),不能直接用Element对象的setNodeValue()方法来设置这些text的内容,而需要用创建的Text对象的setNodeValue()方法来设置文本,这样才能够把创建的Element和其文本内容添加到DOM树中。看看前面的代码,你会更好的理解这一点:& S* J8 |# M% ]3 n( S
  doc.getDocumentElement().appendChild(link);
2 {& y- w" S9 A' u6 C& b  最后,不要忘记把创建好的节点添加到DOM树中。Document类的getDocumentElement()方法,返回代表文档根节点的Element对象。在XML文档中,根节点一定是唯一的。
6 l1 N& F/ c* S7 d- V: V  Q2 L: G1 t$ \  TransformerFactory tFactory =TransformerFactory.newInstance();4 ~1 \! D. B0 ]- a
  Transformer transformer = tFactory.newTransformer();
6 _9 O) T7 o/ _2 z, \1 k3 s  DOMSource source = new DOMSource(doc);# B- Z( Z  Q8 n! U9 u! z
  StreamResult result = new StreamResult(new java.io.File("links.xml"));" b1 `' h# c3 {) x1 P8 r0 a1 N8 u
  transformer.transform(source, result);
) ?- p$ j6 Y5 g; n) `  然后就是用XSLT把DOM树输出了。这里的TransformerFactory也同样应用了工厂模式,使得具体的代码同具体的变换器无关。实现的方法和DocumentBuilderFactory相同,这儿就不赘述了。Transformer类的transfrom方法接受两个参数、一个数据源Source和一个输出目标Result。这里分别使用的是DOMSource和StreamResult,这样就能够把DOM的内容输出到一个输出流中,当这个输出流是一个文件的时候,DOM的内容就被写入到文件中去了。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|Woexam.Com ( 湘ICP备18023104号 )

GMT+8, 2024-5-3 11:19 , Processed in 0.249568 second(s), 29 queries .

Powered by Discuz! X3.4 Licensed

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表