通用xml解析-XStream

场景介绍

  下面的xml模板是在项目中实际使用的。项目中所有的接口都具有相同的结构。

<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:cbcc:std:caps:2020:tech:xsd:caps.202.001.01" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
	<Message>
		<Head>
			<CorpNo>3310000001</CorpNo>
			<ResFlag>SUCC</ResFlag>
			<ErrorCode>I000</ErrorCode>
			<ErrorMsg>平台检验成功</ErrorMsg>
		</Head>
		<Body>
			<ReturnTime>2020-10-30T09:26:51</ReturnTime>
			<SysSeqNo>2020103050006167</SysSeqNo>
			<SerialNum>2020103000000001</SerialNum>
			<RetCode>111111</RetCode>
			<RetMsg>业务处理中</RetMsg>
			<Remark>专项科研经费</Remark>
			<Use>服务费202010</Use>
			<BtchNb>50006167</BtchNb>
		</Body>
	</Message>
</Document>

  所有接口结构统一,一个“Documen“根节点,下面一个“Message“子节点。“Message“下面两个子节点“Head“,“Body“,“Head“,“Body“下是具体的业务数据节点。

XStream工具类

导入XStream依赖

	<!-- 解析xml -->
	<dependency>
	   <groupId>com.thoughtworks.xstream</groupId>
	   <artifactId>xstream</artifactId>
	   <version>1.4.10</version>
	</dependency>
	<!-- fastjson, 展示解析结果 -->
	<dependency>
	  <groupId>com.alibaba</groupId>
	  <artifactId>fastjson</artifactId>
	  <version>1.2.59</version>
    </dependency>

XStreamXmlUtil.java代码

package com.xml.parse.utils;

import com.thoughtworks.xstream.XStream;

/**
 * 解析xml工具
 * @author pst19
 *
 */
public class XStreamXmlUtil {
	
	/**
	 * 文中的样例有两个子类节点Head,Body,每个接口是不同的。
	 * 根节点是Document
	 * @param xml		报文内容
	 * @param rootClass	根节点Class对象
	 * @param subClass1	业务子类节点1
	 * @param subClass2 业务子类节点2
	 * @return
	 */
	public static <T> T xmlToBean(String xml, Class<T> rootClass, Class<?> subClass1, Class<?> subClass2){
		
		XStream xStream = new XStream();
		XStream.setupDefaultSecurity(xStream);
		xStream.allowTypesByRegExp(new String[] { ".*" });
		
		//不使用默认的类加载器,需要手动设置类加载器
		xStream.setClassLoader(rootClass.getClassLoader());
		xStream.processAnnotations(new Class[]{rootClass, subClass1, subClass2});
		//使用子类代替父类。这是本方法通用的关键点,解析不同报文传入不同的子类对象,
		xStream.addDefaultImplementation(subClass1, subClass1.getSuperclass());
		xStream.addDefaultImplementation(subClass2, subClass2.getSuperclass());
		
		return (T)xStream.fromXML(xml);
	}
	
}

通用实体对象

  通过注解 完成xml节点和实体的层级映射

  1. 从根节点开始,首先是 Document
package com.xml.parse.entity;

import com.thoughtworks.xstream.annotations.XStreamAlias;

//映射根节点“Document”
@XStreamAlias("Document")
public class Document {
	//映射根节点下子节点“Message”
	@XStreamAlias("Message")
	private Message message;

	public Message getMessage() {
		return message;
	}

	public void setMessage(Message message) {
		this.message = message;
	}
	
}
  1. Message节点实体对象
package com.xml.parse.entity;

import com.thoughtworks.xstream.annotations.XStreamAlias;
//映射"Message"节点
@XStreamAlias("Message")
public class Message {
	//映射"Head"节点
	@XStreamAlias("Head")
	private BaseHead head;
	//映射"Body"节点
	@XStreamAlias("Body")
	private BaseBody body;
	
	public BaseHead getHead() {
		return head;
	}
	public void setHead(BaseHead head) {
		this.head = head;
	}
	public BaseBody getBody() {
		return body;
	}
	public void setBody(BaseBody body) {
		this.body = body;
	}
	
}
  1. Head,Body的基础类,业务子类都要继承这两个类

Head

package com.xml.parse.entity;

public class BaseHead {

}

Body

package com.xml.parse.entity;

public class BaseBody {

}

创建业务实体类,用于保存实际的业务数据

以样例中的报文“caps.202.001.01”为例
Caps202Head类

