Notes on manipulating Xml in Java

  • List item

Article directory

  • Notes on manipulating Xml in Java
    • 1. Introduction to the use of XmlUtil in Hutool
    • 2. XmlUtil in Hutool quickly reads the value of a certain node in an Xml string [recommended for simple values]
      • 2-1 Hutool toolkit Maven dependencies and test Xml strings are as follows
      • 2-2 Read the value of the node in Xml
    • 3. Detailed operation example of XmlUtil in Hutool
      • 3-1 Xml sample string is as follows
      • 3-2 Query attributes in tags
      • 3-3 Query the text in a pair of tags
      • 3-4 After querying Xml, add a new tag and assign it
      • 3-5 Modify a label data
    • 4 Rely on the tool class XmlUtil re-encapsulated by Hutool to realize xml-map, map-xml, xml-json functions
      • 4-1 Dependencies that need to be added
      • 4-2 Tool class XmlUtil code
        • An enumeration XmlSort used in 4-2-1 is as follows:
        • 4-2-2 XmlUtil.java is as follows
    • 5 Interchange between JavaBean and Xml_Using XStream to achieve, very practical [strongly recommended]
      • 5-1 Introduce XStream dependency
      • 5-2 Tool class XStreamXmlBeanUtil
      • 5-3 Use cases

Notes on using Xml in Java

1. Introduction to the use of XmlUtil in Hutool

# Explanation 1: XmlUtil is just a simple tool package of w3c dom, which reduces the difficulty of operating dom.
# If the project relies heavily on XML, the Dom4j framework is still recommended
# Description 2: JDK has been packaged with XML parsing and construction tools: w3c dom
# XmlUtil in Hutool simplifies the creation, reading and writing of XML
1. Read XML
Reading XML is divided into two methods:

XmlUtil.readXML read XML file
XmlUtil.parseXml parses XML strings into Document objects
\t
2. Write XML
XmlUtil.toStr converts XML documents to String
XmlUtil.toFile writes an XML document to a file
\t
3. Create XML
XmlUtil.createXml creates XML documents, and the created XML defaults to utf8 encoding.
The process of modifying the encoding is in the toStr and toFile methods, that is, the encoding is only defined when XML is converted into text.

4. XML read operation
Through the following tool methods, basic node read operations can be completed.
XmlUtil.cleanInvalid removes invalid characters in XML text
XmlUtil.getElements obtains the list of child nodes according to the node name
XmlUtil.getElement gets the first child node according to the node name
XmlUtil.elementText gets the first child node according to the node name
XmlUtil.transElements converts NodeList to Element list
\t\t
5. XML and object conversion
writeObjectAsXml converts a serializable object to XML and writes it to a file. Existing files will be overwritten.
readObjectFromXml reads an object from XML.
Note that these two methods rely heavily on JDK's XMLEncoder and XMLDecoder,
Generation and parsing must exist in pairs (following a fixed format), and ordinary XML to Bean will report an error.

6. XPath operation
createXPath creates XPath
getByXPath reads information such as XML nodes through XPath

2. XmlUtil in Hutool quickly reads the value of a node in an Xml string [recommended for simple values]

2-1 Hutool toolkit Maven dependencies and test Xml strings are as follows

<!-- Introduce Hutool's Maven dependency -->
<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.8.16</version>
</dependency>
<!-- Xml string for the test below -->
<?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 Read the value of the node in Xml

Document docResult=XmlUtil. readXML(xmlFile);
// The result is "ok"
Object value = XmlUtil.getByXPath("//returnsms/message", docResult, XPathConstants.STRING);

// Note: Element objects currently only support layer-by-layer downward parsing, so please do not skip levels to do queries.
// Otherwise, null will be reported. If you want to directly get the text of a label, with accurate positioning
// You can directly write the path to get,
// But if the same label exists in this level, only the data of the first label will be obtained.
String xmlData="xml string";
Document document = XmlUtil. parseXml(xmlData);
// Get the root node of the XML document
Element elementG=XmlUtil. getRootElement(document);
// Get the data through a fixed path
Object bString = XmlUtil.getByXPath("//root/base/message/event_no", document, XPathConstants.STRING);
System.out.println("event_no element node value: " + bString);

3. Detailed operation example of XmlUtil in Hutool

3-1 Xml sample string is as follows

<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>
                    CCB I
                </value>
            </column>
            <column name="field2">
                <value>
                    Chinese people
                </value>
            </column>
        </values>
        <subForms/>
    </formExport>
</forms>

3-2 Query attributes in tags

