xml解析——注解辅助解析

先上测试xml报文:

<?xml version="1.0" encoding="UTF-8"?>
<Request>
  <Head>
    <CODE>0000</CODE>
    <id>11111</id>
    <TIMESTAMP>1547016623166</TIMESTAMP>
    <serviceId>serviceID</serviceId>
  </Head>
  <BODY>
    <Orders>
      <Order date="2019-01-09" price="123456" user="张三">
        <Goods id="1">
          <name>java从入门到放弃</name>
          <price>1100</price>
          <count>1</count>
          <total_price>100</total_price>
        </Goods>
        <Goods id="1">
          <name>脊椎康复指南</name>
          <price>1000</price>
          <count>1</count>
          <total_price>1000</total_price>
        </Goods>
      </Order>
      <Order date="2019-01-09" price="11000" user="阿珍爱上了阿强">
        <Goods id="1">
          <name>java从入门到放弃</name>
          <price>1100</price>
          <count>1</count>
          <total_price>100</total_price>
        </Goods>
      </Order>
    </Orders>
    <userId>1111</userId>
    <userName>王二麻子</userName>
    <Date>2019-01-09 14:50:23</Date>
  </BODY>
</Request>

一、核心XmlAttribleSub类

public class XmlAttribleSub implements Serializable {
  private static final long serialVersionUID = -4651442473666480694L;

  /** 节点所在层级 */
  private int id;
  /** 节点名称 */
  private String name;
  /** 节点值 基本节点才有值 */
  private String value = "";
  /** 属性map */
  private Map<String, String> attrs = new HashMap<>();
  /** 子节点列表 */
  private List<XmlAttribleSub> subNodes = new ArrayList<>();

  public XmlAttribleSub() {}

  public XmlAttribleSub(int id, String name) {
    this.id = id;
    this.name = name;
  }

  public int getId() {
    return id;
  }

  public void setId(int id) {
    this.id = id;
  }

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public Map<String, String> getAttrs() {
    return attrs;
  }

  public void addAttr(String name, String value) {
    this.attrs.put(name, value);
  }

  public List<XmlAttribleSub> getSubNodes() {
    return subNodes;
  }

  public String getValue() {
    return value == null ? "" : value;
  }

  public void setValue(String value) {
    this.value = value;
  }

  public void addSubNode(XmlAttribleSub subNode) {
    this.subNodes.add(subNode);
  }

  public boolean isRoot() {
    return this.id == 0;
  }

  public boolean isHasAttr() {
    return this.attrs.size() > 0;
  }

  public boolean isHasSubNode() {
    return this.subNodes.size() > 0;
  }

  public boolean isUnderNode() {
    return !isHasAttr() && !isHasSubNode();
  }

  @Override
  public String toString() {
    StringBuilder sb = new StringBuilder();
    if (this.id == 0) {
      sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
    }
    sb.append("<").append(this.name);
    if (CollectionUtil.isNotBlank(attrs)) {
      for (Map.Entry<String, String> entry : attrs.entrySet()) {
        sb.append(" ").append(entry.getKey()).append("=").append("\"").append(entry.getValue())
            .append("\"");
      }
    }
    sb.append(">");
    if (!subNodes.isEmpty()) {
      for (XmlAttribleSub subNode : subNodes) {
        recSub(subNode, sb);
      }
    } else {
      sb.append(this.getValue());
    }
    sb.append("</").append(this.name).append(">");
    return sb.toString();
  }

  private void recSub(XmlAttribleSub sub, StringBuilder sb) {
    sb.append("<").append(sub.getName());
    if (CollectionUtil.isNotBlank(sub.getAttrs())) {
      for (Map.Entry<String, String> entry : sub.getAttrs().entrySet()) {
        sb.append(" ").append(entry.getKey()).append("=").append("\"").append(entry.getValue())
            .append("\"");
      }
    }
    sb.append(">");
    if (sub.getSubNodes().isEmpty()) {
      sb.append(sub.getValue());
    } else {
      for (XmlAttribleSub subNode : sub.getSubNodes()) {
        recSub(subNode, sb);
      }
    }
    sb.append("</").append(sub.getName()).append(">");
  }

}

