要解析如下xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <ns2:FeatureDictionaryResponse xmlns="urn:xxx/Common/MetadataModel" xmlns:ns2="urn:xxx/Metadata"> <ns2:Catalog id="xxxxx-xxxx-xxx-xxxx"/> <ns2:Config> <ProductSelections> <Series id="abc" selectable="false" compound="false" multi="false"> <Feature id="Q0001"/> <Feature id="Q0002"/> </Series> <Series id="def" selectable="false" compound="false" multi="false"> <Feature id="G0001"/> </Series> </ProductSelections> </ns2:Config> </ns:FeatureDictionaryResponse>
一种方法是通过DOM解析方式实现,缺点是嵌套层次多导致代码不易读,修改起来麻烦。这里我们用类似反序列化方式来实现。
一、定义xml节点对应的类
首先定义最内层节点对应的类:
package com.example.model; import lombok.Data; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlRootElement; @XmlAccessorType(XmlAccessType.FIELD) @XmlRootElement(name = "Feature") @Data public class Feature { @XmlAttribute(name = "id") protected String id; }
然后定义其父节点对应的类:
package com.example.model; import lombok.Data; import javax.xml.bind.annotation.*; import java.util.List; @XmlAccessorType(XmlAccessType.FIELD) @XmlRootElement(name = "Series") @Data public class Series { @XmlAttribute protected String id; @XmlElement(name = "Feature") private List<Feature> features; }
以此类推
package com.example.model; import lombok.Data; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; import java.util.List; @XmlRootElement(name = "ProductSelections") @XmlAccessorType(XmlAccessType.FIELD) @Data public class ProductSelections { @XmlElement(name = "Series") protected List<Series> series; }
package com.example.model; import lombok.Data; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; @XmlAccessorType(XmlAccessType.FIELD) @XmlRootElement(name = "ns2:Config") @Data public class Config { @XmlElement(name = "ProductSelections") protected ProductSelections productSelections; }
最外层的类
package com.example.model; import lombok.Data; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; @XmlAccessorType(XmlAccessType.FIELD) @XmlRootElement(name = "FeatureDictionaryResponse", namespace = "urn:xxx/Metadata") @Data public class FeatureDictionaryResponse { @XmlElement(name = "Config", namespace = "urn:xxx/Metadata") protected Config config; }
由于xml中有自定义命名空间,所以我们需要添加一个package-info.java文件(在IDEA中直接添加会提示命名不合法,所以要手动创建出此文件),其内容如下
@XmlSchema(namespace = "urn:xxx/Common/MetadataModel", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED, xmlns = { @XmlNs(prefix = "ns2", namespaceURI = "urn:xxx/Metadata") }) package com.example.model; import javax.xml.bind.annotation.XmlSchema; import javax.xml.bind.annotation.XmlNs;
最后创建一个XmlUtil.java(来源于网上其他博主),提供将字符串解析为对象的方法。
package com.example.common; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; import javax.xml.bind.Unmarshaller; import java.io.StringReader; import java.io.StringWriter; import java.util.Map; public class XmlUtil { /** * 将对象直接转换成String类型的 XML输出 * @param obj * @return */ public static String convertToXml(Object obj) { // 创建输出流 StringWriter sw = new StringWriter(); try { // 利用jdk中自带的转换类实现 JAXBContext context = JAXBContext.newInstance(obj.getClass()); Marshaller marshaller = context.createMarshaller();// 格式化xml输出的格式 marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); // 将对象转换成输出流形式的xml marshaller.marshal(obj, sw); } catch (JAXBException e) { e.printStackTrace(); } return sw.toString(); } public static String mapToXml(Map<String, Object> map) {// 创建输出流 StringBuilder sb = new StringBuilder(); sb.append("<xml> "); //值 for (Map.Entry<String, Object> entry : map.entrySet()) { sb.append("<").append(entry.getKey()).append(">"); sb.append(entry.getValue().toString()); sb.append("</").append(entry.getKey()).append("> "); } sb.append("</xml> "); return sb.toString(); } @SuppressWarnings("unchecked") /** 将String类型的xml转换成对象 */ public static <T> T convertToObj(String xmlStr, Class<T> clazz) { T xmlObject = null; // 进行将Xml转成对象的核心接口 try { JAXBContext context = JAXBContext.newInstance(clazz); Unmarshaller unmarshaller = context.createUnmarshaller(); StringReader sr = new StringReader(xmlStr); xmlObject = (T) unmarshaller.unmarshal(sr); } catch (JAXBException e) { e.printStackTrace(); } return xmlObject; } }
测试:
package com.example; import com.example.common.XmlUtil; import com.example.model.FeatureDictionaryResponse; import java.io.BufferedReader; import java.io.FileReader; /** * @Author jian.yu * @Date 2021/2/4,0004 17:44 * @Description */ public class App { public static void main(String[] args) { StringBuilder content = new StringBuilder(); try { FileReader reader = new FileReader("D:\Demo\XmlResolve\data.xml"); BufferedReader br = new BufferedReader(reader); String line = br.readLine(); while (line != null) { content.append(line); line = br.readLine(); } br.close(); } catch (Exception ex) { System.out.println(ex); } FeatureDictionaryResponse fd = XmlUtil.convertToObj(content.toString(), FeatureDictionaryResponse.class); System.out.println(fd.getConfig().getProductSelections().getSeries()); } }
输出结果:
源码:点此下载