本文讲解三点: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
}
}