使用XStream注解处理复杂xml的属性及数据集合(xml转对象)

版权声明:本文为博主九师兄(QQ群:spark源代码 198279782 欢迎来探讨技术)原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_21383435/article/details/82116706

1. XStream简介

XStream是一个Java对象与XML互相转换的工具类库。
官网链接: http://x-stream.github.io/index.html

2.简单使用

下载页面:http://x-stream.github.io/download.html
使用Maven构建项目的加入以下依赖:

<dependency>
    <groupId>com.thoughtworks.xstream</groupId>
    <artifactId>xstream</artifactId>
    <version>1.4.10</version>
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>${lombok.version}</version>
</dependency>

1.正常xml的解析

注意代码中xmlString都代表当前小结里面的xml字符串

<User>
  <userName>lanweihong</userName>
  <email>[email protected]</email>
</User>

对象

public class User {

    private String userName;
    private String email;

     public User(String userName, String email) {
        this.userName = userName;
        this.email = email;
    }
}

运行

public static void main(String[] args) {
    XStream xStream = new XStream();
    xStream.alias("User", User.class);
    String xml = xmlString;
    //转对象
    User user = (User)xStream.fromXML(xml);
    System.out.println(user.toString());
}

输出文本为:

User:{userName=lanweihong,email=lwhhhp@gmail.com}

2.有点不正常xml的解析

一个看着比较“正常”的带有集合的xml
1. carInfos做为根元素,其子元素是由N个carInfo组成的集合,每个carInfo元素描述一个对象信息。
2. carInfo的子元素,每个tag做为属性名,tag所包含的txt做为属性值。

<carInfos dwName="sys.common.new_vehicle_DW">
    <carInfo index="1">
        <VehicleId>FTBAUD0088</VehicleId>
        <VehicleName>福克斯CAF7163B5轿车</VehicleName>
        <Remark>两厢 双离合 舒适型 国Ⅴ</Remark>
        <VehiclePrice>101800</VehiclePrice>
    </carInfo>
    <carInfo index="2">
        <VehicleId>FTBAUD0078</VehicleId>
        <VehicleName>福克斯CAF7163B5轿车</VehicleName>
        <Remark>两厢 双离合 风尚型 国Ⅴ</Remark>
        <VehiclePrice>113800</VehiclePrice>
    </carInfo>
    <carInfo index="3">
        <VehicleId>FTBAUD0097</VehicleId>
        <VehicleName>福克斯CAF7163B5轿车</VehicleName>
        <Remark>两厢 双离合 智行版 风尚型 国Ⅴ</Remark>
        <VehiclePrice>115800</VehiclePrice>
    </carInfo>
</carInfos>

与xml元素对应的Java类
对应carInfos元素

@XStreamAlias("carInfos")//对应carInfos元素
public class CarInfos {

    @XStreamAsAttribute
    private String dwName;//对应carInfos元素的dwName属性

    @XStreamImplicit(itemFieldName = "carInfo")
    private List<CarInfo> carInfoList = new ArrayList<CarInfo>();//对应N个carInfo元素组成的集合

    //省略getter/setter方法
}

对应carInfo元素

@XStreamAlias("carInfo")//对应carInfo元素
public class CarInfo {

    @XStreamAsAttribute
    private String index;//对应carInfo的index属性

    @XStreamAlias("VehicleId")
    private String vehicleId;//对应carInfo的VehicleId子元素

    @XStreamAlias("VehicleName")
    private String VehicleName;//对应carInfo的VehicleName子元素

    @XStreamAlias("Remark")
    private String remark;//对应carInfo的Remark子元素

    @XStreamAlias("VehiclePrice")
    private String vehiclePrice;//对应carInfo的VehiclePrice子元素

    //省略getter/setter方法
}

解析xml

public static void main(String[] args) throws Exception {
    File dataXml = readXml();//读取xml
    XStream xstream = new XStream(new DomDriver());//创建Xstram对象
    xstream.autodetectAnnotations(true);
    xstream.processAnnotations(CarInfos.class);
    CarInfos carInfos = (CarInfos) xstream.fromXML(dataXml);
    //打印对象
    System.out.printf("CarInfos dwName:%s\n", carInfos.getDwName());
    for (CarInfo carInfo : carInfos.getCarInfoList()) {
        System.out.printf("\tCarInfo index:%s\n", carInfo.getIndex());
        System.out.printf("\tCarInfo VehicleId:%s\n", carInfo.getVehicleId());
        System.out.printf("\tCarInfo VehicleName:%s\n", carInfo.getVehicleName());
        System.out.printf("\tCarInfo VehiclePrice:%s\n", carInfo.getVehiclePrice());
        System.out.printf("\tCarInfo Remark:%s\n", carInfo.getRemark());
    }
    //将对象转为xml,再次打印
    String resultXml = xstream.toXML(carInfos);
    System.out.printf("=======================\n" + resultXml);
}

3.更加不正常xml的解析

一个“有点别扭”的xml

