介绍几种形式的xml报文对应的对象。
必要的依赖:
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.11</version>
</dependency>
<dependency>
<groupId>org.apache.xmlbeans</groupId>
<artifactId>xmlbeans</artifactId>
<version>2.3.0</version>
</dependency>
可选依赖,示例中用到,但非必要:
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
<optional>true</optional>
</dependency>
1、有属性与子元素
xml报文如下:
<?xml version="1.0" encoding="UTF-8" ?>
<root>
<common>
<demo_id>330100A088</demo_id>
<type>request</type>
</common>
<id_validate operation="request">
<sequence>00787278</sequence>
</id_validate>
</root>
对象如下(由外到内):
Root块:
import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Builder;
import lombok.Data;
/**
* XML报文统一格式类
*/
@XStreamAlias("root")
@Data
@Builder
public class Root {
/**
* 通用信息部分
*/
@XStreamAlias("common")
private Common common ;
@XStreamAlias("id_validate")
private Validate id_validate;
}
Common块:
import lombok.Builder;
import lombok.Data;
@Data
@Builder
public class Common {
public Common(String demo_id, String type) {
this.demo_id = demo_id;
this.type = type;
}
/**
* demoId
*/
private String demo_id;
/**
* 请求类型
*/
private String type;
}
id_validate块:
import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamAsAttribute;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@XStreamAlias("id_validate")
public class Validate {
/**
* 属性部分
*/
@XStreamAsAttribute //把字段节点设置成属性:@XStreamAsAttribute
@XStreamAlias("operation") //重命名注解:@XStreamAlias() 这些命名都需要和解析的xml的属性名
private String operation;
/**
* 子元素部分
*/
private String sequence;
}
使用方式:
工具类:
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class XsteamUtil {
/**
* xml转实体
* @param clazz
* @param xml
* @return
*/
public static Object xmltoBean(Class<?> clazz, String xml) {
// DomDriver
XStream xstream = new XStream(new DomDriver());
//应用传过来的类的注解
xstream.processAnnotations(clazz);
//自动检测注解
xstream.autodetectAnnotations(true);
// xstream 的安全框架没有初始化,xstream 容易受攻击,此处设置默认安全防护,同时设置允许的类
XStream.setupDefaultSecurity(xstream);
//使用了默认安全框架,此处为必须项
xstream.allowTypeHierarchy(Root.class);
// 两个类的相等性取决于类名和加载器,XStream必须使用不同的类加载器,防止ClassCastException的快速解决方案是设置当前线程使用的相同类加载器
xstream.setClassLoader(Thread.currentThread().getContextClassLoader());
// 未定义字段不接收
xstream.ignoreUnknownElements();
Object xmlObject= xstream.fromXML(xml);
return xmlObject;
}
}
测试类:
public class Test {
final static String xmlOne = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" +
"<root>\n" +
" <common>\n" +
" <demo_id>330100A088</demo_id>\n" +
" <type>request</type>\n" +
" </common>\n" +
" <id_validate operation=\"request\">\n" +
" <sequence>00787278</sequence>\n" +
" </id_validate>\n" +
"</root>";
public static void main(String[] args) {
Root obj = (Root)XsteamUtil.xmltoBean(Root.class,xmlOne);
System.out.println(obj.toString());
System.out.println(obj.getCommon().getType());
System.out.println(obj.getId_validate().getOperation());
System.out.println(obj.getId_validate().getSequence());
}
}
2、有属性、子元素、属性值,子元素值,集合
xml报文如下:
<?xml version="1.0" encoding="GB2312" ?>
<root>
<common>
<demo_id>330100A001</demo_id>
<type>test</type>
</common>
<data operation="test">
<sequence>105</sequence>
<parser>yes</parser>
<time>20210913100030</time>
<meter id="001" addr="000000000001" tp="01" name="支路1">
<function id="01" sml="Ep+" sid="1" ut="KWh" pm="正向有功" coding="02000" error="2">1.00000</function>
<function id="02" sml="Ep+" sid="1" ut="KWh" pm="反向有功" coding="03000" error="2">2.00000</function>
</meter>
<meter id="002" addr="000000000001" tp="01" name="支路2">
<function id="01" sml="Ep+" sid="1" ut="KWh" pm="正向有功" coding="02000" error="2">-1.00000</function>
</meter>
</data>
</root>
对象如下(由外到内):
Root块:
import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Builder;
import lombok.Data;
/**
* XML报文统一格式类
*/
@XStreamAlias("root")
@Data
@Builder
public class Root {
/**
* 通用信息部分
*/
@XStreamAlias("common")
private Common common ;
@XStreamAlias("id_validate")
private Validate id_validate;
@XStreamAlias("data")
private DataPacket dataPacket;
}
Common块:
import lombok.Builder;
import lombok.Data;
@Data
@Builder
public class Common {
public Common(String demo_id, String type) {
this.demo_id = demo_id;
this.type = type;
}
/**
* demoId
*/
private String demo_id;
/**
* 请求类型
*/
private String type;
}
id_validate块:
import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamAsAttribute;
import com.thoughtworks.xstream.annotations.XStreamImplicit;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@XStreamAlias("data")
public class DataPacket {
/**
* 属性部分
*/
@XStreamAsAttribute //把字段节点设置成属性:@XStreamAsAttribute
@XStreamAlias("operation") //重命名注解:@XStreamAlias() 这些命名都需要和解析的xml的属性名
private String operation;
/**
* 接受子元素部分
*/
private String sequence;
private String parser;
private String time;
@XStreamImplicit(itemFieldName="meter")
private List<Meter> meter;
}
meter 块:
import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamAsAttribute;
import com.thoughtworks.xstream.annotations.XStreamImplicit;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@XStreamAlias("meter")
public class Meter {
/**
* 属性部分
*/
@XStreamAsAttribute //把字段节点设置成属性:@XStreamAsAttribute
@XStreamAlias("id") //重命名注解:@XStreamAlias() 这些命名都需要和解析的xml的属性名
private String id;
@XStreamAsAttribute //把字段节点设置成属性:@XStreamAsAttribute
@XStreamAlias("addr") //重命名注解:@XStreamAlias() 这些命名都需要和解析的xml的属性名
private String addr;
@XStreamAsAttribute //把字段节点设置成属性:@XStreamAsAttribute
@XStreamAlias("tp") //重命名注解:@XStreamAlias() 这些命名都需要和解析的xml的属性名
private String tp;
@XStreamAsAttribute //把字段节点设置成属性:@XStreamAsAttribute
@XStreamAlias("name") //重命名注解:@XStreamAlias() 这些命名都需要和解析的xml的属性名
private String name;
/**
* 接受子元素部分
*/
@XStreamImplicit(itemFieldName="function")
private List<Function> function;
}
function块:
import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamAsAttribute;
import com.thoughtworks.xstream.annotations.XStreamConverter;
import com.thoughtworks.xstream.converters.extended.ToAttributedValueConverter;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@XStreamAlias("function")
@XStreamConverter(value = ToAttributedValueConverter.class, strings = { "value" }) //指定class及Field的converter(转换方式)
public class Function {
/**
* 属性部分
*/
@XStreamAsAttribute //把字段节点设置成属性:@XStreamAsAttribute
@XStreamAlias("id") //重命名注解:@XStreamAlias() 这些命名都需要和解析的xml的属性名
private String id;
@XStreamAsAttribute //把字段节点设置成属性:@XStreamAsAttribute
@XStreamAlias("coding") //重命名注解:@XStreamAlias() 这些命名都需要和解析的xml的属性名
private String coding;
@XStreamAsAttribute //把字段节点设置成属性:@XStreamAsAttribute
@XStreamAlias("error") //重命名注解:@XStreamAlias() 这些命名都需要和解析的xml的属性名
private String error;
private Double value;
}
使用方式(工具类放于最下放):
工具类:
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class XsteamUtil {
/**
* xml转实体
* @param clazz
* @param xml
* @return
*/
public static Object xmltoBean(Class<?> clazz, String xml) {
// DomDriver
XStream xstream = new XStream(new DomDriver());
//应用传过来的类的注解
xstream.processAnnotations(clazz);
//自动检测注解
xstream.autodetectAnnotations(true);
// xstream 的安全框架没有初始化,xstream 容易受攻击,此处设置默认安全防护,同时设置允许的类
XStream.setupDefaultSecurity(xstream);
//使用了默认安全框架,此处为必须项
xstream.allowTypeHierarchy(Root.class);
// 两个类的相等性取决于类名和加载器,XStream必须使用不同的类加载器,防止ClassCastException的快速解决方案是设置当前线程使用的相同类加载器
xstream.setClassLoader(Thread.currentThread().getContextClassLoader());
// 未定义字段不接收
xstream.ignoreUnknownElements();
Object xmlObject= xstream.fromXML(xml);
return xmlObject;
}
}
测试类:
public class Test {
final static String xmlTwo = "<?xml version=\"1.0\" encoding=\"GB2312\" ?>\n" +
"<root>\n" +
" <common>\n" +
" <demo_id>330100A001</demo_id>\n" +
" <type>test</type>\n" +
" </common>\n" +
" <data operation=\"test\">\n" +
" <sequence>105</sequence>\n" +
" <parser>yes</parser>\n" +
" <time>20210913100030</time>\n" +
" <meter id=\"001\" addr=\"000000000001\" tp=\"01\" name=\"支路1\">\n" +
" <function id=\"01\" sml=\"Ep+\" sid=\"1\" ut=\"KWh\" pm=\"正向有功\" coding=\"02000\" error=\"2\">1.00000</function>\n" +
" <function id=\"02\" sml=\"Ep+\" sid=\"1\" ut=\"KWh\" pm=\"反向有功\" coding=\"03000\" error=\"2\">2.00000</function>\n" +
" </meter>\n" +
" <meter id=\"002\" addr=\"000000000001\" tp=\"01\" name=\"支路2\">\n" +
" <function id=\"01\" sml=\"Ep+\" sid=\"1\" ut=\"KWh\" pm=\"正向有功\" coding=\"02000\" error=\"2\">-1.00000</function>\n" +
" </meter>\n" +
" </data>\n" +
"</root>";
public static void main(String[] args) {
Root obj = (Root)XsteamUtil.xmltoBean(Root.class,xmlTwo);
System.out.println(obj.toString());
System.out.println(obj.getCommon().getType());
System.out.println(obj.getDataPacket().getOperation());
System.out.println(obj.getDataPacket().getSequence());
List<Meter> m = obj.getDataPacket().getMeter();
System.out.println(m.get(0).getAddr());
List<Function> f = m.get(0).getFunction();
System.out.println(f.get(0).getValue());
System.out.println(f.get(0).getId());
}
}
3、集合子元素名称重复
xml报文如下:
<?xml version="1.0" encoding="GB2312" ?>
<root>
<common>
<demo_id>330100A001</demo_id>
<type>config</type>
</common>
<meterType_info>
<item id="1" memo="测试表"/>
<item id="2" memo="水表"/>
</meterType_info>
<sampleCode_info>
<item id="1" name="正向有功" symbol="Ep+" unit="KWh" code="1" />
<item id="2" name="有功功率" symbol="P" unit="KW" code="2" />
</sampleCode_info>
</root>
对象如下(由外到内):
Root块:
import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Builder;
import lombok.Data;
/**
* XML报文统一格式类
*/
@XStreamAlias("root")
@Data
@Builder
public class Root {
/**
* 通用信息部分
*/
@XStreamAlias("common")
private Common common ;
@XStreamAlias("id_validate")
private Validate id_validate;
}
Common块:
import lombok.Builder;
import lombok.Data;
@Data
@Builder
public class Common {
public Common(String demo_id, String type) {
this.demo_id = demo_id;
this.type = type;
}
/**
* demoId
*/
private String demo_id;
/**
* 请求类型
*/
private String type;
}
meterType_info块:
import com.thoughtworks.xstream.annotations.XStreamImplicit;
import lombok.Builder;
import lombok.Data;
import java.util.List;
@Data
@Builder
public class MeterTypeInfo {
/**
* 仪表类别定义说明
*/
@XStreamImplicit(itemFieldName="item")
private List<MeterItem> item ;
}
meterType_info下item 块:
import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamAsAttribute;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@XStreamAlias("item")
public class MeterItem {
/**
* 属性部分
*/
@XStreamAsAttribute //把字段节点设置成属性:@XStreamAsAttribute
@XStreamAlias("id") //重命名注解:@XStreamAlias() 这些命名都需要和解析的xml的属性名
private String id;
@XStreamAsAttribute //把字段节点设置成属性:@XStreamAsAttribute
@XStreamAlias("memo") //重命名注解:@XStreamAlias() 这些命名都需要和解析的xml的属性名
private String memo;
}
sampleCode_info块:
import com.thoughtworks.xstream.annotations.XStreamImplicit;
import lombok.Builder;
import lombok.Data;
import java.util.List;
@Data
@Builder
public class SampleCodeInfo {
/**
* 仪表类别定义说明
*/
@XStreamImplicit(itemFieldName="item")
private List<SampleCodeItem> item ;
}
sampleCode_info下item块:
import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamAsAttribute;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@XStreamAlias("item")
public class SampleCodeItem {
/**
* 属性部分
*/
@XStreamAsAttribute //把字段节点设置成属性:@XStreamAsAttribute
@XStreamAlias("id") //重命名注解:@XStreamAlias() 这些命名都需要和解析的xml的属性名
private Integer id;
@XStreamAsAttribute //把字段节点设置成属性:@XStreamAsAttribute
@XStreamAlias("name") //重命名注解:@XStreamAlias() 这些命名都需要和解析的xml的属性名
private String name;
@XStreamAsAttribute //把字段节点设置成属性:@XStreamAsAttribute
@XStreamAlias("symbol") //重命名注解:@XStreamAlias() 这些命名都需要和解析的xml的属性名
private String symbol;
@XStreamAsAttribute //把字段节点设置成属性:@XStreamAsAttribute
@XStreamAlias("unit") //重命名注解:@XStreamAlias() 这些命名都需要和解析的xml的属性名
private String unit;
@XStreamAsAttribute //把字段节点设置成属性:@XStreamAsAttribute
@XStreamAlias("code") //重命名注解:@XStreamAlias() 这些命名都需要和解析的xml的属性名
private String code;
}
使用方式:
工具类:
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class XsteamUtil {
/**
* xml转实体
* @param clazz
* @param xml
* @return
*/
public static Object xmltoBean(Class<?> clazz, String xml) {
// DomDriver
XStream xstream = new XStream(new DomDriver());
//应用传过来的类的注解
xstream.processAnnotations(clazz);
//自动检测注解
xstream.autodetectAnnotations(true);
// xstream 的安全框架没有初始化,xstream 容易受攻击,此处设置默认安全防护,同时设置允许的类
XStream.setupDefaultSecurity(xstream);
//使用了默认安全框架,此处为必须项
xstream.allowTypeHierarchy(Root.class);
//元素集合名称重复时使用可区分重复元素
xstream.addImplicitCollection(MeterTypeInfo.class, "item", MeterItem.class);
xstream.addImplicitCollection(SampleCodeInfo.class, "item",SampleCodeItem.class);
// 两个类的相等性取决于类名和加载器,XStream必须使用不同的类加载器,防止ClassCastException的快速解决方案是设置当前线程使用的相同类加载器
xstream.setClassLoader(Thread.currentThread().getContextClassLoader());
// 未定义字段不接收
xstream.ignoreUnknownElements();
Object xmlObject= xstream.fromXML(xml);
return xmlObject;
}
}
测试类:
public class Test {
final static String xmlThree = "<?xml version=\"1.0\" encoding=\"GB2312\" ?>\n" +
"<root>\n" +
" <common>\n" +
" <demo_id>330100A001</demo_id>\n" +
" <type>config</type>\n" +
" </common>\n" +
" <meterType_info>\n" +
" <item id=\"1\" memo=\"测试表\"/>\n" +
" <item id=\"2\" memo=\"水表\"/>\n" +
" </meterType_info>\n" +
" <sampleCode_info>\n" +
" <item id=\"1\" name=\"正向有功\" symbol=\"Ep+\" unit=\"KWh\" code=\"1\" />\n" +
" <item id=\"2\" name=\"有功功率\" symbol=\"P\" unit=\"KW\" code=\"2\" />\n" +
" </sampleCode_info>\n" +
" </root>";
public static void main(String[] args) {
Root obj = (Root)XsteamUtil.xmltoBean(Root.class,xmlThree);
System.out.println(obj.toString());
System.out.println(obj.getCommon().getType());
System.out.println(obj.getMeterTypeInfo().getItem().get(0).getMemo());
System.out.println(obj.getSampleCodeInfo().getItem().get(0).getName());
}
}
bean转xml如下:
配置与xml转bean相同
工具类:
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;
import lombok.extern.slf4j.Slf4j;
import java.util.StringJoiner;
/**
* 实体转xml
* @param obj 对象
* @param hasHead 是否添加头
* @return
*/
public static String beantoXml(Object obj, Class<?> clazz,boolean hasHead) {
String head = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>";
// DomDriver
XStream xstream = new XStream(new DomDriver());
xstream.autodetectAnnotations(true);
xstream.processAnnotations(clazz);
// xstream 的安全框架没有初始化,xstream 容易受攻击,此处设置默认安全防护,同时设置允许的类
XStream.setupDefaultSecurity(xstream);
xstream.allowTypeHierarchy(Root.class);
xstream.setClassLoader(Thread.currentThread().getContextClassLoader());
// 未定义字段不接收
xstream.ignoreUnknownElements();
String xml = xstream.toXML(obj);
xml = hasHead ? buildHead(xml,head) : xml;
return underlineDoubleToOne(xml);
}
/**
* 添加xml信息头
* @param<?xml version="1.0" encoding="UTF-8" ?>
* @return
*/
public static String buildHead(String xml,String head){
StringJoiner stringJoiner = new StringJoiner("\n");
stringJoiner.add(head);
stringJoiner.add(xml);
return stringJoiner.toString();
}
/**
* XStream将java对象转换为xml时,对象字段中的下划线“_”,转换后变成了两个的解决办法
* @return
*/
public static String underlineDoubleToOne(String xml){
xml = xml.replace("__", "_");
return xml
}
测试类:
public class Test {
final static String xmlOne = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" +
"<root>\n" +
" <common>\n" +
" <demo_id>330100A088</demo_id>\n" +
" <type>request</type>\n" +
" </common>\n" +
" <id_validate operation=\"request\">\n" +
" <sequence>00787278</sequence>\n" +
" </id_validate>\n" +
"</root>";
public static void main(String[] args) {
Root obj = (Root)XsteamUtil.xmltoBean(Root.class,xmlOne);
System.out.println(obj.toString());
System.out.println(obj.getCommon().getType());
System.out.println(obj.getId_validate().getOperation());
System.out.println(obj.getId_validate().getSequence());
//bean转xml
String xmlStr = XsteamUtil.beantoXml(obj,Root.class,true);
System.out.println(xmlStr);
}
}
输出展示:
ps:由于xml的头编码形式 <?xml version="1.0" encoding="UTF-8" ?>,<?xml version="1.0" encoding="GB2312" ?>会有差异,所以要注意乱码。
至此,完毕!