Java中操作Xml使用方法備忘錄(Hutool工具類XmlUtil、XStream)
1. Hutool中XmlUtil的使用簡介
# 說明1: XmlUtil只是w3c dom的簡單工具化封裝,減少操作dom的難度,
# 如果項目對XML依賴較大,依舊推薦Dom4j框架
# 說明2:JDK已經封裝有XML解析和構建工具:w3c dom
# Hutool中XmlUtil簡化XML的創(chuàng)建、讀、寫
1. 讀取XML
讀取XML分為兩個方法:XmlUtil.readXML 讀取XML文件
XmlUtil.parseXml 解析XML字符串為Document對象
2. 寫XML
XmlUtil.toStr 將XML文檔轉換為String
XmlUtil.toFile 將XML文檔寫入到文件
3. 創(chuàng)建XML
XmlUtil.createXml 創(chuàng)建XML文檔, 創(chuàng)建的XML默認是utf8編碼,
修改編碼的過程是在toStr和toFile方法里,既XML在轉為文本的時候才定義編碼。4. XML讀取操作
通過以下工具方法,可以完成基本的節(jié)點讀取操作。
XmlUtil.cleanInvalid 除XML文本中的無效字符
XmlUtil.getElements 根據(jù)節(jié)點名獲得子節(jié)點列表
XmlUtil.getElement 根據(jù)節(jié)點名獲得第一個子節(jié)點
XmlUtil.elementText 根據(jù)節(jié)點名獲得第一個子節(jié)點
XmlUtil.transElements 將NodeList轉換為Element列表
5. XML與對象轉換
writeObjectAsXml 將可序列化的對象轉換為XML寫入文件,已經存在的文件將被覆蓋。
readObjectFromXml 從XML中讀取對象。
注意 這兩個方法嚴重依賴JDK的XMLEncoder和XMLDecoder,
生成和解析必須成對存在(遵循固定格式),普通的XML轉Bean會報錯。6. Xpath操作
createXPath 創(chuàng)建XPath
getByXPath 通過XPath方式讀取XML節(jié)點等信息
2. Hutool中XmlUtil快速讀取Xml字符串某個節(jié)點值 [簡單取值時,推薦使用]
2-1 Hutool工具包Maven依賴和測試Xml字符串如下
<!-- 引入Hutool的Maven依賴 --> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.8.16</version> </dependency>
<!-- 下方測試用的Xml字符串 --> <?xml version="1.0" encoding="utf-8"?> <returnsms> <returnstatus>Success(成功)</returnstatus> <message>ok</message> <remainpoint>1490</remainpoint> <taskID>885</taskID> <successCounts>1</successCounts> </returnsms>
2-2 讀取Xml中的節(jié)點的值
Document docResult=XmlUtil.readXML(xmlFile); // 結果為“ok” Object value = XmlUtil.getByXPath("http://returnsms/message", docResult, XPathConstants.STRING); // 說明:Element對象目前僅能支持一層一層的向下解析,所以請不要跳級去做查詢, // 否則會報null。如果想直接獲取到某個標簽的文本,在有準確定位的情況下 // 可以直接寫出路徑獲取, // 但是如果該層級存在相同的標簽則只獲取第一個標簽的數(shù)據(jù)。 String xmlData="xml字符串"; Document document= XmlUtil.parseXml(xmlData); //獲得XML文檔根節(jié)點 Element elementG=XmlUtil.getRootElement(document); //通過固定路徑獲取到數(shù)據(jù) Object bString = XmlUtil.getByXPath("http://root/base/message/event_no", document, XPathConstants.STRING); System.out.println("event_no元素節(jié)點值:"+bString);
3. Hutool中XmlUtil詳細操作示例
3-1 Xml示例字符串如下
<forms version="2.1"> <formExport> <summary id="1132755668421070367" name="formmain_0031"/> <definitions> <column id="field0001" type="0" name="field1" length="255"/> <column id="field0002" type="0" name="field2" length="256"/> </definitions> <values> <column name="field1"> <value> 建行一世 </value> </column> <column name="field2"> <value> 中國人民 </value> </column> </values> <subForms/> </formExport> </forms>
3-2 查詢標簽內的屬性
// 例: 獲取<definitions>標簽中第一個標簽<column >屬性length的值 String xmlData="上面規(guī)定的xml字符串"; // 測試時自己替換下 Document document= XmlUtil.parseXml(xmlData); //獲得XML文檔根節(jié)點 Element elementG=XmlUtil.getRootElement(document); //打印節(jié)點名稱 System.out.println(elementG.getTagName()); //獲取下層節(jié)點(該方法默認取第一個) Element elementZ=XmlUtil.getElement(elementG,"formExport"); System.out.println(elementZ.getTagName()); //獲取下層節(jié)點(該方法默認取第一個) Element elementZ1=XmlUtil.getElement(elementZ,"definitions"); System.out.println(elementZ1.getTagName()); //獲取下層節(jié)點(該方法默認取第一個) Element elementZ2=XmlUtil.getElement(elementZ1,"column"); System.out.println(elementZ2.getTagName()); //讀取屬性length System.out.println(elementZ2.getAttribute("length"));
3-3 查詢一對標簽中的文本
// 例:獲取<values>標簽中第一個標簽<column>下的<value>所包含的文本,可直接看最后一行 // =======以下內容同3-2,內容開始======================================== String xmlData="上面規(guī)定的xml字符串"; Document document= XmlUtil.parseXml(xmlData); //獲得XML文檔根節(jié)點 Element elementG=XmlUtil.getRootElement(document); //獲取下層節(jié)點(該方法默認取第一個) Element elementZ=XmlUtil.getElement(elementG,"formExport"); //獲取下層節(jié)點(該方法默認取第一個) Element elementZ_1=XmlUtil.getElement(elementZ,"values"); //獲取下層節(jié)點(該方法默認取第一個) Element elementZ_2=XmlUtil.getElement(elementZ_1,"column"); // =======以上內容同3-2,內容結束======================================== //獲取到所有子標簽 // Value返回的時NodeList,遍歷獲取即可 NodeList nodeList=elementZ_2.getElementsByTagName("value"); for (int i = 0; i <nodeList.getLength() ; i++) { //打印標簽的文本 System.out.println(nodeList.item(i).getTextContent()); }
3-4 查詢Xml后,再新增一個標簽并賦值
// 例:給<values>標簽中第一個標簽<column>下再度添加一個<value>標簽,所包含的文本為:從零開始 // =======以下內容同3-2,內容開始======================================== String xmlData="上面規(guī)定的xml字符串"; Document document= XmlUtil.parseXml(xmlData); //獲得XML文檔根節(jié)點 Element elementG=XmlUtil.getRootElement(document); //獲取下層節(jié)點(該方法默認取第一個) Element elementZ=XmlUtil.getElement(elementG,"formExport"); //獲取下層節(jié)點(該方法默認取第一個) Element elementZ_1=XmlUtil.getElement(elementZ,"values"); //獲取下層節(jié)點(該方法默認取第一個) Element elementZ_2=XmlUtil.getElement(elementZ_1,"column"); // =======以上內容同3-2,內容結束======================================== //創(chuàng)建一個標簽 Element elementItem = document.createElement("value"); //賦值 elementItem.setTextContent("從零開始"); //放到某個標簽下面 elementZ_2.appendChild(elementItem); //獲取到所有子標簽 NodeList nodeList=elementZ_2.getElementsByTagName("value"); for (int i = 0; i <nodeList.getLength() ; i++) { //打印標簽的文本 System.out.println(nodeList.item(i).getTextContent()); } System.out.println(XmlUtil.toStr(document)); // 打印的結果: 在<value>建行一世</value>后,新增了一個<value>從零開始</value>
3-5 修改一個標簽數(shù)據(jù)
// 例:給<values>標簽中第一個標簽<column>下的第一個<value>標簽修改成:張三豐 // =======以下內容同3-2,內容開始======================================== String xmlData="上面規(guī)定的xml字符串"; Document document= XmlUtil.parseXml(xmlData); //獲得XML文檔根節(jié)點 Element elementG=XmlUtil.getRootElement(document); //獲取下層節(jié)點(該方法默認取第一個) Element elementZ=XmlUtil.getElement(elementG,"formExport"); //獲取下層節(jié)點(該方法默認取第一個) Element elementZ_1=XmlUtil.getElement(elementZ,"values"); //獲取下層節(jié)點(該方法默認取第一個) Element elementZ_2=XmlUtil.getElement(elementZ_1,"column"); // =======以上內容同3-2,內容結束======================================== //獲取到所有子標簽 NodeList nodeList=elementZ_2.getElementsByTagName("value"); //第一次打印 for (int i = 0; i <nodeList.getLength() ; i++) { //打印標簽的文本 System.out.println(nodeList.item(i).getTextContent()); } //修改 for (int i = 0; i <nodeList.getLength() ; i++) { // ******************* 這里進行修改 ******************** nodeList.item(i).setTextContent("張三豐"); } //第二次打印 for (int i = 0; i <nodeList.getLength() ; i++) { //打印標簽的文本 System.out.println(nodeList.item(i).getTextContent()); } // 打印輸出結果: // 第一次打印輸出為: 建行一世 // 第二次打印輸出為: 張三豐
4 依賴Hutool再次封裝的工具類XmlUtil,實現(xiàn)xml-map、map-xml、xml-json功能
// 作用:
// 1.xml轉map
// 2.xml轉json
// 3.map轉xml
4-1 需要添加的依賴
<dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.7.15</version> </dependency> <dependency> <groupId>org.dom4j</groupId> <artifactId>dom4j</artifactId> <version>2.1.3</version> </dependency>
4-2 工具類XmlUtil代碼
4-2-1 用到的一個枚舉XmlSort如下:
import java.util.HashMap; import java.util.LinkedHashMap; /** * xml解析順序是否有序 * @author ASen */ public enum XmlSort{ /** * 有序 */ SORT(LinkedHashMap.class,"有序"), /** * 無序 */ NO_SORT(HashMap.class,"無序"); /** * 創(chuàng)建的map字節(jié)碼對象 */ private final Class<?> mapClass; /** * 順序名稱 */ private final String message ; XmlSort(Class<?> mapClass, String message) { this.mapClass = mapClass; this.message = message; } public Class<?> getMapClass() { return mapClass; } public String getMessage() { return message; } }
4-2-2 XmlUtil.java如下
package com.asen.demo.util; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.ObjectUtil; import cn.hutool.json.JSONUtil; import com.asen.demo.constant.XmlSort; import org.dom4j.Attribute; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.Element; import org.dom4j.io.SAXReader; import org.dom4j.tree.DefaultDocument; import org.dom4j.tree.DefaultElement; import java.io.File; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; /** * xml解析幫組類 * @author asen * @date 2022/1/10 15:17 */ public class XmlUtil { /** * 標簽屬性 */ private final static String TAG_ATTR = "attr"; /** * 創(chuàng)建的map類型 */ private XmlSort xmlSort = XmlSort.NO_SORT; /** * map to xml * @param map map對象 * @return xml 字符串 */ public String mapToXml(Map<String,Object> map) { if(map.size() != 1){ throw new RuntimeException("map根節(jié)點長度不為1"); } String key = ""; for (String str : map.keySet()) { key = str ; } // 創(chuàng)建根節(jié)點 Element rootElement = new DefaultElement(key); Document document = new DefaultDocument(rootElement); Element node = document.getRootElement(); Object obj = map.get(key); // 斷言 Assert.isAssignable(Map.class,obj.getClass()); mapNodes(node,(Map<String, Object>)obj); return document.asXML(); } /** * 父類節(jié)點已經創(chuàng)建, map 包含父類 * @param node node * @param map map */ public void mapNodes(Element node, Map<String, Object> map) { map.forEach((k,v)->{ Object obj = map.get(k); // 給當前父類添加屬性 if(TAG_ATTR.equals(k)){ Assert.isAssignable(Map.class,obj.getClass()); Map<String,Object> tagMap = (Map<String,Object>) obj; tagMap.forEach((tagKey,tagValue)->{ node.addAttribute(tagKey, (String) tagValue); }); return ; } if(obj instanceof Map){ Element newElement = node.addElement(k); // map 處理 Map<String,Object> childMap = (Map<String,Object>) obj; mapNodes(newElement,childMap); }else if (obj instanceof String){ Element newElement = node.addElement(k); newElement.setText((String) v); } else if (obj instanceof List) { List<Map<String, Object>> list = (List<Map<String, Object>>) obj; list.forEach(itemMap->{ Element newElement = node.addElement(k); mapNodes(newElement,itemMap); }); } }); } /** * 讀取xml文件,返回json字符串 * * @param fileName 文件路徑 * @return json字符串 * @throws DocumentException 異常 */ public String xmlToJson(String fileName) throws DocumentException { Map<String, Object> xmlMap = xmlToMap(fileName); return JSONUtil.toJsonStr(xmlMap); } /** * 讀取xml文件,返回map對象 * * @param fileName 文件路徑 * @return map對象 * @throws DocumentException 異常 */ public Map<String, Object> xmlToMap(String fileName) throws DocumentException { // 創(chuàng)建saxReader對象 SAXReader reader = new SAXReader(); // 通過read方法讀取一個文件 轉換成Document對象 Document document = reader.read(new File(fileName)); //獲取根節(jié)點元素對象 Element node = document.getRootElement(); //遍歷所有的元素節(jié)點 Map<String, Object> map = getNewMap(); // 處理節(jié)點 listNodes(node, map); return map; } /** * 遍歷當前節(jié)點元素下面的所有(元素的)子節(jié)點 * * @param node node */ public void listNodes(Element node, Map<String, Object> map) { Map<String, Object> xiaoMap = getNewMap(); String nodeKey = node.getName(); // 獲取當前節(jié)點的所有屬性節(jié)點 List<Attribute> list = node.attributes(); // 遍歷屬性節(jié)點 Map<String, Object> attrMap = getNewMap(); for (Attribute attr : list) { attrMap.put(attr.getName(), attr.getValue()); } if (ObjectUtil.isNotEmpty(attrMap)) { xiaoMap.put(TAG_ATTR, attrMap); } // 當前節(jié)點下面子節(jié)點迭代器 Iterator<Element> it = node.elementIterator(); if (!("".equals(node.getTextTrim())) || !it.hasNext()) { map.put(nodeKey, node.getTextTrim()); }else{ // 不為空 if (ObjectUtil.isEmpty(map.get(nodeKey))) { map.put(nodeKey, xiaoMap); } else { List<Map<String, Object>> childList = null; // 獲取原來的 Object obj = map.get(nodeKey); if (obj instanceof Iterable) { // 非第一個 childList = (List<Map<String, Object>>) obj; childList.add(xiaoMap); } else if (obj instanceof Map) { // 第一個 Map<String, Object> childMap = (Map<String, Object>) obj; childList = new ArrayList<>(); childList.add(childMap); childList.add(xiaoMap); } // 添加新的 map.put(nodeKey, childList); } } // 遍歷 while (it.hasNext()) { // 獲取某個子節(jié)點對象 Element e = it.next(); // 對子節(jié)點進行遍歷 listNodes(e, xiaoMap); } } /** * 獲取一個新的map對象 * * @return map對象 */ private Map<String, Object> getNewMap() { Object obj = null; try { obj = xmlSort.getMapClass().newInstance(); if (obj instanceof Map) { return (Map<String, Object>) obj; } } catch (InstantiationException | IllegalAccessException e) { e.printStackTrace(); } return null; } /** * 設置是否排序 * * @param xmlSort 是否排序對象 */ public void setXmlSort(XmlSort xmlSort) { this.xmlSort = xmlSort; } }
5 JavaBean與Xml互轉_使用XStream實現(xiàn),很實用 [強烈推薦使用]
說明:
相對于JAXB,XStream更簡潔一些。
常用注解:
- @XStreamAlias:定義xml節(jié)點名
- @XStreamAsAttribute:把字段節(jié)點設置成屬性
5-1 引入XStream依賴
<dependency> <groupId>com.thoughtworks.xstream</groupId> <artifactId>xstream</artifactId> <version>1.4.19</version> </dependency>
5-2 工具類XStreamXmlBeanUtil
import com.thoughtworks.xstream.XStream; /** * XStream 實現(xiàn)bean與xml之間相互轉換 */ public class XStreamXmlBeanUtil { /** * JavaBean轉XML * @param bean - JavaBean * @return - XML */ public static String toXml(Object bean) { return initXStream(bean.getClass()).toXML(bean); } /** * XML轉JavaBean * @param xml - XML * @param beanClazz - JavaBean Class * @param <T> * @return - JavaBean */ @SuppressWarnings("unchecked") public static <T> T fromXml(String xml, Class<T> beanClazz) { return (T) initXStream(beanClazz).fromXML(xml); } private static XStream initXStream(Class<?> beanClazz) { XStream x = new XStream(); x.registerConverter(new DateConverter("yyyy-MM-dd HH:mm:ss", null,TimeZone.getTimeZone("GMT+8"))); //不使用默認的類加載器,需要手動設置類加載器 x.setClassLoader(beanClazz.getClassLoader()); x.processAnnotations(beanClazz); x.allowTypesByRegExp(new String[]{".*"}); // 開起注解功能 x.autodetectAnnotations(true); // 忽律未知字段 x.ignoreUnknownElements(); return x; } }
5-3 使用實例
import com.thoughtworks.xstream.annotations.XStreamAlias; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; public class Test { public static void main(String[] args) { // 1. 普通bean與Xml互轉 User user = new User("貂蟬", 18, "女"); System.out.println("============普通bean轉Xml==============="); String xml = XStreamXmlBeanUtil.toXml(user); System.out.println(xml); System.out.println("============Xml轉普通bean==============="); System.out.println(XStreamXmlBeanUtil.fromXml(xml, User.class)); // 2. 繼承bean與Xml互轉 Child child = new Child("吃糖葫蘆"); child.setName("葫蘆娃"); child.setAge(2); child.setGender("男"); child.setHobby("打游戲"); System.out.println("============繼承bean轉Xml==============="); xml = XStreamXmlBeanUtil.toXml(child); System.out.println(xml); System.out.println("============Xml轉繼承bean===="); // 生成的Xml僅有Child的屬性hobby,但轉后后的Child對象,父屬性都是有值的; System.out.println(XStreamXmlBeanUtil.fromXml(xml, Child.class)); System.out.println("============Xml轉繼承bean,測試轉換后,父屬性、自身屬性是否有值===="); Child c2 = XStreamXmlBeanUtil.fromXml(xml, Child.class); System.out.println( "11111==" + c2.getName() + c2.getGender() + c2.getHobby()); // 輸出內容如下: // ============普通bean轉Xml=============== // <Women> // <name>貂蟬</name> // <age>18</age> // <gender>女</gender> // </Women> // ============Xml轉普通bean=============== // XmlTest.User(name=貂蟬, age=18, gender=女) // ============繼承bean轉Xml=============== // <User> // <name>葫蘆娃</name> // <age>2</age> // <gender>男</gender> // <hobby>打游戲</hobby> // </User> // ============Xml轉繼承bean==== // XmlTest.Child(hobby=打游戲) // 11111==葫蘆娃男打游戲 } } @Data @NoArgsConstructor @AllArgsConstructor @XStreamAlias("Women") class User { private String name; private int age; private String gender; } @NoArgsConstructor @AllArgsConstructor @Data @XStreamAlias("User") class Child extends User { private String hobby; }
5-4 關于XStream更詳細的使用,如設置別名、設置屬性、隱藏集合根節(jié)點等,請參考如下博文
總結
到此這篇關于Java中操作Xml使用方法備忘錄的文章就介紹到這了,更多相關Java操作Xml使用內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
解決Mybatis 大數(shù)據(jù)量的批量insert問題
這篇文章主要介紹了解決Mybatis 大數(shù)據(jù)量的批量insert問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-01-01淺談java中math類中三種取整函數(shù)的區(qū)別
下面小編就為大家?guī)硪黄獪\談java中math類中三種取整函數(shù)的區(qū)別。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-11-11Java線程池ThreadPoolExecutor原理及使用實例
這篇文章主要介紹了Java線程池ThreadPoolExecutor原理及使用實例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-05-05在java中使用SPI創(chuàng)建可擴展的應用程序操作
這篇文章主要介紹了在java中使用SPI創(chuàng)建可擴展的應用程序操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-09-09Spring Boot通過Junit實現(xiàn)單元測試過程解析
這篇文章主要介紹了Spring Boot通過Junit實現(xiàn)單元測試過程解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-01-01Java 實現(xiàn)完整功能的學生管理系統(tǒng)實例
讀萬卷書不如行萬里路,只學書上的理論是遠遠不夠的,只有在實戰(zhàn)中才能獲得能力的提升,本篇文章手把手帶你用Java實現(xiàn)一個完整版學生管理系統(tǒng),大家可以在過程中查缺補漏,提升水平2021-11-11Java ArrayList add(int index, E element)和set(int index, E el
今天小編就為大家分享一篇關于Java ArrayList add(int index, E element)和set(int index, E element)兩個方法的說明,小編覺得內容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧2018-10-10