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"); }
以下为原文:较原始的方法
解析流程及原理
- //根据xml的标签创建对应的实体类
- //创建SAX工厂
- //从工厂实例获取SAX解析器
- //创建Handler子类并new
- //重写此子类:将标签下对应的内容写入实体类中
- //解析
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; } }
运行结果