XML可扩展的标记语言。往往用来作配置文件或者网络数据传输。
XML 指可扩展标记语言(EXtensible Markup Language)XML 是一种标记语言,很类似 HTMLXML 的设计宗旨是传输数据,而非显示数据XML 标签没有被预定义。您需要自行定义标签。XML 被设计为具有自我描述性。XML 是 W3C 的推荐标准一个文档只能有一个根节点。
标签要成对出现。
标签区分大小写。
目前网络数据传输基本都是使用json,不在使用XML了。 所以现在XML的主要作用就配置。
案例:
<?xml version="1.0" encoding="UTF-8"?> <stus> <student skill="哭"> <name>刘备</name> <age>38</age> <tel>13813813838</tel> </student> <student skill="义薄云天"> <name>关羽</name> <age>28</age> <tel>12812812828</tel> </student> <student skill="俺也一样"> <name>张飞</name> <age>26</age> <tel>12612612626</tel> </student> </stus>上面的XML描述了三个学生的信息。
tips: xml的第一行是XML的头信息,这一行必须从第一行第一列开始写。
今天的任务就是使用各种方式将上面的XML解析出来放到一个学生列表中。
创建一个实体类:
public class Student { private String name; private int age; private String tel; private String skill; }jdk提供了DocumentBuilderFactory 可以获取DocumentBuilder ,通过DocumentBuilder可以获取一个Document对象。而Document对象就表示一个文档对象。
[1]通过DocumentBuilder的parse获取一个Document对象。 这里的Documeng是org.w3c.dom下的。
[2]获取根节点:Element root = doc.getDocumentElement();
[3]根节点是一个Element元素。Element接口有方法getAtrtributeXxxxx可以获取元素的属性。 getChildNodes获取它所有的子元素。
[4]getChildNodes返回NodeList,我们可以通过它提供的API遍历它。
遍历过程中取出的元素是Node。 这个Node其实就是Element或者空白节点
[5]根据名称判断对应的标签,使用getAttribute()取出属性值。
[6]继续按照上面的方式取子节点
@Test public void testJDKDom() throws Exception { List<Student> sts = new ArrayList<>(); //获取DocumentBuilderFactory对象 DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); //获取DocumentBuilder DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); //创建Document对象 InputStream in = new FileInputStream("resource/stus.xml"); Document doc = documentBuilder.parse(in); //获取根节点 Element root = doc.getDocumentElement(); System.out.println(root.getTagName()); //获取root的子元素 NodeList studentNodes = root.getChildNodes(); //遍历子元素 for(int i = 0;i<studentNodes.getLength();i++) { //定义学生的属性和对象 Student st = new Student(); Node studentNode = studentNodes.item(i); //判断节点的类型 if(studentNode.getNodeType()==Node.ELEMENT_NODE) {//如果是元素节点就处理 System.out.println("--"+studentNode.getNodeName()); //将Node强制转换为Element Element studentElement = (Element)studentNode; //获取属性 if(studentElement.getNodeName().equals("student")) { String skill = studentElement.getAttribute("skill"); st.setSkill(skill); //获取属性元素 NodeList attrNodes = studentElement.getChildNodes(); for(int j = 0;j<attrNodes.getLength();j++) { Node attrNode = attrNodes.item(j); if(attrNode.getNodeType()==Node.ELEMENT_NODE) { switch(attrNode.getNodeName()) { case "name": String name = attrNode.getTextContent().trim(); st.setName(name); break; case "age": String age = attrNode.getTextContent().trim(); st.setAge(new Integer(age)); break; case "tel": String tel = attrNode.getTextContent().trim(); st.setTel(tel); break; } } } System.out.println(st); //将创建好的学生对象加入集合中 sts.add(st); } } } System.out.println(sts); }DOM4J几乎时所有框架解析XML的使用的方式。
DOM4J可以解析XML文件以及XML字符串。
DOM4J解析的思路和我们上面的第一个方式是一样。
下载DOM4j 的jar文件,添加到我们的classpath中。
@Test public void testDom4j() throws Exception { List<Student> sts = new ArrayList<>(); //创建一个SAXReader SAXReader reader = new SAXReader(); //读取文件,创建一个Document对象 此document非彼document org.dom4j.Document doc = reader.read(new File("resource/stus.xml")); //获取根节点 此Element非彼Element org.dom4j.Element root = doc.getRootElement(); System.out.println("根节点:"+root.getName()); //获取子元素 Iterator<org.dom4j.Element> studentElements = root.elementIterator(); while(studentElements.hasNext()) { org.dom4j.Element studentElement = studentElements.next(); Student st = new Student(); //取出属性 String skill = studentElement.attributeValue("skill"); st.setSkill(skill); //取Student的子元素 Iterator<org.dom4j.Element> attrElements = studentElement.elementIterator(); while(attrElements.hasNext()) { org.dom4j.Element attrElement = attrElements.next(); String name = attrElement.getName(); String text = attrElement.getText().trim(); switch(name) { case "name": st.setName(text); break; case "age": st.setAge(new Integer(text)); break; case "tel": st.setTel(text); break; } } System.out.println(st); //将学生加入集合 sts.add(st); } System.out.println(sts); }观察spring的配置文件
<?xml version="1.0" encoding="UTF-8"?> <beans> <bean id="stuDAO" class="com.igeek.dao.impl.StudentDAOImpl"/> <bean id="stuService" class="com.igeek.service.impl.StudentServiceImpl"> <property name="stuDAO" ref="stuDAO"/> </bean> </beans>spring会自动通过反射创建stuDAO对象,
创建stuService对象。并且会调用studentService中的setStuDAO方法将上面创建的stuDAO设置到studentService中。
工厂实现:
package com.igeek.factory; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Hashtable; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import org.dom4j.Attribute; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.Element; import org.dom4j.io.SAXReader; import com.sun.xml.internal.messaging.saaj.packaging.mime.util.BEncoderStream; /** * @author www.igeekhome.com * * TODO * * 2019年11月2日 下午2:33:45 */ public class BeanFactory { private static BeanFactory instance; private BeanFactory() { init(); } public synchronized static BeanFactory getInstance() { if(instance==null) instance = new BeanFactory(); return instance; } private Map<String,Object> beans = new Hashtable<String,Object>(); private Map<String,Map<String,String>> properties = new HashMap<String, Map<String,String>>(); private String path = "beans.xml"; public void setPath(String path) { this.path = path; } //获取装配好的类对象 public Object getBean(String id) { return beans.get(id); } private void init() { //解析XML,创建对应的对象。 SAXReader reader = new SAXReader(); try { Document doc = reader.read(this.getClass().getClassLoader().getResource(path)); Element root = doc.getRootElement(); Iterator<Element> beanElements = root.elementIterator(); while(beanElements.hasNext()) { Element beanElement = beanElements.next(); //取出beans标签中的id和class String idAttr = beanElement.attributeValue("id"); if(idAttr==null) { throw new RuntimeException("有一个bean标签忘记写id了"); } String classAttr = beanElement.attributeValue("class"); if(classAttr==null) { throw new RuntimeException("有一个bean标签忘记写class了"); } //这里可以使用反射创建类对象了。 Object obj = Class.forName(classAttr).newInstance(); //将对象放入map beans.put(idAttr, obj); //取出子节点 保存子节点 Map<String,String> pros = new HashMap<String, String>(); Iterator<Element> propertyElements = beanElement.elementIterator(); while(propertyElements.hasNext()) { Element propertyElement = propertyElements.next(); //取出name属性和ref属性 String name = propertyElement.attributeValue("name"); if(name==null) { throw new RuntimeException("有一个property标签忘记写name了"); } String ref = propertyElement.attributeValue("ref"); if(ref==null) { throw new RuntimeException("有一个property标签忘记写ref了"); } //将属性的数据保存 pros.put(name,ref); } properties.put(idAttr, pros); } //所有循环结束之后,设置属性 Set<Entry<String, Map<String, String>>> entrySet = properties.entrySet(); for(Entry<String, Map<String, String>> entry : entrySet) { String id = entry.getKey();//获取类对象的ID Object obj = beans.get(id);//取出对应的对象 stuService //遍历属性 Map<String, String> ps = entry.getValue(); Set<Entry<String, String>> entrySet2 = ps.entrySet(); for(Entry<String, String> entry2 : entrySet2) { String name = entry2.getKey(); String ref = entry2.getValue(); //取出要设置的引用对象 Object refObj = beans.get(ref); //找出set方法 stuDAO setStuDAO String setMethodName = "set"+name.substring(0, 1).toUpperCase()+name.substring(1); //找出方法 Method method = obj.getClass().getMethod(setMethodName, refObj.getClass().getInterfaces()[0]); if(method==null) { throw new RuntimeException("兄弟,你忘记写set方法了!"); } //执行对象设置属性 method.invoke(obj, refObj); } } } catch (DocumentException e) { e.printStackTrace(); throw new RuntimeException("你的beans.xml文件名称或者位置配置错误,应该将beans.xml放在src下"); } catch(ClassNotFoundException e) { e.printStackTrace(); throw new RuntimeException("class属性配置出现错误,全限定类名不正确或者类没有无参数的构造方法"); } catch(Exception e) { e.printStackTrace(); } } }