特点是carInfo元素下是多个attribute元素的集合。但是很明显,每个attribute元素的属性name的值,都本应该是carInfo元素的子元素的tagName。

<carInfos dwName="sys.common.new_vehicle_DW">
    <carInfo index="1">
        <attribute name="VehicleId">FTBAUD0088</attribute>
        <attribute name="VehicleName">福克斯CAF7163B5轿车</attribute>
        <attribute name="Remark">两厢 双离合 舒适型 国Ⅴ</attribute>
        <attribute name="VehiclePrice">101800</attribute>
    </carInfo>
    <carInfo index="2">
        <attribute name="VehicleId">FTBAUD0078</attribute>
        <attribute name="VehicleName">福克斯CAF7163B5轿车</attribute>
        <attribute name="Remark">两厢 双离合 风尚型 国Ⅴ</attribute>
        <attribute name="VehiclePrice">113800</attribute>
    </carInfo>
    <carInfo index="3">
        <attribute name="VehicleId">FTBAUD0097</attribute>
        <attribute name="VehicleName">福克斯CAF7163B5轿车</attribute>
        <attribute name="Remark">两厢 双离合 智行版 风尚型 国Ⅴ</attribute>
        <attribute name="VehiclePrice">115800</attribute>
    </carInfo>
</carInfos>

与xml元素对应的Java类
根据attribute元素,新建一个CarAttr类。

注意这里使用到@XStreamCoverter注解。 而且没有对成员变量添加注解。

@XStreamAlias("attribute")
@XStreamConverter(CarAttrConverter.class)
public class CarAttr {

    //没有使用@XStreamAsAttribute注解
    private String name;

    //没有使用注解
    private String value;

    //省略getter/setter方法

对CarInfo类进行修改,因为carInfo元素下是多个attribute元素,所以定义了一个List集合。如同CarInfos与CarInfo的关系。

@XStreamAlias("carInfo")
public class CarInfo {

    @XStreamAsAttribute
    private String index;

    @XStreamImplicit(itemFieldName = "attribute")
    private List<CarAttr> attrs = new ArrayList<CarAttr>();

    //省略getter/setter方法
}

定义CarAttr转换类(这个是可有可无的类)

import com.thoughtworks.xstream.converters.Converter;
import com.thoughtworks.xstream.converters.MarshallingContext;
import com.thoughtworks.xstream.converters.UnmarshallingContext;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;

public class CarAttrConverter implements Converter {

    @Override
    public boolean canConvert(Class type) {
        return type.equals(CarAttr.class);//转换条件
    }

    /**
     * 将java对象转为xml时使用
     */
    @Override
    public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {
        CarAttr attr = (CarAttr) source;
        // writer.startNode("attribute");
        writer.addAttribute("name", attr.getName());
        writer.setValue(attr.getValue());
        // writer.endNode();
    }

    /**
     * 将xml转为java对象使用
     */
    @Override
    public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
        CarAttr a = new CarAttr();// 在解析attribute元素时,先创建一个CarAttr对象
        a.setName(reader.getAttribute("name"));// 将attribute元素的name属性设置为CarAttr对象的name属性值
        a.setValue(reader.getValue());// 将attribute元素的txt值设置为CarAttr对象的value值
        return a;
    }
}

解析xml

public static void main(String[] args) throws Exception {
        File dataXml = readXml();
        XStream xstream = new XStream(new DomDriver());
        xstream.autodetectAnnotations(true);
        xstream.processAnnotations(CarInfos.class);
        CarInfos carInfos = (CarInfos) xstream.fromXML(dataXml);
        //打印对象
        System.out.printf("CarInfos dwName:%s\n", carInfos.getDwName());
        for (CarInfo carInfo : carInfos.getCarInfoList()) {
            System.out.printf("\tCarInfo index:%s\n", carInfo.getIndex());
            for (CarAttr ca : carInfo.getAttrs()) {
                System.out.printf("\t\tCarAttr name:%s,value:%s\n", ca.getName(), ca.getValue());
            }
        }
        String resultXml = xstream.toXML(carInfos);
        System.out.printf("=======================\n" + resultXml);
    }

两个xml的解析方法没有区别,只是在打印解析出的对象时,稍有不同。主要区别在于根据attribute元素,新增加了CarAttr类的定义,及与CarAttr类对应CarAttrConverter转换类的使用。

4.非常不正常xml的解析

<dlineage>
   <relation id="3" type="dataflow">
      <target coordinate="[1,27],[1,31]" column="NAME" id="5" parent_id="1" parent_name="TABLEA"/>
      <source coordinate="[1,27],[1,31]" column="NAME" id="1" parent_id="2" parent_name="B"/>
   </relation>
   <relation id="4" type="dataflow">
      <target coordinate="[1,32],[1,35]" column="AGE" id="6" parent_id="1" parent_name="TABLEA"/>
      <source coordinate="[1,32],[1,35]" column="AGE" id="2" parent_id="2" parent_name="B"/>
   </relation>
   <table name="TABLEA" id="1" type="table" coordinate="[1,13],[1,19]">
      <column name="NAME" id="5" coordinate="[1,27],[1,31]"/>
      <column name="AGE" id="6" coordinate="[1,32],[1,35]"/>
   </table>
   <table name="B" id="2" type="table" coordinate="[1,42],[1,43]">
      <column name="NAME" id="1" coordinate="[1,27],[1,31]"/>
      <column name="AGE" id="2" coordinate="[1,32],[1,35]"/>
   </table>