XmlAttribleSub类是抽象出来的公共xml封装类,含有以下五个属性:

  1. id:当前节点所在层级,根节点为0,往里递增。测试报文Request为根节点,id=0;Head和Body的id为1;
  2. name:当前节点名称;
  3. value:节点值,只有基本节点才有值,即attrs和subNodes都为空,比如测试报文name、price节点等;
  4. attrs:节点属性map,当前节点的属性的键值对集合,比如测试报文Order节点的date,user属性等;
  5. subNodes:当前节点的子节点列表,list元素也是XmlAttribleSub;

 

二、工具类Dom4Util

Dom4Util类提供xml转换方法,包括xml转换成XmlAttribleSub,xml转换成bean,bean转换xml等。
  /**
   * 从根节点开始,将xml转换成XmlAttribleSub
   * 
   * @param xml
   * @return
   * @throws Exception
   */
  public static XmlAttribleSub xPathAttribleSub(String xml) throws Exception {
    Document document = DocumentHelper.parseText(xml);
    Element root = document.getRootElement();
    XmlAttribleSub sub = new XmlAttribleSub(0, root.getName());
    recParse(root, sub, 0);
    return sub;
  }

  /**
   * 递归解析xml
   * 
   * @param root
   * @param sub
   * @param level
   */
  private static void recParse(Element root, XmlAttribleSub sub, int level) {
    level++;
    if (root.isTextOnly()) {
      // 该节点没有字节点
      sub.setValue(root.getText());
    }
    // 设置当前节点属性map
    for (Iterator it = root.attributeIterator(); it.hasNext();) {
      Attribute attr = (Attribute) it.next();
      sub.getAttrs().put(attr.getName(), attr.getValue());
    }
    // 递归子节点
    for (Iterator iter = root.elementIterator(); iter.hasNext();) {
      Element element = (Element) iter.next();
      XmlAttribleSub subNode = new XmlAttribleSub(level, element.getName());
      for (Iterator it = element.attributeIterator(); it.hasNext();) {
        Attribute attr = (Attribute) it.next();
        subNode.getAttrs().put(attr.getName(), attr.getValue());
      }
      if (element.isTextOnly()) {
        subNode.setValue(element.getText());
      } else {
        recParse(element, subNode, level);
      }
      sub.addSubNode(subNode);
    }
  }

从根节点开始,解析整个xml为XmlAttribleSub,这里借助了Document来解析xml报文。

/**
   * 根据指定节点开始,将xml转换成XmlAttribleSub列表
   * 
   * @param xml
   * @param xPathId 报文节点,例如//Orders/Order/goods/name
   * @return
   */
  public static List<XmlAttribleSub> xPathAttribleSub(String xml, String xPathId) throws Exception {
    List<XmlAttribleSub> subs = new ArrayList<>();
    Document document = DocumentHelper.parseText(xml);
    Element root = document.getRootElement();
    // 根据指定节点获取节点
    List<Element> elements = root.selectNodes(xPathId);
    // 判断当前节点的层级,从根节点0开始
    int level = xPathId.substring(1).split("/").length;
    for (Element element : elements) {
      XmlAttribleSub sub = new XmlAttribleSub(level - 2, element.getName());
      recParse(element, sub, level - 2);
      subs.add(sub);
    }
    return subs;
  }

从制定节点开始解析,例如解析报文中的Goods节点,xPathId为//Request/BODY/Orders/Order/goods,返回的是一个list。

 

三、XmlAttribleSub转换成bean

这里需要添加两个注解Xml和Level,来标注bean对应的节点名称、层级等。

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.TYPE, ElementType.METHOD})
public @interface Xml {

  /**
   * 注解是否是节点属性,默认为false,没有默认值添加注解时必填
   * 
   * @return
   */
  boolean isAttr() default false;

