使用xstream处理xml报文,包含xml与bean互化

介绍几种形式的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" ?>会有差异,所以要注意乱码。

至此,完毕!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值