</dlineage>

这里有俩坑
1. 坑1:dlineage对象我的Dlinage(一个解析血缘的工具类收费的))已经存储,不能定义这个
2. 坑2:parent_id parent_name 不识别带有横岗的属性

针对这两个问题对xml进行预处理

xmlString = xmlString.replaceAll("dlineage","DlineageEntity");
xmlString = xmlString.replaceAll("parent_id","parentId");
xmlString = xmlString.replaceAll("parent_name","parentName");

建立实体类

@Data
@XStreamAlias("DlineageEntity")//对应dlineage元素
public class DlineageEntity {

    // 对应relation
    @XStreamImplicit(itemFieldName = "relation")
    private List<Relation> relation;

    // 对应table
    @XStreamImplicit(itemFieldName = "table")
    private List<Table> table;

}
@Data
@XStreamAlias("relation")  // 对应relation
public class Relation {

    // 对应 id 属性
    @XStreamAsAttribute
    private String id;
    // 对应 type 属性
    @XStreamAsAttribute
    private String type;

    // 对应 target 子元素
    @XStreamImplicit(itemFieldName = "target")
    private List<Target> target ;
    // 对应 source 子元素
    @XStreamImplicit(itemFieldName = "source")
    private List<Source> source ;

}
@Data
@XStreamAlias("target") // 对应 target
public class Target {

    // 对应 coordinate 属性
    @XStreamAsAttribute
    private String coordinate;
    // 对应 column 属性
    @XStreamAsAttribute
    private String column;
    // 对应 id 属性
    @XStreamAsAttribute
    private String id;
    // 对应 parentId 属性
    @XStreamAsAttribute
    private String parentId;
    // 对应 parentName 属性
    @XStreamAsAttribute
    private String parentName;

}
@Data
@XStreamAlias("source")
public class Source {

    @XStreamAsAttribute
    private String coordinate;
    @XStreamAsAttribute
    private String column;
    @XStreamAsAttribute
    private String id;
    @XStreamAsAttribute
    private String parentId;
    @XStreamAsAttribute
    private String parentName;

}
@Data
@XStreamAlias("table")
public class Table {

    @XStreamAsAttribute
    private String name;
    @XStreamAsAttribute
    private String id;
    @XStreamAsAttribute
    private String type;
    @XStreamAsAttribute
    private String coordinate;

    @XStreamImplicit(itemFieldName = "column")
    private List<Column> column;
}
@Data
@XStreamAlias("column")
public class Column {

    @XStreamAsAttribute
    private String name;
    @XStreamAsAttribute
    private String id;
    @XStreamAsAttribute
    private String coordinate;


}

解析对象

private static void makeBlood(String result ) {
        result = result.replaceAll("dlineage","DlineageEntity");
        result = result.replaceAll("parent_id","parentId");
        result = result.replaceAll("parent_name","parentName");

        System.out.println( "===>"+result );

        XStream xStream = new XStream();
        xStream.autodetectAnnotations(true);
        xStream.processAnnotations(DlineageEntity.class);
        DlineageEntity carInfos = (DlineageEntity) xStream.fromXML(result);

        System.out.println(carInfos.toString());
    }

结果

DlineageEntity(
    relation=[
        Relation(
            id=3, type=dataflow, 
            target=[ Target( coordinate=[1,27],[1,31], column=NAME, id=5, parentId=1, parentName=TABLEA)], 
            source=[Source(coordinate=[1,27],[1,31], column=NAME, id=1, parentId=2, parentName=B)]
        ),  
        Relation(id=4, type=dataflow, 
            target=[Target(coordinate=[1,32],[1,35], column=AGE, id=6, parentId=1, parentName=TABLEA)], 
            source=[Source(coordinate=[1,32],[1,35], column=AGE, id=2, parentId=2, parentName=B)]
        ) 
],  
table=[ 
     Table(name=TABLEA, id=1, type=table, coordinate=[1,13],[1,19], 
         column=[ 
             Column(name=NAME, id=5, coordinate=[1,27],[1,31]), 
             Column(name=AGE, id=6, coordinate=[1,32],[1,35])
             ]
    ), 
     Table(name=B, id=2, type=table, coordinate=[1,42],[1,43], 
         column=[ 
             Column(name=NAME, id=1, coordinate=[1,27],[1,31]), 
             Column(name=AGE, id=2, coordinate=[1,32],[1,35])
         ]
        )
    )

猜你喜欢

转载自blog.csdn.net/qq_21383435/article/details/82116706
今日推荐