  /**
   * 标志bean属性是否是xml元素,默认为false,是xml元素的属性需要设置为true
   * 
   * @return
   */
  boolean isElement() default false;

  /**
   * 属性是否是list,默认为false
   * 
   * @return
   */
  boolean isList() default false;

  /**
   * 属性bean的类型或list中bean的类型
   * 
   * @return
   */
  Class clazz() default Object.class;

  /**
   * 属性对应的xml节点名称,一样不需要设置
   * 
   * @return
   */
  String xmlName() default "";

  /**
   * 配置在Level注解中时必须配置bean的属性
   * 
   * @return
   */
  String attrName() default "";

  /**
   * xml转date类型的格式
   * 
   * @return
   */
  String dateFormat() default "yyyy-MM-dd HH:mm:ss";

  int id() default -1;

}

Xml注解属性:

  1. isAttr:标注bean的属性是否是对应xml节点的属性,默认为false;
  2. isElement:标注bean的属性是否需要映射成xml的节点或节点属性,默认为false,这个对于bean转换成xml需要;
  3. isList:标注bean的属性是否对应xml的list节点(该类对应节点包含一个list节点),例如Body节点的Orders节点,默认为false,如果isList配置为true,则必须配置clazz;
  4. clazz:bean的属性对应节点的对象的class,默认为Object.class;
  5. xmlName:bean的属性对应xml节点或节点属性的名称,默认为空,如果bean属性名和xml节点名一致,可以不配置;
  6. attrName:配置bean的属性名称,默认为空,当xml注解配置在Level注解中时需要配置;
  7. dateFormat:bean的属性对应Date类型时,需要配置时间格式化字符串,默认为yyyy-MM-dd HH:mm:ss;

Xml注解可以添加在属性上,也可以添加在Level注解中。

 

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE})
public @interface Level {

  /**
   * 类对应节点所在的层级
   * 
   * @return
   */
  int value() default -1;

  /**
   * 类对应的节点名,不设置默认为类名
   * 
   * @return
   */
  String xmlName() default "";

  Xml[] xmls() default {@Xml()};

  /**
   * 标志当前节点映射的bean就是一个list
   * 
   * @return
   */
  boolean isList() default false;
}

Level节点的属性:

  1. value:节点的层级,默认为-1,根节点为0,往里递增;
  2. xmlName:类对应的接待你名称,如果类名与对应节点名称不一致,需要配置正确的节点名称,默认为空;
  3. xmls:类的属性xml配置集合,可以在这里集中配合类的属性Xml注解,默认为一个空的Xml注解数组;
  4. isList:当前类是否对应xml的list节点,例如测试报文中的Order节点就是一个list节点,默认为false;

Level节点只能配置在类上。

下面是测试报文的映射Bean:

1、根节点映射Bean,也是整个报文的映射bean,Request:

@Getter
@Setter
@ToString
@Level(value = 0, xmls = {@Xml(attrName = "head", xmlName = "HEAD", clazz = Head.class, isElement = true),
    @Xml(attrName = "body", xmlName = "BODY", clazz = Body.class, isElement = true)})
public class Request {
  private Head head;
  private Body body;
}

  根节点Reque包含两个对象Head和Body,这里Head属性不会变化,Body类抽出固定的属性,在其子类扩展额外属性,像这里的Orders节点。这里body节点的xml注解clazz配置的是父类Body.class,通过以下方法动态改变注解的clazz属性值

  /**
   * 根据body的实体类获取不同Request
   * 
   * @param reClazz root节点的映射bean的class
   * @param bodyClazz body节点中额外的节点映射bean的class
   * @param <T>
   * @return
   * @throws NoSuchFieldException
   * @throws IllegalAccessException
   */
  public static <T> Class<T> getXmlClass(Class<T> reClazz, Class bodyClazz)
      throws NoSuchFieldException, IllegalAccessException {
    Level level = reClazz.getAnnotation(Level.class);
    Xml[] xmls = level.xmls();
    for (Xml xml : xmls) {
      if (xml.attrName().equals("body")) {
        ReflectUtil.changeAnnotationValue(xml, "clazz", bodyClazz);
      }
    }
    return reClazz;
  }