// Example: Get the value of the length attribute of the first tag <column> in the <definitions> tag

String xmlData="the xml string specified above"; // replace it by yourself during the test
Document document = XmlUtil. parseXml(xmlData);
// Get the root node of the XML document
Element elementG=XmlUtil. getRootElement(document);
// print node name
System.out.println(elementG.getTagName());
// Get the lower node (this method takes the first one by default)
Element elementZ=XmlUtil.getElement(elementG,"formExport");
System.out.println(elementZ.getTagName());
// Get the lower node (this method takes the first one by default)
Element elementZ1=XmlUtil.getElement(elementZ,"definitions");
System.out.println(elementZ1.getTagName());
// Get the lower node (this method takes the first one by default)
Element elementZ2=XmlUtil.getElement(elementZ1,"column");
System.out.println(elementZ2.getTagName());


//Read attribute length
System.out.println(elementZ2.getAttribute("length"));

3-3 Query the text in a pair of tags

// Example: Get the text contained in <value> under the first tag <column> in the <values> tag, you can directly see the last line

// ======= The following content is the same as 3-2, and the content starts =================================== ========
String xmlData="the xml string specified above";
Document document = XmlUtil. parseXml(xmlData);
// Get the root node of the XML document
Element elementG=XmlUtil. getRootElement(document);
// Get the lower node (this method takes the first one by default)
Element elementZ=XmlUtil.getElement(elementG,"formExport");
// Get the lower node (this method takes the first one by default)
Element elementZ_1=XmlUtil.getElement(elementZ,"values");
// Get the lower node (this method takes the first one by default)
Element elementZ_2=XmlUtil.getElement(elementZ_1,"column");
// ======= The above content is the same as 3-2, the content ends =================================== ========

// Get all sub-tags // NodeList when Value is returned, just traverse to get it
NodeList nodeList=elementZ_2.getElementsByTagName("value");
for (int i = 0; i <nodeList.getLength() ; i ++ ) {<!-- -->
    // print the text of the label
    System.out.println(nodeList.item(i).getTextContent());
}

3-4 After querying Xml, add a new tag and assign a value

// Example: Add another <value> tag under the first tag <column> in the <values> tag, and the contained text is: start from zero

// ======= The following content is the same as 3-2, and the content starts =================================== ========
String xmlData="the xml string specified above";
Document document = XmlUtil. parseXml(xmlData);
// Get the root node of the XML document
Element elementG=XmlUtil. getRootElement(document);
// Get the lower node (this method takes the first one by default)
Element elementZ=XmlUtil.getElement(elementG,"formExport");
// Get the lower node (this method takes the first one by default)
Element elementZ_1=XmlUtil.getElement(elementZ,"values");
// Get the lower node (this method takes the first one by default)
Element elementZ_2=XmlUtil.getElement(elementZ_1,"column");
// ======= The above content is the same as 3-2, the content ends =================================== ========

// create a label
Element elementItem = document. createElement("value");
//assignment
elementItem.setTextContent("Start from zero");
// put it under a label
elementZ_2.appendChild(elementItem);
//Get all subtags
NodeList nodeList=elementZ_2.getElementsByTagName("value");
for (int i = 0; i <nodeList.getLength() ; i ++ ) {<!-- -->
    // print the text of the label
    System.out.println(nodeList.item(i).getTextContent());
}
System.out.println(XmlUtil.toStr(document));

// Printed result: After <value>CCB I</value>, a new <value>starts from zero</value>

3-5 modify a tag data

// Example: Modify the first <value> tag under the first tag <column> in the <values> tag to: Zhang Sanfeng

// ======= The following content is the same as 3-2, and the content starts =================================== ========
String xmlData="the xml string specified above";
Document document = XmlUtil. parseXml(xmlData);
// Get the root node of the XML document
Element elementG=XmlUtil. getRootElement(document);
// Get the lower node (this method takes the first one by default)
Element elementZ=XmlUtil.getElement(elementG,"formExport");
// Get the lower node (this method takes the first one by default)
Element elementZ_1=XmlUtil.getElement(elementZ,"values");
// Get the lower node (this method takes the first one by default)
Element elementZ_2=XmlUtil.getElement(elementZ_1,"column");
// ======= The above content is the same as 3-2, the content ends =================================== ========

