本文讲解三点:1. sax中DefaultHandler解析XML总体过程 2. sax中DefaultHandler解析XML非根node的先后顺序 3. sax中DefaultHandler解析XML根node先后顺序 (三点 均通过实际程序测试出来,程序见下文)
一:sax中DefaultHandler解析XML总体过程
startDocument--->具体读到某个node(非根node和根node)的解析过程 --->endDocument 。
二:DefaultHandler 解析XML 的非根node是按顺序的四步(不管当前node是ElementNode[可有属性]还是TextNode)(非根node本测试程序如 person,name,age):
第一步:startElement. (eg:startElement localName : qName : age)
第二步 : characters (eg:characters in age = 25)
第三步 : endElement (eg: endElement in )
第四步 : characters (eg: characters in null = !)
三:DefaultHandler 解析XML 的根node是按顺序的三步(本测试程序中根node为 persons):
第一步:startElement. (eg:startElement localName : qName : persons)
第二步 : characters (eg:characters in persons = !)
第三步 : endElement (eg:endElement in )
---------------------------------------------------------------------------------------------------------------------------------------
使用org.sax.helper.DefaultHandler 解析XML ,一般会调用以下六个方法,需要你重写。
1. 开始解析xml文档 startDocument
2. 读到某个节点 startElement-->characters-->endElement-->characters (endElement后会再调用一次characters方法)
3. 解析xml文档结束 endDocument
---------------------------------------------------------------------------------------------------------------------------------------
org.sax.helper.DefaultHandler 解析XML 的算法思路(自己理解的)
对每一个非根节点node都要进行两项检查:1.检查是不是ElementNode(用startElement方法) ; 2.是不是TextNode(用characters方法),遇到当前节点结尾时,调用endElement和characters方法。最关键的一句话:DefaultHandler会自动解析到下个节点,通过调用startElement方法。并把最新解析到的节点名称放在startElement(Strng url , Sting localName , String qName , Attributes attributes) 的qName中。
---------------------------------------------------------------------------------------------------------------------------------------
测试程序:
客户端eclipse读取服务器端myeclpse的myhttp工程根目录下的persons.xml文件
persons.xml
<?xml version = "1.0" encoding = "UTF-8"> <persons> <person id="23"> <name>黄老师</name> <age>26</age> </person> <person id="25"> <name>杨老师</name> <age>28</age> </person> </persons>
客户端程序运行结果:
--startDocument-- startElement localName: qName:persons characters in persons= ! startElement localName: qName:person characters in person= ! startElement localName: qName:name characters in name=黄老师! endElement in characters in null= ! startElement localName: qName:age characters in age=26! endElement in characters in null= ! endElement in characters in null= ! startElement localName: qName:person characters in person= ! startElement localName: qName:name characters in name=杨老师! endElement in characters in null= ! startElement localName: qName:age characters in age=28! endElement in characters in null= ! endElement in characters in null= ! endElement in --endDocument-- {name=黄老师, id=23, age=26} {name=杨老师, id=25, age=28}
1.分析对每一个非根节点都会按顺序触发4个方法,如<age>和<person>;
对于<age>这个节点很直观可以看到,对于<person>其实也是如此,以person为黄老师为例: 刚开始解析到person节点(即 解析到<person>时),触发startElement和characters;当遍历完 name 和 age节点 到达</person> 时,触发了 endElement 和 characters方法
2.而对于根节点<persons>只触发前三个方法,而不触发最后一个characters方法。
因为xml文档必须包含一个根节点,且只能包含一个根节点,即本xml的根节点为<persons>具有唯一性,所以当解析遇到</persons>时会知道整个xml文档已经解析完毕,所以不会触发characters方法。而是在endElement后直接触发endDocument方法。
客户端eclipse程序目录(左边), 服务器端myeclipse程序目录(右边)
MyHandler2.java
package com.sax.handler; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; public class MyHandler2 extends DefaultHandler { private List<HashMap<String, String>> list = null; private HashMap<String, String> map = null; private String currentTag = null; private String nodeName = null; public MyHandler2(String nodeName) { // TODO Auto-generated constructor stub this.nodeName = nodeName; } public List<HashMap<String, String>> getList() { return list; } @Override public void startDocument() throws SAXException { System.out.println("--startDocument--"); list = new ArrayList<HashMap<String, String>>(); } @Override public void startElement(String url, String localName, String qName, Attributes attributes) throws SAXException { System.out.println("startElement localName: " + localName + "qName:" + qName); currentTag = qName; if (nodeName.equals(qName)) { // nodeName 是 person ,由构造函数传入。 map = new HashMap<String, String>(); map.put("id", attributes.getValue("id")); } } @Override public void characters(char[] arg0, int arg1, int arg2) throws SAXException { System.out.println("characters in " + currentTag + "=" + new String(arg0, arg1, arg2) + "!"); if ("name".equals(currentTag)) { map.put("name", new String(arg0, arg1, arg2)); } if ("age".equals(currentTag)) { map.put("age", new String(arg0, arg1, arg2)); } } @Override public void endElement(String url, String localName, String qName) throws SAXException { System.out.println("endElement in " + localName); if ("person".equals(qName)) { list.add(map); } currentTag = null; } @Override public void endDocument() throws SAXException { System.out.println("--endDocument--"); } }
SaxService.java
package com.sax.service; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import java.util.List; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.xml.sax.SAXException; import com.sax.handler.MyHandler; import com.sax.handler.MyHandler2; public class SaxService { public SaxService() { // TODO Auto-generated constructor stub } public static List<HashMap<String, String>> readXML( InputStream inputStream, String nodeName) { try { // 创建一个解析XML的工厂对象 SAXParserFactory spf = SAXParserFactory.newInstance(); SAXParser parser = spf.newSAXParser(); // MyHandler handler = new MyHandler(nodeName); MyHandler2 handler = new MyHandler2(nodeName); parser.parse(inputStream, handler); inputStream.close(); // return handler.getList(); return handler.getList(); } catch (ParserConfigurationException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SAXException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; } }
HttpUtils.java
package com.sax.http; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; public class HttpUtils { public HttpUtils() { // TODO Auto-generated constructor stub } public static InputStream getXML(String path) { InputStream inputStream = null; try { URL url = new URL(path); if (url != null) { HttpURLConnection httpURLConnection = (HttpURLConnection) url .openConnection(); httpURLConnection.setConnectTimeout(3000); httpURLConnection.setDoInput(true); // 从服务器获取数据 httpURLConnection.setRequestMethod("GET"); int responseCode = httpURLConnection.getResponseCode(); if (responseCode == 200) { inputStream = httpURLConnection.getInputStream(); } } } catch (MalformedURLException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return inputStream; } }
Test.java
package com.sax.test; import java.io.InputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import com.sax.handler.MyHandler; import com.sax.http.HttpUtils; import com.sax.service.SaxService; public class Test { public Test() { // TODO Auto-generated constructor stub } /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub List<HashMap<String, String>> list = new ArrayList<HashMap<String,String>>(); InputStream inputStream = HttpUtils.getXML("http://192.168.0.102:8080/myhttp/persons.xml"); list = SaxService.readXML(inputStream, "person"); for (HashMap<String, String> hashMap : list) { System.out.println(hashMap.toString()); } } }
服务器端 LoginAction.java
package com.login.manager; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class LoginAction extends HttpServlet { /** * Constructor of the object. */ public LoginAction() { super(); } /** * Destruction of the servlet. <br> */ public void destroy() { super.destroy(); // Just puts "destroy" string in log // Put your code here } /** * The doGet method of the servlet. <br> * * This method is called when a form has its tag value method equals to get. * * @param request * the request send by the client to the server * @param response * the response send by the server to the client * @throws ServletException * if an error occurred * @throws IOException * if an error occurred */ public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } /** * The doPost method of the servlet. <br> * * This method is called when a form has its tag value method equals to * post. * * @param request * the request send by the client to the server * @param response * the response send by the server to the client * @throws ServletException * if an error occurred * @throws IOException * if an error occurred */ public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=utf-8"); request.setCharacterEncoding("utf-8"); response.setCharacterEncoding("utf-8"); //客户端 HttpUtils并没有写request方法是post ,但服务器端可自动识别 String method = request.getMethod(); System.out.println("request method :"+method); PrintWriter out = response.getWriter(); String username = request.getParameter("username"); System.out.println("-username->>"+username); String password = request.getParameter("password"); System.out.println("-password->>"+password); if (username.equals("admin") && password.equals("123")) { // 表示服务器段返回的结果 out.print("login is success !"); } else { out.print("login is fail !"); } out.flush(); out.close(); } /** * Initialization of the servlet. <br> * * @throws ServletException * if an error occurs */ public void init() throws ServletException { // Put your code here } }