71 SAX解析XML流程

新:使用Dom4J的SAX解析XML

我就不详细写了

	SAXReader reader = new SAXReader();
				Document doc = reader.read(new File("conf/emplist.xml"));
				Element root = doc.getRootElement();
				List<Element> list = root.elements("emp");
				for(Element e:list) {
					
					//1.获取e的子节点
					Element nameEle = e.element("name");
					//2.获取子节点的值
					String name = nameEle.getTextTrim();
					//1和2两步可以省略成下面这步:
					String name = e.elementText("name");
					
					
					//获取节点的属性的值
					String key = e.attributeValue("path");
					String value = e.attributeValue("className");
				}

  

以下为原文:较原始的方法

解析流程及原理

  1. //根据xml的标签创建对应的实体类
  2. //创建SAX工厂
  3. //从工厂实例获取SAX解析器
  4. //创建Handler子类并new
  5. //重写此子类:将标签下对应的内容写入实体类中
  6. //解析

SAX解析xml文件只走一次,一次就解析完成,解析顺序是从上到下,逐行解析,解析标签,然后解析标签之间的内容(即使是空白、换行符都要解析出来),然后再解析标签。

SAX可以识别开始标签与结束标签,所以我们可以在startElement()与endElement()方法里很方便的做一些事情。

characters()方法用来读取两个相邻标签之间的内容(并不是读成对标签之间的内容),即使是空白,也读出来。例如:</person> </persons>,我们可以使用trim()将空白字符消除

使用一个变量tag来存储标签名,可以在characters()方法中对应当前的标签名,方便判断标签并读取数据。

案例演示

将下面xml使用SAX解析,将结果存放在实体类中。

<?xml version="1.0" encoding="UTF-8"?>
<persons>
	<person>
		<name>周杰伦</name>
		<fans>3000w</fans>
	</person>
	<person>
		<name>蔡依林</name>
		<fans>2000w</fans>
	</person>
</persons>

  

代码

其中 show方法不是重写方法,是自定义方法。

实体类:

package _20191224_review;
/**
 * person.xml中Person标签的实体
*/
public class Person {
	private String name;
	private String fans;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getFans() {
		return fans;
	}
	public void setFans(String fans) {
		this.fans = fans;
	}
}

  

解析流程:

package _20191224_review;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

/**
 * SAX
 * xml解析
 * 代码:36
 */
public class TestXmlSAX {
	public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {
		//从工厂中获取SAX
		SAXParserFactory factory = SAXParserFactory.newInstance();
		//从SAX中获取解析器
		SAXParser parser = factory.newSAXParser();
		//创建Handler子类,并实例化
		PersonHandler handler = new PersonHandler();
		//重写该类中的必要方法
		//解析
		parser.parse(Thread.currentThread().getContextClassLoader().getResourceAsStream("_20191224_review/person.xml"),handler);
		//尝试获取数据
		handler.show();
	}
}

class PersonHandler extends DefaultHandler{
	private List<Person> persons;
	private String tag;
	private Person person;
	public PersonHandler() {
		persons = new ArrayList<>();
	}
	@Override
	public void startDocument() throws SAXException {
		System.out.println("解析文档开始了");
	}
	@Override
	public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
		tag = qName;
		System.out.println("元素开始-->"+tag);
		if(tag.equals("person")) {
			person = new Person();
		}
	}
	@Override
	public void endElement(String uri, String localName, String qName) throws SAXException {
		tag = qName;
		System.out.println("元素结束-->"+qName);
		if(tag.equals("person")) {
			persons.add(person);
		}
	}
	@Override
	public void characters(char[] ch, int start, int length) throws SAXException {
		String content = new String(ch,start,length);
		if(content.trim().isEmpty()) {
			return;
		}
		System.out.println("tag "+tag+" 内容:"+content);
		if(tag.equals("name")) {
			person.setName(content);
		}
		if(tag.equals("fans")) {
			person.setFans(content);
		}
	}
	public void show() {
		Iterator it = persons.iterator();
		while(it.hasNext()) {
			Person p = (Person)it.next();
			System.out.println("名字:"+p.getName()+" 粉丝数:"+p.getFans());
		}
	}
}

  

 

运行效果

另一个案例:拓展,加入反射

xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app>
	<servlet>
		<servlet-name>login</servlet-name>
		<servlet-class>_20191224_servlet.LoginServlet</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>login</servlet-name>		
		<url-pattern>/login</url-pattern>
		<url-pattern>/g</url-pattern>
	</servlet-mapping>
	<servlet>
		<servlet-name>reg</servlet-name>
		<servlet-class>_20191224_servlet.RegisterServlet</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>reg</servlet-name>
		<url-pattern>/reg</url-pattern>
	</servlet-mapping>
</web-app>

  

我们已经将xml的数据存在了handler里,接下来我们使用反射机制,来动态的创建对象,使得模拟登陆请求和注册请求。在这两个请求之下,创建不同的类。

先写一个接口

package _20191224_servlet;

public interface Servlet {
	void service();
}

  

写两个实现类

登陆类

package _20191224_servlet;

public class LoginServlet implements Servlet{
	
	@Override
	public void service() {
		System.out.println("LoginServlet");
	}
}

  

注册类

package _20191224_servlet;