//Get all subtags
NodeList nodeList=elementZ_2.getElementsByTagName("value");
// first print
for (int i = 0; i <nodeList.getLength() ; i ++ ) {<!-- -->
    // print the text of the label
    System.out.println(nodeList.item(i).getTextContent());
}
//Revise
for (int i = 0; i <nodeList.getLength() ; i ++ ) {<!-- -->
    // ******************* Modify here *********************
    nodeList.item(i).setTextContent("Zhang Sanfeng");
}
// second print
for (int i = 0; i <nodeList.getLength() ; i ++ ) {<!-- -->
    // print the text of the label
    System.out.println(nodeList.item(i).getTextContent());
}
// print out the result:
// The first print output is: CCB I
// The second printout is: Zhang Sanfeng

4 Rely on the tool class XmlUtil re-encapsulated by Hutool to realize xml-map, map-xml, xml-json functions

// Function:
// 1.xml to map
// 2.xml to json
// 3. map to xml

4-1 Dependencies that need to be added

<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 Tool class XmlUtil code

An enumeration XmlSort used in 4-2-1 is as follows:

import java.util.HashMap;
import java.util.LinkedHashMap;
 
 
/**
 * Whether the xml parsing order is in order
 * @author ASen
 */
 
public enum XmlSort{<!-- -->
    /**
     * orderly
     */
    SORT(LinkedHashMap.class,"Ordered"),
    /**
     * Disorder
     */
    NO_SORT(HashMap.class,"Unordered");
 
    /**
     * Created map bytecode object
     */
    private final Class<?> mapClass;
 
    /**
     * sequence name
     */
    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 is as follows

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 parsing helper class
 * @author asen
 * @date 2022/1/10 15:17
 */
public class XmlUtil {<!-- -->
 
    /**
     * Label attribute
     */
    private final static String TAG_ATTR = "attr";
 
    /**
     * The type of map created
     */
    private XmlSort xmlSort = XmlSort.NO_SORT;
 
    /**
     * map to xml
     * @param map map object
     * @return xml string
     */
    public String mapToXml(Map<String,Object> map) {<!-- -->
        if(map. size() != 1){<!-- -->
            throw new RuntimeException("map root node length is not 1");
        }
        String key = "";
        for (String str : map. keySet()) {<!-- -->
            key = str;
        }
        // create root node
        Element rootElement = new DefaultElement(key);
        Document document = new DefaultDocument(rootElement);
        Element node = document. getRootElement();
        Object obj = map. get(key);
        // assert
        Assert.isAssignable(Map.class, obj.getClass());
        mapNodes(node,(Map<String, Object>)obj);
        return document.asXML();
    }
 
    /**
     * The parent class node has been created, and the map contains the parent class
     * @param node node
     * @param map map
     */
    public void mapNodes(Element node, Map<String, Object> map) {<!-- -->
        map.forEach((k,v)->{<!-- -->
            Object obj = map. get(k);
            // Add properties to the current parent class
            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 processing
                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);
                });
            }
        });
    }
 
 
    /**
     * Read the xml file and return the json string
     *
     * @param fileName file path
     * @return json string
     * @throws DocumentException exception
     */
    public String xmlToJson(String fileName) throws DocumentException {<!-- -->
        Map<String, Object> xmlMap = xmlToMap(fileName);
        return JSONUtil.toJsonStr(xmlMap);
    }
 
    /**
     * Read the xml file and return the map object
     *
     * @param fileName file path
     * @return map object
     * @throws DocumentException exception
     */
    public Map<String, Object> xmlToMap(String fileName) throws DocumentException {<!-- -->
        // create saxReader object
        SAXReader reader = new SAXReader();
        // Read a file through the read method and convert it into a Document object
        Document document = reader. read(new File(fileName));
        // Get the root node element object
        Element node = document. getRootElement();
        //Loop through all element nodes
        Map<String, Object> map = getNewMap();
        // process node
        listNodes(node, map);
        return map;
    }
 
 
    /**
     * Traversing all (element's) child nodes below the current node element
     *
     * @param node node
     */
    public void listNodes(Element node, Map<String, Object> map) {<!-- -->
        Map<String, Object> xiaoMap = getNewMap();
        String nodeKey = node. getName();
        // Get all attribute nodes of the current node
        List<Attribute> list = node.attributes();
        // loop through attribute nodes
        Map<String, Object> attrMap = getNewMap();
        for (Attribute attr : list) {<!-- -->
            attrMap.put(attr.getName(), attr.getValue());
        }
        if (ObjectUtil.isNotEmpty(attrMap)) {<!-- -->
            xiaoMap.put(TAG_ATTR, attrMap);
        }
 
        // Child node iterator below the current node
        Iterator<Element> it = node. elementIterator();
 
        if (!("".equals(node.getTextTrim())) || !it.hasNext()) {<!-- -->
            map.put(nodeKey, node.getTextTrim());
        }else{<!-- -->
            // not null
            if (ObjectUtil.isEmpty(map.get(nodeKey))) {<!-- -->
                map.put(nodeKey, xiaoMap);
            } else {<!-- -->
                List<Map<String, Object>> childList = null;
                // get the original
                Object obj = map. get(nodeKey);
                if (obj instanceof Iterable) {<!-- -->
                    // not the first
                    childList = (List<Map<String, Object>>) obj;
                    childList.add(xiaoMap);
                } else if (obj instanceof Map) {<!-- -->
                    // First
                    Map<String, Object> childMap = (Map<String, Object>) obj;
                    childList = new ArrayList<>();
                    childList.add(childMap);
                    childList.add(xiaoMap);
                }
                // add new
                map. put(nodeKey, childList);
            }
        }
 
        // traverse
        while (it.hasNext()) {<!-- -->
            // Get a child node object
            Element e = it. next();
            // traverse the child nodes
            listNodes(e, xiaoMap);
        }
    }
 
    /**
     * Get a new map object
     *
     * @return map object
     */
    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;
    }
 
    /**
     * Set whether to sort
     *
     * @param xmlSort Whether to sort objects
     */
    public void setXmlSort(XmlSort xmlSort) {<!-- -->
        this.xmlSort = xmlSort;
    }
}