package com.xml.parse.entity.caps202;

import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.xml.parse.entity.BaseHead;

/**
 * 继承基础类BaseHead
 * 
 *
 */
@XStreamAlias("Head")
public class Caps202Head extends BaseHead{
	//映射CorpNo节点
	//以下属性和节点一一对应
	@XStreamAlias("CorpNo")
	private String corpNo;
	
	@XStreamAlias("ResFlag")
	private String resFlag;
	
	@XStreamAlias("ErrorCode")
	private String errorCode;
	
	@XStreamAlias("ErrorMsg")
	private String errorMsg;

	public String getCorpNo() {
		return corpNo;
	}

	public void setCorpNo(String corpNo) {
		this.corpNo = corpNo;
	}

	public String getResFlag() {
		return resFlag;
	}

	public void setResFlag(String resFlag) {
		this.resFlag = resFlag;
	}

	public String getErrorCode() {
		return errorCode;
	}

	public void setErrorCode(String errorCode) {
		this.errorCode = errorCode;
	}

	public String getErrorMsg() {
		return errorMsg;
	}

	public void setErrorMsg(String errorMsg) {
		this.errorMsg = errorMsg;
	}
}

Caps202Body类

package com.xml.parse.entity.caps202;

import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.xml.parse.entity.BaseBody;

@XStreamAlias("Body")
public class Caps202Body extends BaseBody{
	//以下属性和节点一一对应
	@XStreamAlias("ReturnTime")
	private String returnTime;
	
	@XStreamAlias("SysSeqNo")
	private String sysSeqNo;
	
	@XStreamAlias("SerialNum")
	private String serialNum;
	
	@XStreamAlias("RetCode")
	private String retCode;
	
	@XStreamAlias("RetMsg")
	private String retMsg;
	
	@XStreamAlias("Remark")
	private String remark;
	
	@XStreamAlias("Use")
	private String use;
	
	@XStreamAlias("BtchNb")
	private String btchNb;
	
	public String getReturnTime() {
		return returnTime;
	}
	public void setReturnTime(String returnTime) {
		this.returnTime = returnTime;
	}
	public String getSysSeqNo() {
		return sysSeqNo;
	}
	public void setSysSeqNo(String sysSeqNo) {
		this.sysSeqNo = sysSeqNo;
	}
	public String getSerialNum() {
		return serialNum;
	}
	public void setSerialNum(String serialNum) {
		this.serialNum = serialNum;
	}
	public String getRetCode() {
		return retCode;
	}
	public void setRetCode(String retCode) {
		this.retCode = retCode;
	}
	public String getRetMsg() {
		return retMsg;
	}
	public void setRetMsg(String retMsg) {
		this.retMsg = retMsg;
	}
	public String getRemark() {
		return remark;
	}
	public void setRemark(String remark) {
		this.remark = remark;
	}
	public String getUse() {
		return use;
	}
	public void setUse(String use) {
		this.use = use;
	}
	public String getBtchNb() {
		return btchNb;
	}
	public void setBtchNb(String btchNb) {
		this.btchNb = btchNb;
	}
	
}

解析caps.202.001.01.xml报文

  前面的准备工作完成,我们来解析一个xml报文,试一试
测试代码

package com.xml.parse;

import java.io.IOException;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.xml.parse.entity.Document;
import com.xml.parse.entity.caps202.Caps202Body;
import com.xml.parse.entity.caps202.Caps202Head;
import com.xml.parse.utils.XStreamXmlUtil;
import com.xml.utils.TxtFileReader;

public class Test {

	public static void main(String[] args) throws IOException {
		//从文件中读取xml字符串
		TxtFileReader tfr = new TxtFileReader("./file/caps.202.001.01.xml");
		String text = tfr.readAll();
		//System.out.println("xml text: \n" + text);
		
		//解析caps.202.001.01.xml,传入是对应的Caps202Head,和 Caps202Body
		//一行代码就搞定了
		Document doc = XStreamXmlUtil.xmlToBean(text, Document.class, Caps202Head.class, Caps202Body.class);
		
		//使用json格式展示解析后的结果,方便观察不是必须的
		System.out.println(JSON.toJSONString(doc,SerializerFeature.PrettyFormat, SerializerFeature.WriteMapNullValue, 
	            SerializerFeature.WriteDateUseDateFormat));
	}
}

解析结果:
在这里插入图片描述

再解析一个新报文,看看实际效果

  样例caps.204.001.01.xml