public class RegisterServlet implements Servlet {

	@Override
	public void service() {
		System.out.println("RegisterServlet");
	}

}

  

上下文类:

将原本储存在List中的数据转换为存储在Map,根据不同的请求获取不同的类名,使用反射动态创建类。

package _20191224_servlet;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 上下文:servlet-mapping下的url-pattern会找到对应的servlet-name
 * 然后找到servlet标签中对应的servlet-name,然后找到对应的servlet-class
 * @author TEDU
 *代码:
 */
public class WebContext {
	private List<Entity> entitys = null;
	private List<Mapping> mappings = null;
	//key-->servlet-name value-->servlet-class
	private Map<String,String> entityMap = new HashMap<String,String>();
	//url-->pattern value-->servlet-name
	private Map<String,String> mappingMap = new HashMap<String,String>();
	
	public WebContext() {
	}
	public WebContext(List<Entity> entitys, List<Mapping> mappings) {
		this.entitys = entitys;
		this.mappings = mappings;
		//将entityList转为对应的Map
		for(Entity entity : entitys) {
			entityMap.put(entity.getName(),entity.getClazz());
		}
		//将MappingList转为对应的Map
		for(Mapping mapping : mappings) {
			for(String pattern : mapping.getPatterns()) {
				mappingMap.put(pattern,mapping.getName());
			}
		}
	}
	
	
	/**
	 * 获取calss
	 * @param pattern
	 * @return
	 */
	public String getClazz(String pattern) {
		String name = mappingMap.get(pattern);//丢pattern进去获取servlet-name
		return entityMap.get(name);//丢servlet-name进去获取servlet-class
	}
}

  

TestXmlSAXPro:解析xml

package _20191224_servlet;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
/**
 *	解析 web.xml 并做反射
 * 	代码:
 */
public class TestXmlSAXPro {
	public static void main(String[] args) throws Exception {
		//SAX工厂
		SAXParserFactory factory = SAXParserFactory.newInstance();
		//从工厂获取SAX解析器
		SAXParser parser = factory.newSAXParser();
		//创建Handler子类并new
		WebHandler handler = new WebHandler();
		//重写此类
		//解析
		parser.parse(Thread.currentThread().getContextClassLoader().getResourceAsStream("_20191224_servlet/web.xml"),handler);
		//尝试获取结果
		WebContext context = new WebContext(handler.getEntitys()
				,handler.getMappings());
//改写的部分开始 //假设你输入了../login String className = context.getClazz("/login"); System.out.println(className); String className1 = context.getClazz("/g"); System.out.println(className1); String className2 = context.getClazz("/reg"); System.out.println(className2); //反射 Class<?> clz = Class.forName(className); Servlet servlet = (Servlet)clz.getConstructor().newInstance(); System.out.println(servlet); servlet.service(); //改写的部分结束 } } class WebHandler extends DefaultHandler{ private List<Mapping> mappings;//servlet-mapping 标签的集合实例 private List<Entity> entitys;//servlet标签的集合实例 private Mapping mapping;///servlet-mapping 标签的实例 private Entity entity;//servlet标签的实例 private String tag; //存储标签名的变量 private boolean isMapping = false;//标记当前标签是否为servlet-Mapping public WebHandler(){ mappings = new ArrayList<>(); entitys = new ArrayList<>(); } public List<Mapping> getMappings() { return mappings; } public List<Entity> getEntitys() { return entitys; } //开始标签 @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { tag = qName; if(tag.equals("servlet")) { entity = new Entity(); } if(tag.equals("servlet-mapping")) { isMapping = true; mapping = new Mapping(); } } //结束标签 @Override public void endElement(String uri, String localName, String qName) throws SAXException { tag = qName; //如果是结束标签,则将实例添加到对应的集合中 if(tag.equals("servlet")) { entitys.add(entity); } if(tag.equals("servlet-mapping")) { mappings.add(mapping); isMapping = false; } } //每个标签(不分开始与结束标签)之间的内容 @Override public void characters(char[] ch, int start, int length) throws SAXException { String content = new String(ch,start,length).trim(); if(content.isEmpty()) return; if(isMapping) { //如果是Mapping标签下的属性 if(tag.equals("servlet-name")) { mapping.setName(content); } if(tag.equals("url-pattern")) { mapping.addPattern(content); } }else { if(tag.equals("servlet-name")) { entity.setName(content); } if(tag.equals("servlet-class")) { entity.setClazz(content); } } } }

  

Mapping类。

package _20191224_servlet;

import java.util.HashSet;
import java.util.Set;

public class Mapping {
	private String name;
	private Set<String> patterns;
	public Mapping() {
		patterns = new HashSet<>();
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Set<String> getPatterns() {
		return patterns;
	}
	public void setPatterns(Set<String> patterns) {
		this.patterns = patterns;
	}
	public void addPattern(String pattern) {
		patterns.add(pattern);
	}
}

  

Entity类:

package _20191224_servlet;

public class Entity {
	private String name;
	private String clazz;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getClazz() {
		return clazz;
	}
	public void setClazz(String clazz) {
		this.clazz = clazz;
	}
	
}

  

运行结果

posted @ 2019-12-24 12:20  Scorpicat  阅读(383)  评论(0编辑  收藏  举报