问题背景
近期项目中涉及接收xml入参数据自动映射到java实体,xml数据是以@RequestBody形式接收,通过javax.xml.bind.annotation注解来实现自动转换,但是在xml数据中有一个子节点内的数据是非固定格式的数据,里面的各个元素的标签是动态的而不是固定的,就需要将这个子节点内数据当做一个字符串来解析并映射到实体的一个属性上,查阅资料后才找到一种解决办法。
目前的解决途径
通过目标字段增加@XmlJavaTypeAdapter自定义xml到java类型的适配器来实现,话不多说,上代码
实体类
package org.example;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
/**
* @Title: Company
* @Package org.example
* @Description: TODO
* @Author MYF
* @Date 2022/12/1 21:24
* @Version V1.0
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement
public class Company {
private String businessName;
private String orgType;
@XmlJavaTypeAdapter(CustomAdapter.class)
private String legalExt;
public String getBusinessName() {
return businessName;
}
public void setBusinessName(String businessName) {
this.businessName = businessName;
}
public String getOrgType() {
return orgType;
}
public void setOrgType(String orgType) {
this.orgType = orgType;
}
public String getLegalExt() {
return legalExt;
}
public void setLegalExt(String legalExt) {
this.legalExt = legalExt;
}
}
自定义xml到java类型的适配器
本例中只实现了xml到java类型的转换也就是下放代码中的 unmarshal 方法
package org.example;
import org.w3c.dom.Element;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
/**
* @Title: CustomAdapter
* @Package org.example
* @Description: TODO
* @Author MYF
* @Date 2022/12/1 21:26
* @Version V1.0
*/
public class CustomAdapter extends XmlAdapter<Object, String> {
@Override
public String unmarshal(Object xmlObj) throws Exception {
Element element = (Element)xmlObj;
TransformerFactory transFactory = TransformerFactory.newInstance();
Transformer transformer = transFactory.newTransformer();
StringWriter buffer = new StringWriter();
/**是否省略xml的头部声明**/
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
/**转换成字符串时应用的编码**/
transformer.setOutputProperty(OutputKeys.ENCODING, StandardCharsets.UTF_8.name());
/**可以理解为压缩xml,不美化格式**/
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "0");
transformer.transform(new DOMSource(element),
new StreamResult(buffer));
String xmlStr = buffer.toString();
return xmlStr;
}
@Override
public Object marshal(String v) throws Exception {
return v;
}
}
测试类
注:本例中测试xml中的数据为假数据
package org.example;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import java.io.Reader;
import java.io.StringReader;
public class TestXmlTransform {
public static void main(String[] args) throws Exception {
/**
* 示例xml结构如下,其中legalExt下为
* <company>
* <businessName>北京神宇科技公司</businessName>
* <orgType>02</orgType>
* <legalExt>
* <legalName>赵公子</legalName>
* <legalType>自然人</legalType>
* <legalIdCard>假装身份证号</legalIdCard>
* <dynamicKey1>dynamicVal1</dynamicKey1>
* <dynamicKey2>dynamicVal2</dynamicKey2>
* <dynamicKeyN>dynamicValN</dynamicKeyN>
* </legalExt>
* </company>
* 其中dynamicKey1~dynamicKeyN为动态标签,可能随实际业务不同而不同
* **/
String xmlStr = "<company><businessName>北京神宇科技公司</businessName><orgType>02</orgType><legalExt><legalName>赵公子</legalName><legalType>自然人</legalType><legalIdCard>假装身份证号</legalIdCard><dynamicKey1>dynamicVal1</dynamicKey1><dynamicKey2>dynamicVal2</dynamicKey2><dynamicKeyN>dynamicValN</dynamicKeyN></legalExt></company>";
Reader reader = null;
JAXBContext context = JAXBContext.newInstance(Company.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
reader = new StringReader(xmlStr);
Company company = (Company)unmarshaller.unmarshal(reader);
System.out.println(company.getLegalExt());
if (reader != null) {
reader.close();
}
}
}
测试类执行结果
实际代码输出为一行,为方便贴图借用hutoo的XmlUtil格式化了一下
最后
以上的代码已经打包到CSDN—→传送门
时间有限没在继续寻找更好的解决方案,如有更好的解决方式还望各位朋友留言相告!
PS:第一次编写这种文章,各位浅喷~