<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:cbcc:std:caps:2020:tech:xsd:caps.202.001.01" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
	<Message>
		<Head>
			<CorpNo>3310000001</CorpNo>
			<ResFlag>SUCC</ResFlag>
			<ErrorCode>I000</ErrorCode>
			<ErrorMsg>平台检验成功</ErrorMsg>
		</Head>
		<Body>
			<ReturnTime>2020-10-30T09:26:51</ReturnTime>
			<SysSeqNo>2020103050006167</SysSeqNo>
			<SerialNum>2020103000000001</SerialNum>
			<RetCode>111111</RetCode>
			<RetMsg>业务处理中</RetMsg>
			<Remark>专项科研经费</Remark>
			<Use>服务费202010</Use>
			<BtchNb>50006167</BtchNb>
		</Body>
	</Message>
</Document>

建对应实体类Caps204Body和Caps204Head,仿照Caps202建就可以了

package com.xml.parse.entity.caps204;

import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.xml.parse.entity.BaseHead;

@XStreamAlias("Head")
public class Caps204Head extends BaseHead{

	@XStreamAlias("CorpNo")
	private String corpNo;
	
	@XStreamAlias("ResFlag")
	private String resFlag;
	
	@XStreamAlias("ErrorCode")
	private String errorCode;
	
	@XStreamAlias("ErrorMsg")
	private String errorMsg;

	public String getCorpNo() {
		return corpNo;
	}

	public void setCorpNo(String corpNo) {
		this.corpNo = corpNo;
	}

	public String getResFlag() {
		return resFlag;
	}

	public void setResFlag(String resFlag) {
		this.resFlag = resFlag;
	}

	public String getErrorCode() {
		return errorCode;
	}

	public void setErrorCode(String errorCode) {
		this.errorCode = errorCode;
	}

	public String getErrorMsg() {
		return errorMsg;
	}

	public void setErrorMsg(String errorMsg) {
		this.errorMsg = errorMsg;
	}
}

package com.xml.parse.entity.caps204;

import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.xml.parse.entity.BaseBody;

@XStreamAlias("Body")
public class Caps204Body extends BaseBody{

	@XStreamAlias("ReturnTime")
	private String returnTime;
	
	@XStreamAlias("SysSeqNo")
	private String sysSeqNo;
	
	@XStreamAlias("SerialNum")
	private String serialNum;
	
	@XStreamAlias("RetCode")
	private String retCode;
	
	@XStreamAlias("RetMsg")
	private String retMsg;
	
	@XStreamAlias("Remark")
	private String remark;
	
	@XStreamAlias("Use")
	private String use;
	
	@XStreamAlias("BtchNb")
	private String btchNb;
	
	public String getReturnTime() {
		return returnTime;
	}
	public void setReturnTime(String returnTime) {
		this.returnTime = returnTime;
	}
	public String getSysSeqNo() {
		return sysSeqNo;
	}
	public void setSysSeqNo(String sysSeqNo) {
		this.sysSeqNo = sysSeqNo;
	}
	public String getSerialNum() {
		return serialNum;
	}
	public void setSerialNum(String serialNum) {
		this.serialNum = serialNum;
	}
	public String getRetCode() {
		return retCode;
	}
	public void setRetCode(String retCode) {
		this.retCode = retCode;
	}
	public String getRetMsg() {
		return retMsg;
	}
	public void setRetMsg(String retMsg) {
		this.retMsg = retMsg;
	}
	public String getRemark() {
		return remark;
	}
	public void setRemark(String remark) {
		this.remark = remark;
	}
	public String getUse() {
		return use;
	}
	public void setUse(String use) {
		this.use = use;
	}
	public String getBtchNb() {
		return btchNb;
	}
	public void setBtchNb(String btchNb) {
		this.btchNb = btchNb;
	}
	
}

测试解析代码

package com.xml.parse;

import java.io.IOException;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.xml.parse.entity.Document;
import com.xml.parse.entity.caps204.Caps204Body;
import com.xml.parse.entity.caps204.Caps204Head;
import com.xml.parse.utils.XStreamXmlUtil;
import com.xml.utils.TxtFileReader;

public class Test {

