java---解析XML文件,通過反射動態將XML內容封裝到一個類中


本博客講的XML解析,使用的是dom4j。

首先建立一個maven項目,在dom.xml中引入相應的dom4j的版本。作者下載的是熱度很高的1.6.1版本。maven的使用在這里不做詳細講解。

引入成功后,來簡單了解該包提供的API

1.org.dom4j.io.SAXReader.class-----該類提供了reader方法,可以將xml文件讀取為Document對象,該方法返回值類型為Document

2.org.dom4j.Document.class----------該類提供了getRootElement方法,可以獲得Document對象的根節點,此方法返回值類型是Element

3.org.dom4j.Element-------該類提供了elements方法,獲取所有的子節點,返回值類型為Element;

                attributeValue方法,獲得通過屬性名節點的屬性值,返回值類型為String

                getStringValue()方法,獲得element的文本值,返回值類型為String

下面使用上述方法來解析XML文件。

一:新建或者自己導如XML文件。作者為了方便演示,新建一個新的XML文件,如下。

<?xml version="1.0" encoding="UTF-8"?>

<students>
    <student id="1">
        <name>Claire</name>
        <age>18</age>
        <gender>女</gender>
    </student>
    <student id="2">
        <name>Leafly</name>
        <age>18</age>
        <gender>男</gender>
    </student>
    <student id="3">
        <name>Dingdang</name>
        <age>18</age>
        <gender>男</gender>
    </student>
    <student id="4">
        <name>DingDing</name>
        <age>18</age>
        <gender>男</gender>
    </student>
    <student id="5">
        <name>DangDang</name>
        <age>18</age>
        <gender>女</gender>
    </student>

</students>

2.將上述xml文件放到src下面。

3.創建一個Student類,其屬性與上述xml中的元素一致。

public class Student {
    //private static final int AAA = 1;
    private String id;
    private String name;
    private String age;
    private String gender;
    
    
    //構造
    
    public Student() {
        
    }
    
    public Student(String id, String name, String age, String gender) {
        super();
        this.id = id;
        this.name = name;
        this.age = age;
        this.gender = gender;
    }
    
    



    //getter setter
    public String getId() {
        return id;
    }
    
    public void setId(String id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getAge() {
        return age;
    }
    public void setAge(String age) {
        this.age = age;
    }
    public String getGender() {
        return gender;
    }
    public void setGender(String gender) {
        this.gender = gender;
    }


    
    
    //toString
    @Override
    public String toString() {
        return "Student [id=" + id + ", name=" + name + ", age=" + age + ", gender=" + gender + "]";
    }
    

}

 

4.創建新類ReadXMl,在該類中創建方法來解析XML文件。

    private static void readXmlFun() throws DocumentException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {
        
        
        //1.反射,得到類的引用
        Class student = Class.forName("readXmlAndReflect.Student");
        //通過類的引用,得到類的對象
        Object stuInstance = student.newInstance();
        //創建一個list 來放多個student的對象
        List<Student> students = new ArrayList<Student>();
        
        SAXReader reader = new SAXReader();
        //將XML文件讀取為一份document對象
        Document document = reader.read(readXmlFun.class.getResourceAsStream("/StudentDate.xml"));
        //利用Document類中的方法,獲取根節點.返回的是Element
        Element rootElement = document.getRootElement();
        
        //利用Element中的方法,獲取根節點下的全部子節點.返回一個List<element>
        List<Element> elements = rootElement.elements();
        
        //利用Element中的方法,獲取子 節點中的屬性(StudentData中的屬性為id)
        //1.遍歷list,獲得每個元素
        for (Element element : elements) {
            System.out.println("---------------------------------");
            //遍歷並得到每個元素執行屬性名稱的屬性值
            String stuId = element.attributeValue("id");
            System.out.println("學生id為"+ stuId);
            //遍歷並獲得每個元素的全部子節點,返回一個List<element>
            List<Element> subElement = element.elements();
            
        
            //通過方法名反射出方法對象
            Method method2 = student.getDeclaredMethod("setId", String.class);
            //通過反射調用方法,stuInstance對象調用method,參數為stuData---相當於給各參數賦值
            method2.invoke(stuInstance, stuId);
            
            for (Element subElementData : subElement) {
                //得到每個子節點的名字
                String elementName = subElementData.getName();
                //遍歷並獲得每個子元素的文本內容,如得到name子節點的文本值為Claire
                String stuData = subElementData.getStringValue();
                System.out.println(elementName +"為" + stuData);
                
                
                //通過elemetname得到對應的get set方法,先拼接出方法名,比如 name--setName
                String funName = "set" + (elementName.charAt(0)+"").toUpperCase()+elementName.substring(1);
            
                //通過方法名反射出方法對象
                Method method1 = student.getDeclaredMethod(funName, String.class);
                //通過反射調用方法,調用stuInstance對象的method方法,參數為stuData---給各屬性賦值
                method1.invoke(stuInstance, stuData);
            }
            //將每個學生對象添加到list列表中
            students.add((Student)stuInstance);
            System.out.println(students);
        
        }
    }