修改注解属性值的方法

  /**
   * 修改注解的属性值
   * 
   * @param annotation
   * @param name
   * @param value
   * @throws NoSuchFieldException
   * @throws IllegalAccessException
   */
  public static void changeAnnotationValue(Annotation annotation, String name, Object value)
      throws NoSuchFieldException, IllegalAccessException {
    InvocationHandler handler = Proxy.getInvocationHandler(annotation);
    Field f = handler.getClass().getDeclaredField("memberValues");
    f.setAccessible(true);
    Map<String, Object> memberValues = (Map<String, Object>) f.get(handler);
    memberValues.put(name, value);
  }

2、//Request/Head节点的映射类Head:

@Getter
@Setter
@ToString
@Level(value = 1, xmls = {@Xml(attrName = "code", xmlName = "CODE", isElement = true),
    @Xml(attrName = "timestamp", xmlName = "TIMESTAMP", isElement = true)})
public class Head {
  private String code;
  @Xml(isElement = true)
  private String id;
  private Timestamp timestamp;
  @Xml(isElement = true)
  private String serviceId;
}

 这里,Xml注解可以注解在属性上,也可以集中注解在Level注解中,如果属性重复注解,以属性上的Xml注解为准。

3、Body类:

@Getter
@Setter
@ToString
@Level(value = 1, xmlName = "BODY", xmls = {
    @Xml(attrName = "userId", isElement = true),
    @Xml(attrName = "userName", isElement = true)
})
public class Body {
  private long userId;
  private String userName;
  @Xml(xmlName = "Date", isElement = true)
  private Date date;
}

 父类Body包含该节点的固定属性节点以及节点Xml注解配置和当前节点的Level配置。

//Request/BODY节点的映射类,Body的子类OrderBody:

public class OrderBody extends Body {

  @Xml(xmlName = "Orders", isList = true, clazz = Order.class, isElement = true)
  private List<Order> orders;

  public List<Order> getOrders() {
    return orders;
  }

  public void setOrders(List<Order> orders) {
    this.orders = orders;
  }

  @Override public String toString() {
    String s = super.toString();
    return s.substring(0, s.length() - 1) + ", orders=" + orders + ")";
  }
}

 Body的子类可以继承其父类的属性及Xml注解配置和Level注解配置。

4、//Request/BODY/Orders/Order节点的映射类Order:

@Level(value = 1, isList = true,
    xmls = {@Xml(attrName = "user", isAttr = true, isElement = true),
        @Xml(attrName = "date", isAttr = true, isElement = true, dateFormat = "yyyy-MM-dd"),
        @Xml(attrName = "price", isAttr = true, isElement = true), @Xml(attrName = "goodsList",
            xmlName = "Order", clazz = Goods.class, isElement = true, isList = true)})
public class Order {
  // @Xml(isAttr = true, isElement = true)
  private String user;
  // @Xml(isAttr = true, isElement = true)
  private Date date;
  // @Xml(isAttr = true, isElement = true)
  private String price;
  // @Xml(clazz = Goods.class, isElement = true, isList = true)
  private List<Goods> goodsList = new ArrayList<>();

  public void add(Goods goods) {
    this.goodsList.add(goods);
  }

  public String getUser() {
    return user;
  }

  public void setUser(String user) {
    this.user = user;
  }

  public Date getDate() {
    return date;
  }

  public void setDate(Date date) {
    this.date = date;
  }

  public String getPrice() {
    return price;
  }

  public void setPrice(String price) {
    this.price = price;
  }

  public List<Goods> getGoodsList() {
    return goodsList;
  }

  public void setGoodsList(List<Goods> goodsList) {
    this.goodsList = goodsList;
  }