	public static void main(String[] args) throws IOException {
		//从文件中读取xml字符串
		TxtFileReader tfr = new TxtFileReader("./file/caps.202.001.01.xml");
		String text = tfr.readAll();
		//System.out.println("xml text: \n" + text);
		
//		//解析xml
//		Document doc = XStreamXmlUtil.xmlToBean(text, Document.class, Caps202Head.class, Caps202Body.class);
		
		//这里传Caps204Head和Caps204Body 即可
		Document doc = XStreamXmlUtil.xmlToBean(text, Document.class, Caps204Head.class, Caps204Body.class);
		
		//使用json格式,展示解析后的结构
		System.out.println(JSON.toJSONString(doc,SerializerFeature.PrettyFormat, SerializerFeature.WriteMapNullValue, 
	            SerializerFeature.WriteDateUseDateFormat));
	}
}

解析结果
在这里插入图片描述

总结一下

  当我们把准备工作做完,解析新的xml就很简单了。针对不同的Head,Body创建不同子类。在解析时传入相应的业务子类,就可以完成解析非常方便。要注意一点,实际使用时,业务子类要强制转换一下,才可以获取到业务数据。

补充读文件的类

package com.xml.utils;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

/**
 * 读文本文件
 * @author jiyh
 * @create 2012-03-21 13:45
 */
public class TxtFileReader {

	private File file;
	private FileInputStream fis;
	private InputStreamReader isr;
	private BufferedReader br;
	
	public TxtFileReader(){
		
	}
	
	/**
	 * 使用从文件信息中获得字符集, 构造读文件对象
	 * @param fullName
	 * @throws IOException
	 */
	public TxtFileReader(String fullName) throws IOException{
		this(new File(fullName));
	}
	
	/**
	 * 使用指定字符集, 构造读文件对象
	 * @param fullName
	 * @param charset
	 * @throws IOException
	 */
	public TxtFileReader(String fullName, String charset) throws IOException{
		this( new File(fullName), charset);
	}
	
	/**
	 * 使用从文件信息中获得字符集, 构造读文件对象
	 * @param file
	 * @throws IOException
	 */
	public TxtFileReader(File file) throws IOException{
		this.file = file;
		this.fis = new FileInputStream(file);
		this.isr = new InputStreamReader(fis);
		this.br = new BufferedReader(isr);
	}
	
	/**
	 * 使用指定字符集, 构造读文件对象
	 * @param fullName
	 * @param charset
	 * @throws IOException
	 */
	public TxtFileReader(File file, String charset) throws IOException{
		this.file = file;
		this.fis = new FileInputStream(file);
		if(charset == null || charset.equals("")){
			this.isr = new InputStreamReader(fis);
		}else {
			this.isr = new InputStreamReader(fis, charset);
		}
		
//		this.isr = new InputStreamReader(fis, charset);
		this.br = new BufferedReader(isr);
	}
	
	/**
	 * 读一行数据
	 * @return
	 * @throws IOException
	 */
	public String readLine() throws IOException{
		return this.br.readLine();
	}
	
	/**
	 * 按行读取数据,并把数据保存到集合中
	 * 以"#"开头的行跳过
	 * @return
	 * @throws IOException
	 */
	public List<String> readLineList() throws IOException{
		List<String> lineList = new ArrayList<String>();
		
		String line = null;
		while ((line = this.readLine() ) != null) {
			line = line.trim();
			
			if (line.startsWith("#")) {
				continue;
			}
			
			lineList.add(line);
		}
		
		this.close();
		return lineList;
	}
	
	/**
	 * 读取说有文本
	 * 以"#"开头的行跳过
	 * @return
	 * @throws IOException
	 */
	public String readAll() throws IOException{
		List<String> lineList = new ArrayList<String>();
		
		StringBuffer text = new StringBuffer();
		String line = null;
		
		String br =System.getProperty( "line.separator"); 
		while ((line = this.readLine() ) != null) {
//			line = line.trim();
			
			if (line.contains("#")) {
				continue;
			}
			
//			lineList.add(line);
			text.append(line).append(br);
		}
		
		this.close();
		return text.toString();
	}
	
	/**
	 * 返回当前读文件的流对象
	 * @return
	 */
	public BufferedReader getBr() {
		return br;
	}

	/**
	 * 关闭文件流
	 * @throws IOException
	 */
	public void close(){
		if (this.br != null) {
			try {
				this.br.close();
			} catch (IOException e) {
			}
		}
		if (this.isr != null) {
			try {
				this.isr.close();
			} catch (IOException e) {
			}
		}
		if (this.fis != null) {
			try {
				this.fis.close();
			} catch (IOException e) {
			}
		}
		
		
	}
	
	/**
	 * 删除当前文件
	 */
	public void delete(){
		if(this.file.exists() && this.file.isFile()){
			this.file.delete();
		}
	}
	
}

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值