5 Interchange between JavaBean and Xml_Using XStream to achieve, very practical [strongly recommended]

Description:
Compared to JAXB, XStream is more concise.
Common annotations:
@XStreamAlias: Define xml node name

5-1 Introduce XStream dependency

<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.19</version>
</dependency>

5-2 Tool class XStreamXmlBeanUtil

import com.thoughtworks.xstream.XStream;
 
/**
 * XStream implements conversion between bean and xml
 */
public class XStreamXmlBeanUtil {<!-- -->
    /**
     * JavaBean to XML
     * @param bean - JavaBean
     * @return - XML
     */
    public static String toXml(Object bean) {<!-- -->
        return initXStream(bean. getClass()). toXML(bean);
    }
 
    /**
     * XML to 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")));
\t\t
        //Do not use the default class loader, you need to manually set the class loader
        x.setClassLoader(beanClazz.getClassLoader());
        x. processAnnotations(beanClazz);
        x.allowTypesByRegExp(new String[]{<!-- -->".*"});
        // Enable annotation function
        x. autodetectAnnotations(true);
        // suddenly unknown field
        x.ignoreUnknownElements();
        return x;
    }
}

5-3 Use cases

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. Common bean and Xml conversion
        User user = new User("Diao Chan", 18, "Female");
        System.out.println("============ normal bean to Xml=================");
        String xml = XStreamXmlBeanUtil.toXml(user);
        System.out.println(xml);
System.out.println("============Xml to ordinary bean=================");
        System.out.println(XStreamXmlBeanUtil.fromXml(xml, User.class));
 
 // 2. Inherited bean and Xml exchange
        Child child = new Child("Eat candied haws");
        child.setName("cucurbit baby");
        child. setAge(2);
        child.setGender("Male");
        child.setHobby("playing games");
 
        System.out.println("============= inherited bean to Xml=================");
        xml = XStreamXmlBeanUtil.toXml(child);
        System.out.println(xml);
        System.out.println("============Xml to inherit bean====");
// The generated Xml only has the attribute hobby of Child, but the parent attribute of the converted Child object has values;
        System.out.println(XStreamXmlBeanUtil.fromXml(xml, Child.class));
        System.out.println("============Xml to inherit bean, test whether the parent attribute and its own attribute have value====");
        Child c2 = XStreamXmlBeanUtil.fromXml(xml, Child.class);
        System.out.println( "11111==" + c2.getName() + c2.getGender() + c2.getHobby());
\t\t
// The output is as follows:
// ============= Ordinary bean to Xml================
// <Women>
// <name>Diao Chan</name>
// <age>18</age>
// <gender>female</gender>
// </Women>
// =============Xml to normal bean================
// XmlTest.User(name=Diaochan, age=18, gender=female)
// ============= Inherited bean to Xml================
// <User>
// <name>Gourd Baby</name>
// <age>2</age>
// <gender>Male</gender>
// <hobby>playing games</hobby>
// </User>
// ============Xml to inherit bean====
// XmlTest.Child(hobby=playing games)
// 11111==Gourd boy playing games
    }
}
 
@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;
}