Java解析XML文件的方式,温故而知新

18 if(books!=null){

19 for(int i=0;i<books.getLength();i++){

20 Node book=books.item(i);

21 //获取id属性

22 if(book.getNodeType()==Node.ELEMENT_NODE){

23 String id=book.getAttributes().getNamedItem(“id”).getNodeValue();

24 System.out.println(“id is:” + id);

25 //遍历book下的子节点

26 for(Node node=book.getFirstChild(); node!=null;node=node.getNextSibling()){

27 if(node.getNodeType()==Node.ELEMENT_NODE){

28 //依次读取book里的name,price和memo三个子元素

29 if(node.getNodeName().equals(“name”)){

30 String name=node.getFirstChild().getNodeValue();

31 System.out.println(“name is:” + name);

32 }

33 if(node.getNodeName().equals(“price”)){

34 String price=node.getFirstChild().getNodeValue();

35 System.out.println(“price is:” + price);

36 }

37 if(node.getNodeName().equals(“memo”)){

38 String memo=node.getFirstChild().getNodeValue();

39 System.out.println(“memo is:” + memo);

40 }

41 }

42 }

43 }

44 }

45 }

第19行的for循环里,我们是遍历book元素通过观察xml文件,我们发现book元素出现了2次,所有这个循环会运行两次,而且,book元素有1个id属性,所有我们需要通过第23行的代码,得到id属性的值。

在文档里,book元素有3个子节点,分别是name,price和memo,所以在代码的26行里,再次使用for循环遍历其中的子节点。在遍历时,我们通过29到32行的代码获取到了book元素里name的值,通过类似的代码后继的33到40行代码里得到了price和memo这两个元素的值。

46 } catch (ParserConfigurationException e) {

47 e.printStackTrace();

48 } catch (FileNotFoundException e) {

49 e.printStackTrace();

50 } catch (IOException e) {

51 e.printStackTrace();

52 } catch (SAXException e) {

53 e.printStackTrace();

54 } catch (Exception e) {

55 e.printStackTrace();

56 }

57 //在finally里关闭io流

58 finally{

59 try {

60 input.close();

61 } catch (IOException e) {

62 e.printStackTrace();

63 }

64 }

65 }

66 }

同样地,在解析完成后,在finally从句里,我们关闭了之前用到的IO流(input对象)。

3 基于事件的解析方式

SAX是Simple API for XML的缩写,不同于DOM的文档驱动,它是事件驱动的,也就是说,它是一种基于回调(callback)函数的解析方式,比如开始解析xml文档时,会调用我们自己定义的startDocument函数,从下表里,我们能看到基于SAX方式里的各种回调函数以及它们被调用的时间点。

函数名

调用时间点

startDocument

开始解析xml文档时(解析xml文档第一个字符时)会被调用

endDocument

当解析完xml文档时(解析到xml文档最后一个字符时)会被调用

startElement

当解析到开始标签时会被调用,比如在解析“<name>FrameWork</name>”这个element时,当读到开始标签“<name>”时,会被调用

endElement

当解析到结束标签时会被调用,比如在解析“<name>FrameWork</name>”这个element时,当读到结束标签“</name>”时,会被调用

characters

1行开始后,遇到开始或结束标签之前存在字符,则会调用

2两个标签之间,存在字符,则会调用,比如在解析“<name>FrameWork</name>”时,发现存在FrameWork,则会被调用

3标签和行结束符之前存在字符,则会调用

从上表里我们能看到characters方法会在多个场合被回调,但我们最期望的调用场景是第2种,这就要求我们最好在解析xml文档前整理下它的格式,尽量避免第1和第3种情况。在ParserXmlBySAX.java这个案例中,我们通过了编写上述的回调函数,实现了SAX方式解析xml文档的功能。

1 //省略import的代码

2 //基于SAX的解析代码需要继承DefaultHandler类

3 public class ParserXmlBySAX extends DefaultHandler{

4 // 记录当前解析到的节点名

5 private String tagName;

6 //主方法

7 public static void main(String[] argv) {

8 String uri = “src/book.xml”;

9 try {

10 SAXParserFactory parserFactory = SAXParserFactory.newInstance();

11 ParserXmlBySAX myParser = new ParserXmlBySAX();

12 SAXParser parser = parserFactory.newSAXParser();

13 parser.parse(uri, myParser);

14 } catch (IOException ex) {

15 ex.printStackTrace();

16 } catch (SAXException ex) {

17 ex.printStackTrace();

18 } catch (ParserConfigurationException ex) {

19 ex.printStackTrace();

20 } catch (FactoryConfigurationError ex) {

21 ex.printStackTrace();

22 }

23 }

在main方法的第8行里,我们指定了待解析xml文档的路径和文件名,在第10行里,我们创建了SAXParserFactory这个类型的SAX解析工厂对象。在第12行,我们通过SAX解析工厂对象,创建了SAXParser这个类型的解析类。在第13行,通过了parse方法启动了解析。

在上文里我们就已经知道,在SAX的方式里,是通过调用各种回调函数来完成解析的,所以在代码里,我们还得自定义各个回调函数,代码如下。

// 处理到文档结尾时,直接输出,不做任何动作

25 public void endDocument() throws SAXException {

26 System.out.println(“endDocument”);

27 }

28 // 处理到结束标签时,把记录当前标签名的tagName设置成null

29 public void endElement(String uri, String localName, String qName) throws SAXException {

30 tagName = null;

31 }

32 // 开始处理文档时,直接输出,不做任何动作

33 public void startDocument() throws SAXException {

34 System.out.println(“startDocument”);

35 }

36 // 处理开始标签

37 public void startElement(String uri, String localName, String name,Attributes attributes) throws SAXException {

38 if (“book”.equals(name)) { //解析book标签的属性

39 for (int i = 0; i < attributes.getLength(); i++) {

40 System.out.println(“attribute name is:” + attributes.getLocalName(i) + " attribute value:" + attributes.getValue(i));

41 }

42 }

小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Java工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Java开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频

如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Java)
img

img-1R2lZIiy-1710827914186)]
[外链图片转存中…(img-VVsNXnDZ-1710827914186)]
[外链图片转存中…(img-VqKwKMEV-1710827914188)]

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频

如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Java)
[外链图片转存中…(img-pnieDMZj-1710827914188)]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值