  @Override
  public String toString() {
    return "Order{" + "user='" + user + '\'' + ", date='" + date + '\'' + ", price='" + price + '\''
        + ", goodsList=" + goodsList.toString() + '}';
  }
}

5、//Request/BODY/Orders/Order/Goods节点的映射类Goods:

@Getter
@Setter
@ToString
@Level(0)
public class Goods {

  @Xml(id = 0, isAttr = true, isElement = true)
  private String id;

  @Xml(id = 1, xmlName = "name", isElement = true)
  private String name;

  @Xml(isElement = true)
  private String price;

  @Xml(isElement = true)
  private int count;

  @Xml(isElement = true, xmlName = "total_price")
  private String totalPrice;
}

 

bean配置文成,上菜刀了,Dom4Util类的xml解析成对应bean的方法:

  /**
   * XmlAttribleSub转换成bean
   * 
   * @param sub
   * @param clazz
   * @param <T>
   * @return
   * @throws Exception
   */
  public static <T> T xmlSubToBean(XmlAttribleSub sub, Class<T> clazz) throws Exception {
    if (!sub.isHasAttr() && !sub.isHasSubNode()) {
      throw new Exception(sub + "既没有属性也没有子节点");
    }
    T t = clazz.newInstance();
    Xml[] xmls = XmlAnnotationUtil.getClassXmls(clazz);
    Field field;
    // 解析属性
    for (Map.Entry<String, String> entry : sub.getAttrs().entrySet()) {
      field = XmlAnnotationUtil.getBeanField(clazz, xmls, entry.getKey());
      Xml xml = XmlAnnotationUtil.getXml(xmls, entry.getKey());
      if (xml != null) {
        if (DataType.isDate(field.getType().getTypeName())) {
          ReflectUtil.setField(t, field, DateUtil.parseDate(entry.getValue(), xml.dateFormat()));
        } else {
          ReflectUtil.setField(t, field, entry.getValue());
        }
      }
    }
    // 解析子节点
    Xml xml;
    Object o;
    Level level = clazz.getAnnotation(Level.class);
    if (level != null && level.isList()) {
      // 如果当前节点就是一个list
      List list = new ArrayList();
      xml = XmlAnnotationUtil.getListXml(xmls);
      if (xml != null) {
        field = XmlAnnotationUtil.getBeanField(clazz, xmls, sub.getName());
        for (XmlAttribleSub xmlAttribleSub : sub.getSubNodes()) {
          list.add(xmlSubToBean(xmlAttribleSub, xml.clazz()));
        }
        ReflectUtil.setField(t, field, list);
      }
    } else {
      // 遍历当前节点的子节点
      for (XmlAttribleSub xmlAttribleSub : sub.getSubNodes()) {
        xml = XmlAnnotationUtil.getXml(xmls, xmlAttribleSub.getName());
        if (xml != null) {
          field = XmlAnnotationUtil.getBeanField(clazz, xmls, xmlAttribleSub.getName());
          if (xml.isList()) {
            // 当前sub的子节点是一个list的元素
            Class subClazz = XmlAnnotationUtil.getSubNodeBeanClazz(xmls, xmlAttribleSub.getName());
            if (subClazz == null) {
              throw new Exception(xmlAttribleSub.getName() + "节点没有配置映射clazz");
            }
            List list = new ArrayList();
            for (XmlAttribleSub s : xmlAttribleSub.getSubNodes()) {
              // 子节点是否还有子节点或有属性
              if (s.isHasSubNode() || s.isHasAttr()) {
                list.add(xmlSubToBean(s, subClazz));
              } else {
                log.warn("list存在空节点");
              }
            }
            ReflectUtil.setField(t, field, list);
          } else if (!Object.class.getTypeName().equals(xml.clazz().getTypeName())) {
            // 子节点是bean
            o = xmlSubToBean(xmlAttribleSub, xml.clazz());
            ReflectUtil.setField(t, field, o);
          } else if (xmlAttribleSub.isUnderNode()) {
            // 当前节点是普通节点
            if (DataType.DATATYPE_DATE.equals(field.getType().getTypeName())) {
              ReflectUtil.setField(t, field,
                  DateUtil.parseDate(xmlAttribleSub.getValue(), xml.dateFormat()));
            } else {
              ReflectUtil.setField(t, field,
                  DataType.transfer(xmlAttribleSub.getValue(), field.getType()));
            }
          }
        }
      }
    }
    return t;
  }

  这里,反射对象的属性用到了工具类ReflectUtil,获取对象的所有属性,包括父类的属性:

  /**
   * 获取类的所有属性,包括父类的所有属性
   * 
   * @param clazz
   * @return
   */
  public static Field[] getAllFields(Class clazz) {
    List<Field> fieldList = new ArrayList<>();
    recurField(fieldList, clazz);
    return CollectionUtil.toArray(fieldList);
  }

  private static void recurField(List<Field> fieldList, Class clazz) {
    if (clazz != null) {
      Field[] fields = clazz.getDeclaredFields();
      fieldList.addAll(Arrays.asList(fields));
      recurField(fieldList, clazz.getSuperclass());
    }
  }

