JAVADREAM

hackiller
数据加载中……
J2EE复习(二)XML(下)--xml解析

xml的四种解析方法及源代码(SAX、DOM、JDOM、DOM4J)

第一种:SAX解析
SAX处理机制:SAX是一种基于事件驱动的API。利用SAX解析XML文档,牵涉到两个部分:解析器和事件处理器。解析器负责读取XML文档,并向事件处理器发生事件,如元素开始和元素结束事件;而事件处理器则负责对事件做出响应,对传递的XML数据进行处理。

测试用的xml文件db.xml

 1<?xml version="1.0" encoding="UTF-8"?>
 2<!--<!DOCTYPE dbconfig SYSTEM "db.dtd">-->
 3<dbconfig>
 4 <db type="oracle">
 5  <driver>oracle.jdbc.driver.OracleDriver</driver>
 6  <url>jdbc:oracle:thin:@localhost:1521:oracle</url>
 7  <user>scott</user>
 8  <password>tiger</password>
 9 </db>
10</dbconfig>
DTD文件db.dtd
1<!ELEMENT dbconfig (db+)>
2<!ELEMENT db (driver,url,user,password)>
3<!ELEMENT driver (#PCDATA)>
4<!ELEMENT url (#PCDATA)>
5<!ELEMENT user (#PCDATA)>
6<!ELEMENT password (#PCDATA)>
7<!ATTLIST db type CDATA #REQUIRED>

SAX解析实例一
org.xml.sax.DefalutHandler类:  可以扩展该类,给出自己的解析实现
SAXPrinter.java

 1import java.io.File;
 2

 3import
 javax.xml.parsers.SAXParser;
 4import
 javax.xml.parsers.SAXParserFactory;
 5

 6import
 org.xml.sax.Attributes;
 7import
 org.xml.sax.SAXException;
 8import
 org.xml.sax.helpers.DefaultHandler;
 9

10public class SAXPrinter extends
 DefaultHandler
11
{
12

13  
/**
14   * 文档开始事件
15   */

16    public void startDocument() throws SAXException
17    
{
18        System.out.println("<?xml version=\"1.0\" encoding=\"utf-8\"?>"
);
19    }

20    
21  
/**
22   * 接收处理指令事件
23   */

24    public void processingInstruction(String target, String data) throws SAXException
25    
{
26        System.out.println("<?"+target+" "+data+"?>"
);
27    }

28    
29  
/**
30   * 元素开始事件
31
   * 参数说明:
32
   *   uri - 名称空间 URI,如果元素没有任何名称空间 URI,或者没有正在执行名称空间处理,则为空字符串。
33
   *   localName - 本地名称(不带前缀),如果没有正在执行名称空间处理,则为空字符串。
34
   *   qName - 限定的名称(带有前缀),如果限定的名称不可用,则为空字符串。
35
   *   attributes - 附加到元素的属性。如果没有属性,则它将是空的 Attributes 对象。
36   */

37    public void startElement(String uri, String localName, String qName, Attributes attrs) throws SAXException
38    
{
39        System.out.print("<"+qName);//输出元素名称

40        int len=attrs.getLength();//元素属性列表长度
41
        
42    //利用循环输出属性列表

43        for(int i=0;i<len;i++)
44        
{
45            System.out.print(" "
);
46
            System.out.print(attrs.getQName(i));
47            System.out.print("=\"");

48            System.out.print(attrs.getValue(i));
49            System.out.print("\"");

50        }

51        System.out.print(">");
52    }

53    
54  
/**
55   * 元素中字符数据事件:接收元素中字符数据
56
   * 注意:1.应用程序不要试图读取ch数组指定范围外的数据,(即start至length之外)
57
   *      2.有些解析器将使用ignorableWhitespace()方法来报告元素内容中的空白,而不是characters()方法,如:进行有效性验证的解析器
58   */

59    public void characters(char[] ch, int start, int length) throws SAXException
60    
{
61        System.out.print(new
 String(ch,start,length));
62    }

63
64  
/**
65   * 结束元素事件
66   */

67    public void endElement(String uri, String localName, String qName) throws SAXException
68    
{
69        System.out.print("</"+qName+">"
);
70    }

71
72    public static void
 main(String[] args)
73    
{
74        SAXParserFactory spf=
SAXParserFactory.newInstance();
75
        
76        try

77        {
78            SAXParser sp=
spf.newSAXParser();
79            sp.parse(new File("db.xml"),new
 SAXPrinter());
80        }

81        catch (Exception e)
82        
{
83
            e.printStackTrace();
84        }

85    }

86}

SAX解析实例二
org.xml.sax.ContentHandler接口: 通过实现该接口给出自己的解析实现。
org.xml.sax.ErrorHandler接口:如果SAX应用程序需要实现定制的错误处理,那么它必须实现这个接口,并调用XMLReader对象的setErrorHandler()方法向解析器注册异常处理实例,这样,解析器将通过这个接口报告所有的错误和警告。
ContentHandlerImpl.java

 1import org.xml.sax.Attributes;
 2import
 org.xml.sax.ContentHandler;
 3import
 org.xml.sax.Locator;
 4import
 org.xml.sax.SAXException;
 5

 6public class ContentHandlerImpl implements
 ContentHandler
 7
{
 8  
/**
 9   * 文档开始事件
10   */

11  public void startDocument() throws SAXException
12  
{
13    System.out.println("<?xml version=\"1.0\" encoding=\"utf-8\"?>"
);
14  }

15  
16  
/**
17   * 接收处理指令事件
18   */

19  public void processingInstruction(String target, String data) throws SAXException
20  
{
21    System.out.println("<?"+target+" "+data+"?>"
);
22  }

23  
24  
/**
25   * 元素开始事件
26
   * 参数说明:
27
   *   uri - 名称空间 URI,如果元素没有任何名称空间 URI,或者没有正在执行名称空间处理,则为空字符串。
28
   *   localName - 本地名称(不带前缀),如果没有正在执行名称空间处理,则为空字符串。
29
   *   qName - 限定的名称(带有前缀),如果限定的名称不可用,则为空字符串。
30
   *   attributes - 附加到元素的属性。如果没有属性,则它将是空的 Attributes 对象。
31   */

32  public void startElement(String uri, String localName, String qName, Attributes attrs) throws SAXException
33  
{
34    System.out.print("<"+qName);//输出元素名称

35    int len=attrs.getLength();//元素属性列表长度
36
    
37    //利用循环输出属性列表

38    for(int i=0;i<len;i++)
39    
{
40      System.out.print(" "
);
41
      System.out.print(attrs.getQName(i));
42      System.out.print("=\"");

43      System.out.print(attrs.getValue(i));
44      System.out.print("\"");

45    }

46    System.out.print(">");
47  }

48  
49  
/**
50   * 元素中字符数据事件:接收元素中字符数据
51
   * 注意:1.应用程序不要试图读取ch数组指定范围外的数据,(即start至length之外)
52
   *      2.有些解析器将使用ignorableWhitespace()方法来报告元素内容中的空白,而不是characters()方法,如:进行有效性验证的解析器
53   */

54  public void characters(char[] ch, int start, int length) throws SAXException
55  
{
56    System.out.print(new
 String(ch,start,length));
57  }

58
59  
/**
60   * 结束元素事件
61   */

62  public void endElement(String uri, String localName, String qName) throws SAXException
63  
{
64    System.out.print("</"+qName+">"
);
65  }

66
67  public void endDocument() throws
 SAXException
68  
{
69
    
70  }

71
72  public void endPrefixMapping(String prefix) throws
 SAXException
73  
{
74
    
75  }

76
77  public void ignorableWhitespace(char[] ch, int start, int length) throws
 SAXException
78  
{
79
    
80  }

81
82  public void
 setDocumentLocator(Locator locator)
83  
{
84
    
85  }

86
87  public void skippedEntity(String name) throws
 SAXException
88  
{
89
    
90  }

91
92  public void startPrefixMapping(String prefix, String uri) throws
 SAXException
93  
{
94
    
95  }

96
97}
 ErrorHandlerImpl.java
 1public class ErrorHandlerImpl implements ErrorHandler
 2
{
 3

 4  public void warning(SAXParseException e) throws
 SAXException
 5  
{
 6    System.out.println("[Warning ]"+getLocationString(e)+":"+
e.getMessage());
 7  }

 8
 9  public void error(SAXParseException e) throws
 SAXException
10  
{
11    System.out.println("[Error ]"+getLocationString(e)+":"+
e.getMessage());
12  }

13
14  public void fatalError(SAXParseException e) throws
 SAXException
15  
{
16    System.out.println("[Fatal Error ]"+getLocationString(e)+":"+
e.getMessage());
17  }

18
19  private
 String getLocationString(SAXParseException e)
20  
{
21    StringBuffer sb=new
 StringBuffer();
22    String publicId=
e.getPublicId();
23    if(publicId!=null
)
24    
{
25
      sb.append(publicId);
26      sb.append(" "
);
27    }

28    
29    String systemId=
e.getSystemId();
30    if(systemId!=null
)
31    
{
32
      sb.append(systemId);
33      sb.append(" "
);
34    }

35    
36
    sb.append(e.getLineNumber());
37    sb.append(":"
);
38
    sb.append(e.getColumnNumber());
39    return
 sb.toString();
40  }

41}
SaxParserTest.java
 1import java.io.FileInputStream;
 2

 3import
 org.xml.sax.InputSource;
 4import
 org.xml.sax.XMLReader;
 5import
 org.xml.sax.helpers.XMLReaderFactory;
 6

 7public class
 SaxParserTest
 8
{
 9  public static void
 main(String[] args)
10  
{
11    try

12    {
13      XMLReader xmlReader=
XMLReaderFactory.createXMLReader();
14      //关闭或打开验证

15      xmlReader.setFeature("http://xml.org/sax/features/validation",true);
16      //注册事件处理器

17      xmlReader.setContentHandler(new ContentHandlerImpl());
18      //注册异常处理器

19      xmlReader.setErrorHandler(new ErrorHandlerImpl());
20
      
21      xmlReader.parse(new InputSource(new FileInputStream("saxdb.xml"
)));
22    }
 catch (Exception e)
23    
{
24
      System.out.println(e.getMessage());
25    }

26  }

27}

第二种:DOM解析
DOM中的核心概念就是节点。DOM在分析XML文档时,将将组成XML文档的各个部分(元素、属性、文本、注释、处理指令等)映射为一个对象(节点)。在内存中,这些节点形成一课文档树。整棵树是一个节点,树中的每一个节点也是一棵树(子树),可以说,DOM就是对这棵树的一个对象描述,我们通过访问树中的节点来存取XML文档的内容。
PS:属性节点是附属于元素的,不能被看做是元素的子节点,更不能作为一个单独的节点
DOMPrinter.java

 1import org.w3c.dom.Document;
 2import
 org.w3c.dom.NamedNodeMap;
 3import
 org.w3c.dom.Node;
 4

 5import
 com.sun.org.apache.xerces.internal.parsers.DOMParser;
 6

 7public class
 DOMPrinter
 8
{
 9  public static void
 main(String[] args)
10  
{
11    try

12    {
13      /** 获取Document对象 */

14      DOMParser parser = new DOMParser();
15      parser.parse("db.xml"
);
16      Document document =
 parser.getDocument();
17
      printNode(document);
18    }
 catch (Exception e)
19    
{
20
      e.printStackTrace();
21    }

22  }

23  
24  public static void
 printNode(Node node)
25  
{
26    short nodeType=
node.getNodeType();
27    switch
(nodeType)
28    
{
29    case Node.PROCESSING_INSTRUCTION_NODE://预处理指令类型

30      printNodeInfo(node);
31      break
;
32    case Node.ELEMENT_NODE://元素节点类型

33      printNodeInfo(node);
34
      printAttribute(node);
35      break
;
36    case Node.TEXT_NODE://文本节点类型

37      printNodeInfo(node);
38      break
;
39    default
:
40      break
;
41    }

42    
43    Node child=
node.getFirstChild();
44    while(child!=null
)
45    
{
46
      printNode(child);
47      child=
child.getNextSibling();
48    }

49  }

50  
51  
/**
52   * 根据节点类型打印节点
53   * @param
 node
54   */

55  public static void printNodeInfo(Node node)
56  
{
57    if (node.getNodeType() ==
 Node.ELEMENT_NODE)
58    
{
59      System.out.println("NodeName: " +
 node.getNodeName());
60    }

61    else if (node.getNodeType() == Node.TEXT_NODE)
62    
{
63      String value =
 node.getNodeValue().trim();
64      if (!value.equals(""
))
65        System.out.println("NodeValue: " +
 value);
66      else

67        System.out.println();
68    }
else
69    {
70      System.out.println(node.getNodeName()+" : "+
node.getNodeValue());
71    }

72  }

73  
74  
/**
75   * 打印节点属性
76   * @param
 aNode 节点
77   */

78  public static void printAttribute(Node aNode)
79  
{
80    NamedNodeMap attrs =
 aNode.getAttributes();
81    if(attrs!=null
)
82    
{
83      for (int i = 0; i < attrs.getLength(); i++
)
84      
{
85        Node attNode =
 attrs.item(i);
86        System.out.println("Attribute: " + attNode.getNodeName() + "=\"" + attNode.getNodeValue()+"\""
);
87      }

88    }

89  }
DOM生成XML文档:DOMCreateExample.java
 1import java.io.FileNotFoundException;
 2import
 java.io.FileOutputStream;
 3import
 java.io.IOException;
 4

 5import
 javax.xml.parsers.DocumentBuilder;
 6import
 javax.xml.parsers.DocumentBuilderFactory;
 7import
 javax.xml.parsers.ParserConfigurationException;
 8

 9import
 org.w3c.dom.Document;
10import
 org.w3c.dom.Element;
11

12import
 com.sun.org.apache.xml.internal.serialize.XMLSerializer;
13

14public class
 DOMCreateExample
15
{
16  public static void main(String[] args) throws
 ParserConfigurationException
17  
{
18    //DOMImplementation domImp = DOMImplementationImpl.getDOMImplementation();

19    DocumentBuilderFactory builderFact = DocumentBuilderFactory.newInstance();
20    DocumentBuilder builder =
 builderFact.newDocumentBuilder();
21
   
22    Document doc =
 builder.newDocument();
23    //Document doc = domImp.createDocument(null, null, null);

24   
25    Element root = doc.createElement("games"
);
26    Element child1 = doc.createElement("game"
);
27    child1.appendChild(doc.createTextNode("Final Fantasy VII"
));
28    child1.setAttribute("genre""rpg"
);
29
    root.appendChild(child1);
30
    doc.appendChild(root);
31
     
32
     XMLSerializer serial;
33    try

34    {
35      serial = new XMLSerializer(new FileOutputStream("domcreate.xml"), null
);
36
      serial.serialize(doc);
37    }
 catch (FileNotFoundException e1)
38    
{
39
      e1.printStackTrace();
40    }
 catch (IOException e)
41    
{
42
      e.printStackTrace();
43    }

44  }

45}
第三种JDOM解析
JDOM利用了java语言的优秀特性,极大地简化了对XML文档的处理,相比DOM简单易用。JDOM也使用对象树来表示XML文档,JDOM使用SAXj解析器来分析XML文档,构建JDOM树。然而JOMD本身并没有提供解析器,它使用其他开发商提供的标准SAX解析器,JDOM默认通过JAXP来选择解析器,可以通过手动知道解析器的类名来设置。
首先要在工程中添加jdom的jar包,这里使用jdom1.0.jar。(见附件)
JDOMConvert.java
 1import java.io.File;
 2

 3import
 org.jdom.Document;
 4import
 org.jdom.Element;
 5import
 org.jdom.input.SAXBuilder;
 6import
 org.jdom.output.Format;
 7import
 org.jdom.output.XMLOutputter;
 8

 9public class
 JDOMConvert
10
{
11    public static void
 main(String[] args)
12    
{
13        SAXBuilder saxBuilder=new
 SAXBuilder();
14        try

15        {
16            Document doc=saxBuilder.build(new File("domdb.xml"
));
17
      
18      //首先创建好节点

19      Element eltDb=new Element("db");
20      Element eltDriver=new Element("driver"
);
21      Element eltUrl=new Element("url"
);
22      Element eltUser=new Element("user"
);
23      Element eltPassword=new Element("password"
);
24
      
25      //设置节点的值

26      eltDriver.setText("com.mysql.jdbc.Driver");
27      eltUrl.setText("jdbc:mysql://localhost/mySql"
);
28      eltUser.setText("root"
);
29      eltPassword.setText("xlc"
);
30
      
31      //添加到根节点

32      eltDb.addContent(eltDriver);
33
      eltDb.addContent(eltUrl);
34
      eltDb.addContent(eltUser);
35
      eltDb.addContent(eltPassword);
36      //根节点设置属性

37      eltDb.setAttribute("type","mysql");
38
      
39      Element root=
doc.getRootElement();
40      //root.removeChild("db");//删除节点

41      root.addContent(eltDb);//增加节点
42
      
43      //修改db节点中内容

44      root.getChild("db").getChild("user").setText("system");
45      root.getChild("db").getChild("password").setText("manager"
);
46
      
47            XMLOutputter xmlOut=new
 XMLOutputter();
48
            
49      //设置XML格式

50            Format fmt=Format.getPrettyFormat();
51            fmt.setIndent("    "
);
52            fmt.setEncoding("utf-8"
);
53
            
54
            xmlOut.setFormat(fmt);
55
            xmlOut.output(doc,System.out);
56        }

57        catch (Exception e)
58        
{
59
            e.printStackTrace();
60        }

61    }

62}
JDOM生成XML文档:JDOMCreate.java
 1import java.io.IOException;
 2

 3import
 org.jdom.Document;
 4import
 org.jdom.Element;
 5import
 org.jdom.output.XMLOutputter;
 6

 7public class
 JDOMCreate
 8
{
 9  public static void
 main(String[] args)
10  
{
11    Document doc = new Document(new Element("games"
));
12    Element newGame = new Element("game").setText("Final Fantasy VI"
);
13
    doc.getRootElement().addContent(newGame);
14    newGame.setAttribute("genre""rpg"
);
15    XMLOutputter domstream = new
 XMLOutputter();
16    try

17    {
18
      domstream.output(doc, System.out);
19    }
 catch (IOException e)
20    
{
21
      e.printStackTrace();
22    }

23  }

24}

第四种:DOM4J解析
dom4j与JDOM一样,也是一种用于解析XML文档的开放源代码的XML框架,dom4j也应用于java平台,dom4j API使用了java集合框架并完全支持DOM、SAX和JAXP。与JDOM不同的是,dom4j使用接口和抽象类,虽然dom4j的API相对复杂些,但它提供了比JDOM更好的灵活性。dom4j也使用SAX解析器来分析XML文档,创建dom4j树。此外dom4j也可以接收DOM格式的内容,并提供了从dom4j树到SAX事件流或W3C DOM树的输出机制。与JDOM不同,dom4j自带了一个SAX解析器Aelfred2,如果没有显示的设置SAX解析器,也没有通过系统属性org.xml.sax.driver设置解析器,dom3j将会使用JAXP来加载JAXP配置的解析器,如果创建解析器失败,那么最后才使用dom4j自带的Aelfred2解析器。
同样,首先要在工程中添加dom4j的jar包,这里使用dom4j-1.6.1.jar。(见附件)
Dom4j生成XML文档db.xml:Dom4jCreate.java

 1import java.io.IOException;
 2

 3import
 org.dom4j.Document;
 4import
 org.dom4j.DocumentHelper;
 5import
 org.dom4j.Element;
 6import
 org.dom4j.io.OutputFormat;
 7import
 org.dom4j.io.XMLWriter;
 8

 9public class
 Dom4jCreate
10
{
11

12  public static void
 main(String[] args)
13  
{
14    Document doc =
 DocumentHelper.createDocument();
15

16    doc.addProcessingInstruction("xml-stylesheet""type='text/xsl' href='db.xsl'"
);
17    doc.addDocType("dbconfig"null,"db.dtd"
);
18
    
19    //
Element root=DocumentHelper.createElement("dbconfig");
20    // doc.setRootElement(root);

21    Element root = doc.addElement("dbconfig");
22

23    Element eltDb= root.addElement("db"
);
24    Element eltDriver = eltDb.addElement("driver"
);
25    Element eltUrl = eltDb.addElement("url"
);
26    Element eltUser = eltDb.addElement("user"
);
27    Element eltPassword = eltDb.addElement("password"
);
28
    
29    eltDriver.setText("com.mysql.jdbc.Driver"
);
30    eltUrl.setText("jdbc:mysql://localhost/mySql"
);
31    eltUser.setText("root"
);
32    eltPassword.setText("xlc"
);
33    eltDb.addAttribute("type","mysql"
);
34
        
35    try

36    {
37      //设置输出格式

38      OutputFormat outFmt = new OutputFormat("    "true);
39      outFmt.setEncoding("UTF-8"
);
40
      
41      
/*PrintWriter pw = new PrintWriter(System.out);
42
      doc.write(pw);
43
      pw.flush();
44      pw.close();*/

45
46      XMLWriter xmlWriter = new
 XMLWriter(System.out, outFmt);
47      // XMLWriter xmlWriter=new XMLWriter(new FileWriter("db.xml"),outFmt);

48      xmlWriter.write(doc);
49
      xmlWriter.flush();
50
      xmlWriter.close();
51    }
 catch (IOException e)
52    
{
53
      e.printStackTrace();
54    }

55  }

56}
Dom4j修改XML文档db.xml:Dom4jModify.java
Dom4jModify.java

 相关资料链接
J2EE复习(一)HTML
J2EE复习(二)XML(上)
J2EE复习(二)XML(下)--XML解析
J2EE复习(三)JavaScript

posted on 2009-04-09 09:53 hackiller 阅读(1468) 评论(4)  编辑  收藏 所属分类: J2EE第一次复习

评论

# re: J2EE复习(二)XML(下)--xml解析 2009-04-09 17:22 NJPaul

学习J2EE一上来老师就告诉我们如何用xml配置各种框架和资源,至于xml是如何被解析的看了你的文章才略微懂了一点。想问的一个问题是当应用要读取配置文件里的某个节点的某个属性的时候,它必须要把那个xml文件重头到尾解析一遍吗?比如说先匹配到那个节点,再匹配它的属性。如果是这样的话,频繁解析的代价会不会大了一点,不能解析一遍然后放到内存里随机读取吗?
  回复  更多评论    

# re: J2EE复习(二)XML(下)--xml解析 2009-04-09 19:48 xlc

@NJPaul
1.不一定要把整个XML文件从头到尾解析。
比如你用jodom解析,在JDOMConvert.java中可以通过root.getChild("db").getAttribute("type")得到db节点的type属性

2.解析XML文件后,可以将解析内容放入到一个Hashtable缓存里面,然后读取
比如SAX解析,你可以在处理元素开始事件的startElement()方法中添加
elementNae(全局变量) = qName; ,还可以在此方法中处理元素属性的代码, 然后在处理元素中字符数据事件的characters()方法中添加hashtable(全局变量).put(elementName,new String(ch, start, length))。
其他的都可以这样。
  回复  更多评论    

# re: J2EE复习(二)XML(下)--xml解析 2009-04-10 13:45 NJPaul

哦。那各种框架和容器的配置文件解析是框架给我们做好的吗,什么情况下我们需要自己去解析呢?
  回复  更多评论    

# re: J2EE复习(二)XML(下)--xml解析 2009-04-10 16:34 hackiller

@NJPaul
是的,比如说hibernate框架就是用dom4j来解析读取配置文件的。
在用ssh框架时,我还没碰到过要自己解析xml配置文件。学习mvc模式时会需要自己写配置文件的解析。
  回复  更多评论    

只有注册用户登录后才能发表评论。


网站导航: