Java解析XML的类库很多,本文记录用XStream库对XML的处理
背景
实际开发中,应用报文的格式一般都是JSON和XML;JSON大家都很熟悉(优秀类库:GSON/FastJson/Jackson),但对XML的解析可能并不熟悉,这主要是因为XML一般用于特定的领域:如金融和支付行业,想要和银联及网联对接,XML是少不了的
XStream的使用
XStream是解析XML的一款轻量级类库,简单快捷。下面以网联的交易查询接口为例,记录XML的序列化和反序列化的相关使用方法
报文结构如下:
-
创建对应的类(具体类信息添加在文末)
-
创建XStream工具类
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class XmlUtil {
* @param obj 要序列化的对象
* @return 序列化后的xml字符串
public static String toXml(Object obj) {
XStream xStream = new XStream();
xStream.autodetectAnnotations(true);
try {
return xStream.toXML(obj);
} catch (Exception e) {
throw new RuntimeException("Serialization object to xml error: " + e.getMessage());
* @param is XML字符串的字节流
* @param targetClazz xml反序列化的目标类
* @param <T>
* @return 目标类对象
public static <T> T fromXml(InputStream is, Class<T> targetClazz) {
XStream xStream = new XStream();
XStream.setupDefaultSecurity(xStream);
xStream.allowTypes(new Class[] {TransStatusInquiryResponse.class});
xStream.processAnnotations(targetClazz);
try {
return (T) xStream.fromXML(is);
} catch (Exception e) {
throw new RuntimeException("Deserialization from xml to object error: " + e.getMessage());
- 测试序列化和反序列化的结果
public class Test {
public static final String XML_NS = "name_space_string";
public static final String ISO_DATE_TIME = "yyyy-MM-dd'T'HH:mm:ss";
public static final String responseXml = "<root xmlns=\"name_space_string\">\n" +
" <MsgHeader>\n" +
" <MsgTp>epcc.302.001.01</MsgTp>\n" +
" <IssrId>ICBC00001</IssrId>\n" +
" <Drctn>21</Drctn>\n" +
" <SignSN>87654321</SignSN>\n" +
" <NcrptnSN></NcrptnSN>\n" +
" <DgtlEnvlp></DgtlEnvlp>\n" +
" </MsgHeader>\n" +
" <MsgBody>\n" +
" <SysRtnInf>\n" +
" <SysRtnCd>00000000</SysRtnCd>\n" +
" <SysRtnDesc></SysRtnDesc>\n" +
" <SysRtnTm>2020-11-29T15:41:15</SysRtnTm>\n" +
" </SysRtnInf>\n" +
" <BizInf>\n" +
" <RPFlg>foo</RPFlg>\n" +
" <OriSysRtnCd>foo</OriSysRtnCd>\n" +
" <OriSysRtnDesc>foo</OriSysRtnDesc>\n" +
" <OriBizstsCd></OriBizstsCd>\n" +
" <OriBizStsDesc></OriBizStsDesc>\n" +
" <OriTrxctgy>0115</OriTrxctgy>\n" +
" <OriTrxId>20201128888888888888888800022</OriTrxId>\n" +
" <OriTrxStatus>foo</OriTrxStatus>\n" +
" <DbtrBankId>foo</DbtrBankId>\n" +
" <CdtrBankId>foo</CdtrBankId>\n" +
" <OriTrxAmt>foo</OriTrxAmt>\n" +
" <OriBatchId>foo</OriBatchId>\n" +
" <OriSgnNo>foo</OriSgnNo>\n" +
" <PyerAcctTp>foo</PyerAcctTp>\n" +
" <PyerAcctId>foo</PyerAcctId>\n" +
" <PyerAcctNm>foo</PyerAcctNm>\n" +
" <AcctshrtId>foo</AcctshrtId>\n" +
" <ResfdAcctshrtId>foo</ResfdAcctshrtId>\n" +
" </BizInf>\n" +
" </MsgBody>\n" +
"</root>";
public static void main(String[] args) {
String xmlStr = XmlUtil.toXml(buildRequestObj());
System.out.println(xmlStr);
System.out.println("--------------------------");
TransStatusInquiryResponse inquiryResponse = XmlUtil.fromXml(new ByteArrayInputStream(responseXml.getBytes(StandardCharsets.UTF_8)), TransStatusInquiryResponse.class);
System.out.println(inquiryResponse.toString());
private static TransStatusInquiryRequest buildRequestObj() {
TransStatusInquiryRequest inquiryRequest = new TransStatusInquiryRequest();
inquiryRequest.setXmlns(XML_NS);
MsgRequestHeader requestHeader = new MsgRequestHeader();
requestHeader.setSndDt(DateTimeFormatter.ofPattern(ISO_DATE_TIME).format(LocalDateTime.now()));
requestHeader.setMsgTp("epcc.301.001.01");
requestHeader.setIssrId("ICBC00001");
requestHeader.setDrctn("11");
requestHeader.setSignSn("12345678");
requestHeader.setNcrptnSn("");
requestHeader.setDgtlEnvlp("");
inquiryRequest.setMsgRequestHeader(requestHeader);
MsgRequestBody requestBody = new MsgRequestBody();
requestBody.setInstgId("12345678901234");
requestBody.setRPFlg("2");
OriginTrxInfo originTrxInfo = new OriginTrxInfo();
originTrxInfo.setOriTrxCtgy("0115");
originTrxInfo.setOriTrxId("20201128888888888888888800022");
originTrxInfo.setOriTrxDtTm(DateTimeFormatter.ofPattern(ISO_DATE_TIME).format(LocalDateTime.now()));
originTrxInfo.setOriAcctTp("00");
originTrxInfo.setOrisgnNo("");
requestBody.setOriginTrxInfo(originTrxInfo);
inquiryRequest.setMsgRequestBody(requestBody);
return inquiryRequest;
结果如下:
序列化,组装交易查询的请求报文:
<root xmlns="name_space_string">
<MsgHeader>
<SndDt>2020-11-29T15:46:55</SndDt>
<MsgTp>epcc.301.001.01</MsgTp>
<IssrId>ICBC00001</IssrId>
<Drctn>11</Drctn>
<SignSN>12345678</SignSN>
<NcrptnSN></NcrptnSN>
<DgtlEnvlp></DgtlEnvlp>
</MsgHeader>
<MsgBody>
<InstgId>12345678901234</InstgId>
<RPFlg>2</RPFlg>
<OriTrxInf>
<OriTrxCtgy>0115</OriTrxCtgy>
<OriTrxId>20201128888888888888888800022</OriTrxId>
<OriTrxDtTm>2020-11-29T15:46:55</OriTrxDtTm>
<OriAcctTp>00</OriAcctTp>
<OrisgnNo></OrisgnNo>
</OriTrxInf>
</MsgBody>
</root>
--------------------------
反序列化响应报文,结果如下:
TransStatusInquiryResponse(xmlns=name_space_string, msgResponseHeader=MsgResponseHeader(sndDt=null, msgTp=epcc.302.001.01, issrId=ICBC00001, drctn=21, signSn=87654321, ncrptnSn=, dgtlEnvlp=), msgResponseBody=MsgResponseBody(sysRtnInf=SysRtnInf(sysRtnCd=00000000, sysRtnDesc=, sysRtnTm=2020-11-29T15:41:15), bizInf=BizInf(rPFlg=foo, oriSysRtnCd=foo, oriSysRtnDesc=foo, oriBizstsCd=, oriBizStsDesc=, oriTrxctgy=0115, oriTrxId=20201128888888888888888800022, oriTrxStatus=foo, dbtrBankId=foo, cdtrBankId=foo, oriTrxAmt=foo, oriBatchId=foo, oriSgnNo=foo, pyerAcctTp=foo, pyerAcctId=foo, pyerAcctNm=foo, acctshrtId=foo, resfdAcctshrtId=foo)))
请求报文相关的类信息如下:
@Getter
@Setter
@ToString
@XStreamAlias("root")
public class TransStatusInquiryRequest {
@XStreamAlias("xmlns")
@XStreamAsAttribute
private String xmlns;
@XStreamAlias("MsgHeader")
private MsgRequestHeader msgRequestHeader;
@XStreamAlias("MsgBody")
private MsgRequestBody msgRequestBody;
@Getter
@Setter
@ToString
@XStreamAlias("MsgHeader")
public class MsgRequestHeader {
@XStreamAlias("SndDt")
private String sndDt;
@XStreamAlias("MsgTp")
private String msgTp;
@XStreamAlias("IssrId")
private String issrId;
@XStreamAlias("Drctn")
private String drctn;
@XStreamAlias("SignSN")
private String signSn;
@XStreamAlias("NcrptnSN")
private String ncrptnSn;
@XStreamAlias("DgtlEnvlp")
private String dgtlEnvlp;
@Getter
@Setter
@ToString
@XStreamAlias("MsgBody")
public class MsgRequestBody {
@XStreamAlias("InstgId")
private String instgId;
@XStreamAlias("RPFlg")
private String rPFlg;
@XStreamAlias("OriTrxInf")
private OriginTrxInfo originTrxInfo;
@Getter
@Setter
@ToString
@XStreamAlias("OriTrxInf")
public class OriginTrxInfo {
@XStreamAlias("OriTrxCtgy")
private String oriTrxCtgy;
@XStreamAlias("OriTrxId")
private String oriTrxId;
@XStreamAlias("OriTrxDtTm")
private String oriTrxDtTm;
@XStreamAlias("OriAcctTp")
private String oriAcctTp;
@XStreamAlias("OrisgnNo")
private String orisgnNo;
响应报文对应的类信息如下:
@Getter
@Setter
@ToString
@XStreamAlias("root")
public class TransStatusInquiryResponse {
@XStreamAlias("xmlns")
@XStreamAsAttribute
private String xmlns;
@XStreamAlias("MsgHeader")
private MsgResponseHeader msgResponseHeader;
@XStreamAlias("MsgBody")
private MsgResponseBody msgResponseBody;
@Getter
@Setter
@ToString
@XStreamAlias("MsgHeader")
public class MsgResponseHeader {
@XStreamAlias("SndDt")
private String sndDt;
@XStreamAlias("MsgTp")
private String msgTp;
@XStreamAlias("IssrId")
private String issrId;
@XStreamAlias("Drctn")
private String drctn;
@XStreamAlias("SignSN")
private String signSn;
@XStreamAlias("NcrptnSN")
private String ncrptnSn;
@XStreamAlias("DgtlEnvlp")
private String dgtlEnvlp;
@Getter
@Setter
@ToString
@XStreamAlias("MsgBody")
public class MsgResponseBody {
@XStreamAlias("SysRtnInf")
private SysRtnInf sysRtnInf;
@XStreamAlias("BizInf")
private BizInf bizInf;
@Getter
@Setter
@ToString
@XStreamAlias("SysRtnInf")
public class SysRtnInf {
@XStreamAlias("SysRtnCd")
private String sysRtnCd;
@XStreamAlias("SysRtnDesc")
private String sysRtnDesc;
@XStreamAlias("SysRtnTm")
private String sysRtnTm;
@Getter
@Setter
@ToString
@XStreamAlias("BizInf")
public class BizInf {
@XStreamAlias("RPFlg")
private String rPFlg;
@XStreamAlias("OriSysRtnCd")
private String oriSysRtnCd;
@XStreamAlias("OriSysRtnDesc")
private String oriSysRtnDesc;
@XStreamAlias("OriBizstsCd")
private String oriBizstsCd;
@XStreamAlias("OriBizStsDesc")
private String oriBizStsDesc;
@XStreamAlias("OriTrxctgy")
private String oriTrxctgy;
@XStreamAlias("OriTrxId")
private String oriTrxId;
@XStreamAlias("OriTrxStatus")
private String oriTrxStatus;
@XStreamAlias("DbtrBankId")
private String dbtrBankId;
@XStreamAlias("CdtrBankId")
private String cdtrBankId;
@XStreamAlias("OriTrxAmt")
private String oriTrxAmt;
@XStreamAlias("OriBatchId")
private String oriBatchId;
@XStreamAlias("OriSgnNo")
private String oriSgnNo;
@XStreamAlias("PyerAcctTp")
private String pyerAcctTp;
@XStreamAlias("PyerAcctId")
private String pyerAcctId;
@XStreamAlias("PyerAcctNm")
private String pyerAcctNm;
@XStreamAlias("AcctshrtId")
private String acctshrtId;
@XStreamAlias("ResfdAcctshrtId")
private String resfdAcctshrtId;
简单,流畅的API,但完全灵活
从java.io输入解析到org.w3c.dom.Document
将org.w3c.dom.Document序列化为任何java.io输出
通过XSLT和自定义过滤器支持将java.io,SAX,StAX,JAXB输入转换为它们中的任何一个
通过XPath查询org.w3c.dom.Document以获取String,Boolean,Number,org.w3c.dom.Element或Node,并使用Java 8 Streaming API
常见的序列化方式
一、Protocol Buffer
Protocol Buffers(也称protobuf)是Google公司设计的一种独立于开发语言,独立于平台的可扩展的结构化数据序列机制。通俗点来讲它跟xml和json是一类。是一种数据交互格式协议。
protocol buffer的使用还是相对简单点,唯一麻烦的就是多了一个预编译的过程,将.proto文件转换成.java文件。
jprotobuf
jprotobuf是百度针对Java程序开发一套简易类库,目的是简化Protocol Buffer类库的使用。
二、fastJson
fastjson 是由阿里巴巴开发的一个性能很好的Java 语言实现的 Json解析器和生成器。特点:速度快,测试表明fastjson具有极快的性能,超越任其他的java json parser。功能强大,完全支持java bean、集合、Map、日期、En
拳击手2java
此存储库包含与src/data/boxer目录中的xdrs.dtd文件对应的类层次结构。
它允许将带注释的 XML Boxer 输出快速反序列化为 Java 对象。
先决条件是 maven(用于解析)和构建和运行的(用于输出)。 修改属性文件并指定 CCG 解析器、Boxer 和模型的路径后,您可以从程序中调用 C&C 工具并自行处理输出(请参阅 )。
上周五看了GKCTF的babycat那题,接触了XMLDecoder的漏洞,看了几天还是没看太明白。。。太菜了呜呜。。所以这是第一篇,暂时分析到这里,前面的处理XML的流程没看明白,光写篇文章理一下后面的部分。等以后再来填坑了。
只是简单的记录自己的调试过程,非常失败,没搞太懂。
利用就是,写一个这样的xml:
<object class="java.lang.ProcessBuilder">
<array class="jav
Java中的XML序列化是将Java对象转换为XML格式的过程。XML序列化可以用于数据持久化、数据传输等场景。Java提供了多种方式来实现XML序列化,包括JAXB、XStream、Dom4j等。
JAXB是Java Architecture for XML Binding的缩写,是Java SE 6及以上版本中自带的一种XML数据绑定技术。JAXB通过注解或XML配置文件来描述Java类与XML之间的映射关系,从而实现Java对象到XML的序列化和反序列化。以下是一个使用JAXB进行XML序列化的示例代码:
```java
// 定义一个Java类
@XmlRootElement
public class Person {
private String name;
private int age;
private String address;
public String getName() {
return name;
public void setName(String name) {
this.name = name;
public int getAge() {
return age;
public void setAge(int age) {
this.age = age;
public String getAddress() {
return address;
public void setAddress(String address) {
this.address = address;
// 序列化Java对象到XML
public static void serializeToXml(Person person, String xmlFilePath) throws JAXBException {
JAXBContext context = JAXBContext.newInstance(Person.class);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(person, new File(xmlFilePath));
// 反序列化XML到Java对象
public static Person deserializeFromXml(String xmlFilePath) throws JAXBException {
JAXBContext context = JAXBContext.newInstance(Person.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
return (Person) unmarshaller.unmarshal(new File(xmlFilePath));
使用JAXB进行XML序列化需要注意以下几点:
1. Java类需要使用@XmlRootElement注解标注为根元素。
2. Java类的属性需要使用@XmlAttribute或@XmlElement注解标注为XML属性或元素。
3. 序列化时需要创建JAXBContext和Marshaller,反序列化时需要创建JAXBContext和Unmarshaller。
4. 序列化时可以设置Marshaller的属性,如是否格式化输出。
除了JAXB外,XStream和Dom4j也是常用的XML序列化工具。XStream是一款简单易用的XML序列化框架,通过注解或代码配置来完成Java类与XML之间的映射关系。Dom4j是一款基于Java的XML解析器和生成器,可以快速方便地操作XML文档。无论使用哪种工具,XML序列化都是Java开发中常用的技术之一。