还有注解工具类XmlAnnotationUtil的方法:

/**
   * 获取xml映射bean的所有xml注解
   * 
   * @param clazz
   * @return
   */
  public static Xml[] getClassXmls(Class clazz) throws Exception {
    List<Xml> xmlList = new ArrayList<>();
    Level level = (Level) ReflectUtil.getAnnotation(clazz, Level.class);
    Xml[] xs = null;
    if (levelHasXml(level)) {
      xs = level.xmls();
    }
    Field[] fields = ReflectUtil.getAllFields(clazz);
    if (CollectionUtil.isNotBlank(fields)) {
      Field f;
      for (Field field : fields) {
        Xml xml = field.getAnnotation(Xml.class);
        if (xml != null) {
          // 设置xml的attrName和xmlName
          InvocationHandler handler = Proxy.getInvocationHandler(xml);
          f = handler.getClass().getDeclaredField("memberValues");
          f.setAccessible(true);
          Map<String, Object> memberValues = (Map<String, Object>) f.get(handler);
          memberValues.put("attrName", field.getName());
          if (xml.xmlName().isEmpty()) {
            memberValues.put("xmlName", field.getName());
          }
          // 以属性上的注解为主,level注解中配置的xml会被覆盖掉
          xmlList.add(xml);
          if (xs != null) {
            for (int i = 0; i < xs.length; i++) {
              if (field.getName().equals(xs[i].attrName())) {
                xs[i] = null;
              }
            }
          }
        }
      }
    }
    if (CollectionUtil.isNotBlank(xs)) {
      for (Xml xml : xs) {
        if (xml != null) {
          xmlList.add(xml);
        }
      }
    }
    return CollectionUtil.toArray(xmlList);
  }

 还有bean转换成XmlAttribleSub方法:

public static XmlAttribleSub beanToXmlSub(Object obj) throws Exception {
    Class clazz = obj.getClass();
    Level level = (Level) ReflectUtil.getAnnotation(clazz, Level.class);
    int nodeLevel = 0;
    Xml[] xmls = XmlAnnotationUtil.getClassXmls(clazz);
    String classXmlName = clazz.getSimpleName();
    if (level != null) {
      nodeLevel = level.value();
      classXmlName = level.xmlName().length() > 0 ? level.xmlName() : classXmlName;
    } else {
      log.warn("转xml的类{}未添加注解标志节点级别,默认为root", clazz.getName());
    }

    XmlAttribleSub root = new XmlAttribleSub(nodeLevel, classXmlName);
    Field[] fields = ReflectUtil.getAllFields(clazz);
    XmlAttribleSub sub;
    Xml xml;
    String attrName;
    Object attrValue;
    for (Field field : fields) {
      xml = XmlAnnotationUtil.getXml(xmls, field.getName());
      field.setAccessible(true);
      try {
        attrValue = field.get(obj);
        if (xml != null) {
          if (xml.isElement()) {
            // 节点属性是xml元素
            if (!Object.class.getName().equals(xml.clazz().getName())) {
              if (xml.isList()) {
                List list = (List) attrValue;
                // XmlAttribleSub xmlAttribleSub = root;
                if (level.isList()) {
                  // 当前节点是list
                  if (CommonUtils.isNotEmpty(list)) {
                    for (Object subNode : list) {
                      root.addSubNode(beanToXmlSub(subNode));
                    }
                  }
                } else {
                  // 当前节点包含list节点
                  XmlAttribleSub xmlAttribleSub = new XmlAttribleSub(nodeLevel + 1, xml.xmlName());
                  if (CommonUtils.isNotEmpty(list)) {
                    for (Object subNode : list) {
                      xmlAttribleSub.addSubNode(beanToXmlSub(subNode));
                    }
                  }
                  root.addSubNode(xmlAttribleSub);
                }
              } else {
                // 当前节点有bean子节点
                root.addSubNode(beanToXmlSub(attrValue));
              }
            } else if (xml.isAttr()) {
              // bean属性添加了xml注解,并且标志为xml节点属性
              attrName = "".equals(xml.xmlName()) ? field.getName() : xml.xmlName();
              String value = DataType.isDate(attrValue)
                  ? DateUtil.formatDate((Date) attrValue, xml.dateFormat())
                  : DataType.getAsStringNotNull(attrValue);
              // 设置属性
              root.addAttr(attrName, value);
            } else {
              // 属性是普通节点
              attrName = "".equals(xml.xmlName()) ? field.getName() : xml.xmlName();
              sub = new XmlAttribleSub(nodeLevel + 1, attrName);
              String value = DataType.isDateType(attrValue)
                  ? DateUtil.formatDate((Date) attrValue, xml.dateFormat())
                  : DataType.getAsStringNotNull(attrValue);
              sub.setValue(DataType.getAsStringNotNull(value));
              root.addSubNode(sub);
            }
          }
        }
      } catch (IllegalAccessException e) {
        root = null;
        log.error("bean转换成XmlAttribleSub异常", e);
      }
    }
    return root;
  }

根节点的XmlAttribleSub对象的tostring方法可以转换成xml报文:

 @Override
  public String toString() {
    StringBuilder sb = new StringBuilder();
    if (this.id == 0) {
      sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
    }
    sb.append("<").append(this.name);
    if (CollectionUtil.isNotBlank(attrs)) {
      for (Map.Entry<String, String> entry : attrs.entrySet()) {
        sb.append(" ").append(entry.getKey()).append("=").append("\"").append(entry.getValue())
            .append("\"");
      }
    }
    sb.append(">");
    if (!subNodes.isEmpty()) {
      for (XmlAttribleSub subNode : subNodes) {
        recSub(subNode, sb);
      }
    } else {
      sb.append(this.getValue());
    }
    sb.append("</").append(this.name).append(">");
    return sb.toString();
  }

  private void recSub(XmlAttribleSub sub, StringBuilder sb) {
    sb.append("<").append(sub.getName());
    if (CollectionUtil.isNotBlank(sub.getAttrs())) {
      for (Map.Entry<String, String> entry : sub.getAttrs().entrySet()) {
        sb.append(" ").append(entry.getKey()).append("=").append("\"").append(entry.getValue())
            .append("\"");
      }
    }
    sb.append(">");
    if (sub.getSubNodes().isEmpty()) {
      sb.append(sub.getValue());
    } else {
      for (XmlAttribleSub subNode : sub.getSubNodes()) {
        recSub(subNode, sb);
      }
    }
    sb.append("</").append(sub.getName()).append(">");
  }

 

这里面用到了一些自己写的工具类,详细代码请移步码云。

转换测试xml报文为Request对象

Request request = Dom4Util.xmlToBean(xml, XmlAnnotationUtil.getXmlClass(Request.class, OrderBody.class));

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值