 這里解釋下,上面使用的

Document document = reader.read(readXmlFun.class.getResourceAsStream("/StudentDate.xml"));
前面加上/------------代表在當前類的src下面找

 


如果沒有/--------------代表在跟類同級的目錄下找。








可以看到上面使用了反射。利用反射可以動態的為每一個Student對象賦值。當我們的XML文件改變,添加或刪除了新的屬性之后,完全不需要去修改我們的ReadXML類,只在Student類中添加或刪除對應的屬性即可。實現了解耦。

 我們經常通過反射來做下面的事情:

1.獲取到某各類的引用

  通常有3種方式:

    1.Class clazz = Class.forName(" 這里必須是類全名");

    2.我們每一個類都有一個靜態的class屬性:Class clazz =類名A.Class(這個與第一種方式的區別是,不會去運行類A中的靜態代碼塊);

    3.每個類都有一個getClass()方法: classA a = new ClassA(); Class clazz =a.getClass();

2.通過該類的引用獲取類的對象

  object o = clazz.newInstance();

3.通過該類的引用獲取屬性

 

  

4.通過該類的引用獲取所有方法(普通/構造)

 

 

下面代碼詳細說明了反射機制中常用的方法,有興趣可以了解下:

package readXmlAndReflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.sql.Types;

public class Reflect {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {
        Class clazz = Class.forName("readXmlAndReflect.Student");
        //創建對象
        Object o =clazz.newInstance();
        
        
        //創建一個stringBuffer
        StringBuffer buffer = new StringBuffer();
        
        //類 public class readXmlAndReflect.Student{}
        buffer.append("\n"+"-------------class-------------------"+"\n");
        buffer.append(Modifier.toString(clazz.getModifiers()) + " class " + clazz.getName()+"{"+"\n");
        
        //
        buffer.append("\n"+"-------------field-------------------"+"\n");
        //獲取所有聲明的屬性,包括私有和常量
        Field[] fields = clazz.getDeclaredFields();
        //遍歷所有的屬性
        for (Field field : fields) {
            //獲取屬性的修飾符 如public static 
            buffer.append("\t" + Modifier.toString(field.getModifiers()));
            //獲取屬性的類型 如 string int getType()獲取到的類全名(如java.lang.String),想要獲得簡單類型名如String,可以使用Class類中getSimpleName()方法
            buffer.append("\t" + field.getType().getSimpleName());
            //獲取屬性名稱
            buffer.append("\t" + field.getName());
            buffer.append(";"+"\n");
            
            //得到域之后有什么用呢?
            //我們可以直接使用得到的域給其賦值或讀取域的值,由於域都是私有的,這里需要利用反射打破類的封裝
            field.setAccessible(true);//如果沒有這一句,運行時會報錯java.lang.IllegalAccessException:
            //給對象0的域field 賦值為"3"
            field.set(o, "3");
            //獲取 對象o 的 域field 的值
            System.out.println(field.get(o));
            
        }
        
        
        
    
        
        //方法 如 public static string function(){}
        buffer.append("\n"+"-------------function-------------------"+"\n");
        //獲得所有聲明的方法,包括private
        Method[] motheds = clazz.getDeclaredMethods();
        
        for (Method method : motheds) {
            //獲得方法的修飾符 如 public static 
            buffer.append("\t"+Modifier.toString(method.getModifiers()) + " ");
            //獲得方法的返回值類型
            buffer.append(method.getReturnType().getSimpleName()+" ");
            //獲得方法名
            buffer.append(method.getName() + "(");
            //獲得方法的參數類型,可能有多個參數,所以返回值為一個數組
            Class[] parameterTypes = method.getParameterTypes();
            //遍歷方法的參數類型
            for (Class parameterType : parameterTypes) {
                //遍歷獲得每一個參數類型
                buffer.append(parameterType.getSimpleName()+", ");
            }
            buffer.append(") { }"+"\n");
            
        }
        
        
        //獲得方法有什么用??通常用來調用方法
        //1.先通過方法名來獲得一個方法
        Method setNameFun = clazz.getMethod("setName", String.class);
        //可以直接調用,調用方法method---調用o對象的setNameFun方法,參數為“小笨蛋”
        setNameFun.invoke(o, "小笨蛋");
        
        
        //構造方法
        buffer.append("\n" + "-------------constructions-------------------"+"\n");
        Constructor[] constructors = clazz.getDeclaredConstructors();
        for (Constructor constructor : constructors) {
            
            buffer.append(Modifier.toString(constructor.getModifiers()) + " ");
            buffer.append(constructor.getName() + " (");
            Class[] parametertypes = constructor.getParameterTypes();
            for (Class parametertype : parametertypes) {
                buffer.append(parametertype.getSimpleName() +",");
            }
            buffer.append(") { }"+"\n");
        }
        
        buffer.append("}");
        
        System.out.println(buffer);
    }

}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM