xml与javabean相互转换
- 一、JAXB
- 1. 对象转XML格式和XML格式转对象
- 2. 举例
- 3. 对象转XML报错及解决方案
- 4. XML转对象报错及解决方案
- 二、SAX
- 三、Android的xml pull解析
一、JAXB
1. 对象转XML格式和XML格式转对象
格式转换工具类
XmlUtils.java
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import java.io.StringWriter;
public class XmlUtils {
private static final Logger log = LoggerFactory.getLogger(XmlUtils.class);
public static String convertToXml(Object obj){
String resultXml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n";
return resultXml+convertToXml(obj,"utf-8");
}
public static String convertToXml(Object obj,String encoding){
String result = null;
try {
JAXBContext context = JAXBContext.newInstance(obj.getClass());
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT,true);
marshaller.setProperty(Marshaller.JAXB_ENCODING,encoding);
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
StringWriter writer = new StringWriter();
marshaller.marshal(obj,writer);
result =writer.toString();
} catch (Exception e) {
log.error("转换XML失败:"+e.getMessage());
}
return result;
}
}
/**
* 将对象根据路径转换成xml文件
*
* @param obj
* @param path
* @return
*/
public static void convertToXmlFile(Object obj, String path) {
try {
// 利用jdk中自带的转换类实现
JAXBContext context = JAXBContext.newInstance(obj.getClass());
Marshaller marshaller = context.createMarshaller();
// 格式化xml输出的格式
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT,
Boolean.TRUE);
// 将对象转换成输出流形式的xml
// 创建输出流
FileWriter fw = null;
try {
fw = new FileWriter(path);
} catch (IOException e) {
e.printStackTrace();
}
marshaller.marshal(obj, fw);
} catch (JAXBException e) {
e.printStackTrace();
}
}
@SuppressWarnings("unchecked")
/**
* 将String类型的xml转换成对象
*/
public static Object convertXmlStrToObject(Class clazz, String xmlStr) {
String resultXml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n";
Object xmlObject = null;
try {
JAXBContext context = JAXBContext.newInstance(clazz);
// 进行将Xml转成对象的核心接口
Unmarshaller unmarshaller = context.createUnmarshaller();
StringReader sr = new StringReader(resultXml+xmlStr);
xmlObject = unmarshaller.unmarshal(sr);
} catch (JAXBException e) {
e.printStackTrace();
}
return xmlObject;
}
@SuppressWarnings("unchecked")
/**
* 将file类型的xml转换成对象
*/
public static Object convertXmlFileToObject(Class clazz, String xmlPath) {
Object xmlObject = null;
try {
JAXBContext context = JAXBContext.newInstance(clazz);
Unmarshaller unmarshaller = context.createUnmarshaller();
FileReader fr = null;
try {
fr = new FileReader(xmlPath);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
xmlObject = unmarshaller.unmarshal(fr);
} catch (JAXBException e) {
e.printStackTrace();
}
return xmlObject;
}
/**
* xml装换成JavaBean
* @param t
* @param xml
* @return
*/
@SuppressWarnings("unchecked")
public static<T> T converyToJavaBean(Class<T> t,String xml){
// 如果xml参数中有以下协议,则不需要再重复加
String resultXml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n";
T obj = null;
SAXParserFactory sax = null;
StringReader reader = null;
try {
JAXBContext context = JAXBContext.newInstance(t);
Unmarshaller unmarshaller = context.createUnmarshaller();
reader = new StringReader(resultXml+xml);
sax = SAXParserFactory.newInstance();
// sax.setXIncludeAware(false);
sax.setValidating(false);
// 忽略命名空间
sax.setNamespaceAware(false);
XMLReader xmlReader = sax.newSAXParser().getXMLReader();
Source source = new SAXSource(xmlReader, new InputSource(reader));
obj = (T) unmarshaller.unmarshal(source);
return obj;
} catch (Exception e) {
throw new RuntimeException(e.getMessage());
}finally {
if(reader!=null){
reader.close();
}
}
}
2. 举例
<send direction="outgoing" pono="66612345" client="direct" action="eftrequest" function="payment" companyno="1" printer-ready="1" storeno="1" testmode="0" requestid="4">
<accept>
<param id="amount" value="5500"/>
<param id="currency" value="978"/>
<param id="last-receipt-number" value="981"/>
<param id="shift" value="1"/>
<param id="ta-date" value="20141009"/>
<param id="ta-time" value="155735"/>
</accept>
</send>
import javax.xml.bind.annotation.*;
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "send")
public class Send {
@XmlElement(name = "accept")
private Accept accept;
@XmlAttribute(name = "direction")
private String direction;
@XmlAttribute(name = "pono")
private String pono;
@XmlAttribute(name = "client")
private String client;
@XmlAttribute(name = "action")
private String action;
@XmlAttribute(name = "function")
private String function;
@XmlAttribute(name = "companyno")
private String companyNo;
@XmlAttribute(name = "printer-ready")
private String printerReady;
@XmlAttribute(name = "storeno")
private String storeNo;
@XmlAttribute(name = "testmode")
private String testMode;
@XmlAttribute(name = "requestid")
private String requestId;
public Accept getAccept() {
return accept;
}
public void setAccept(Accept accept) {
this.accept = accept;
}
public String getDirection() {
return direction;
}
public void setDirection(String direction) {
this.direction = direction;
}
public String getPono() {
return pono;
}
public void setPono(String pono) {
this.pono = pono;
}
public String getClient() {
return client;
}
public void setClient(String client) {
this.client = client;
}
public String getAction() {
return action;
}
public void setAction(String action) {
this.action = action;
}
public String getFunction() {
return function;
}
public void setFunction(String function) {
this.function = function;
}
public String getCompanyNo() {
return companyNo;
}
public void setCompanyNo(String companyNo) {
this.companyNo = companyNo;
}
public String getPrinterReady() {
return printerReady;
}
public void setPrinterReady(String printerReady) {
this.printerReady = printerReady;
}
public String getStoreNo() {
return storeNo;
}
public void setStoreNo(String storeNo) {
this.storeNo = storeNo;
}
public String getTestMode() {
return testMode;
}
public void setTestMode(String testMode) {
this.testMode = testMode;
}
public String getRequestId() {
return requestId;
}
public void setRequestId(String requestId) {
this.requestId = requestId;
}
}
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import java.util.List;
@XmlAccessorType(XmlAccessType.FIELD)
public class Accept {
@XmlElement(name = "param")
private List<Param> param;
public List<Param> getParam() {
return param;
}
public void setParam(List<Param> param) {
this.param = param;
}
}
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
@XmlAccessorType(XmlAccessType.FIELD)
public class Param {
@XmlAttribute(name = "id")
public String id;
@XmlAttribute(name = "value")
public String value;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
Param param1 = new Param();
param1.setId("amount");
param1.setValue("5500");
Param param2 = new Param();
param2.setId("currency");
param2.setValue("978");
Param param3 = new Param();
param3.setId("last-receipt-number");
param3.setValue("981");
Param param4 = new Param();
param4.setId("shift");
param4.setValue("1");
Param param5 = new Param();
param5.setId("ta-date");
param5.setValue("20141009");
Param param6 = new Param();
param6.setId("ta-time");
param6.setValue("155735");
List<Param> param = new ArrayList<>();
param.add(param1);
param.add(param2);
param.add(param3);
param.add(param4);
param.add(param5);
param.add(param6);
Accept accept = new Accept();
accept.setParam(param);
Send send = new Send();
send.setAccept(accept);
send.setDirection("outgoing");
send.setPono("66612345");
send.setClient("direct");
send.setAction("eftrequest");
send.setFunction("payment");
send.setCompanyNo("1");
send.setStoreNo("1");
send.setPrinterReady("1");
send.setTestMode("0");
send.setRequestId("4");
String xml = XmlUtils.convertToXml(send);
System.out.println(xml);
3. 对象转XML报错及解决方案
com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 8 counts of IllegalAnnotationExceptions
类的两个属性具有相同名称 "orderName"
his problem is related to the following location:
at public java.lang.String com.xl.mall.entity.Order.getOrderName()
at com.xl.mall.entity.Order
this problem is related to the following location:
at private java.lang.String com.xl.mall.entity.Order.orderName
at com.xl.mall.entity.Order
实体类中的属性和Getter方法冲突,在class上注解@XmlAccessorType(XmlAccessType.FIELD)即可
4. XML转对象报错及解决方案
xml转换java bean可能报的异常javax.xml.bind.UnmarshalException: 意外的元素 (uri:"", local:"accept")。所需元素为<{}Send>
原因:
- java bean不符合xml文件的层级关系(例如:根目录没有@XmlRootElement注解,accept不是根目录等)
- xml字符串或文件中格式不正确(例如:没有根目录)
二、SAX
pom.xml
<dependency>
<groupId>org.dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>2.1.3</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
XmlUtil.java
import lombok.extern.slf4j.Slf4j;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.io.StringReader;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
@Slf4j
public class XmlUtil {
//${abc}正则
public static String varRegex = "\\$\\{\\s*(\\w+)\\s*(([\\+\\-])\\s*(\\d+)\\s*)?\\}";
/**
* xml解析成document对象
*
* @param xml
* @return
*/
public Document getDocument(String xml) {
StringReader stringReader = new StringReader(xml);
SAXReader saxReader = new SAXReader();
Document document = null;
try {
document = saxReader.read(stringReader);
} catch (DocumentException e) {
}
return document;
}
/**
* xml与bean的相互转换
*
* @param element
* @param direction 1:java2xml,2:xml2java
* @param obj
*/
public void parseXml(Element element, String direction, Object obj) {
//获取当前元素的所有子节点(在此我传入根元素)
List<Element> elements = element.elements();
//判断是否有子节点
if (elements != null && elements.size() > 0) {
//进入if说明有子节点
//遍历
for (Element e : elements) {
//判断转换方向(1:java2xml;2:xml2java)
if ("2".equals(direction)) //这里是xml转bean
{
//声明Field
Field field = null;
try {
//反射获取属性
field = obj.getClass().getDeclaredField(e.getName());
} catch (Exception e1) {
}
//获取当前属性是否为list
if (field != null && List.class.getName().equals(field.getType().getName())) {
//反射获取set方法
Method method = this.getDeclaredMethod(obj, "set".concat(this.toUpperCaseFirstOne(e.getName())), new Class[]{List.class});
//声明临时list
List temList = new ArrayList();
if (method != null) {
try {
//反射调用obj的当前方法,可变参数为templist
method.invoke(obj, temList);
} catch (Exception e1) {
log.info("【{}】方法执行失败", method, e1);
}
}
//获取List的泛型参数类型
Type gType = field.getGenericType();
//判断当前类型是否为参数化泛型
if (gType instanceof ParameterizedType) {
//转换成ParameterizedType对象
ParameterizedType pType = (ParameterizedType) gType;
//获得泛型类型的泛型参数(实际类型参数)
Type[] tArgs = pType.getActualTypeArguments();
if (tArgs != null && tArgs.length > 0) {
//获取当前元素的所有子元素
List<Element> elementSubList = e.elements();
//遍历
for (Element e1 : elementSubList) {
try {
//反射创建对象
Object tempObj = Class.forName(tArgs[0].getTypeName()).newInstance();
temList.add(tempObj);
//递归调用自身
this.parseXml(e1, direction, tempObj);
} catch (Exception e2) {
log.error("【{}】对象构造失败", tArgs[0].getTypeName(), e2);
}
}
}
}
} else {
//说明不是list标签,继续递归调用自身即可
this.parseXml(e, direction, obj);
}
} else if ("1".equals(direction)) //说明转换方向为:javabean转xml
{
//递归调用自身
this.parseXml(e, direction, obj);
}
//此时还在for循环遍历根元素的所有子元素
}
} else {
//说明无子节点
//获取当前元素的名称
String nodeName = element.getName();
//获取当前元素的对应的值
String nodeValue = element.getStringValue();
//判断转换方向:1:java2xml、2:xml2java
if ("1".equals(direction))//java2xml
{
if (nodeValue != null && nodeValue.matches(varRegex)) {
/**
* 获取模板中各节点定义的变量名,例如<traceNo>${traceNo}</traceNo>
*/
nodeValue = nodeValue.substring(nodeValue.indexOf("${") + 2, nodeValue.indexOf("}"));
Object value = null;
//根据解析出的变量名,调用obj对象的getXXX()方法获取变量值
Method method = this.getDeclaredMethod(obj, "get".concat(this.toUpperCaseFirstOne(nodeValue)), null);
if (method != null) {
try {
value = method.invoke(obj);
} catch (Exception e) {
log.error("方法【{}】调用异常", "get".concat(this.toUpperCaseFirstOne(nodeValue)));
}
}
//将变量值填充至xml模板变量名位置,例如<traceNo>${traceNo}</traceNo>
element.setText(value == null ? "" : value.toString());
}
//叶子节点
log.debug("节点名【{}】,节点变量名【{}】", element.getName(), nodeValue);
} else if ("2".equals(direction))//xml2java
{
if (nodeName != null && !"".equals(nodeName)) {
//根据xml节点名,调用obj对象的setXXX()方法为obj设置变量值
Method method = this.getDeclaredMethod(obj, "set".concat(this.toUpperCaseFirstOne(nodeName)), new Class[]{String.class});
if (method != null) {
try {
method.invoke(obj, nodeValue);
} catch (Exception e) {
log.error("方法【{}】调用异常", "set".concat(this.toUpperCaseFirstOne(nodeName)));
}
}
}
}
}
}
private Method getDeclaredMethod(Object object, String methodName, Class<?>[] parameterTypes) {
for (Class<?> superClass = object.getClass(); superClass != Object.class; superClass = superClass.getSuperclass()) {
try {
return superClass.getDeclaredMethod(methodName, parameterTypes);
} catch (NoSuchMethodException e) {
//Method 不在当前类定义, 继续向上转型
}
//..
}
return null;
}
private String toUpperCaseFirstOne(String s) {
// 进行字母的ascii编码前移,效率要高于截取字符串进行转换的操作
char[] cs = s.toCharArray();
cs[0] -= 32;
return String.valueOf(cs);
}
}
实体类
import lombok.Data;
import java.util.List;
@Data
public class RspSchool {
//学校编号
private String number;
//学校名称
private String name;
//学校省份
private String province;
//学校地址
private String address;
//多个学生
private List<Student> students;//模拟测试数据,返回多个学生
//省略get和set方法
}
import lombok.Data;
@Data
public class Student {
//学生班级
private String stuclass;
//学生姓名
private String stuname;
//学生分数
private String stuscore;
//省略set和get方法
}
Test.java
import com.alibaba.fastjson.JSON;
import org.dom4j.Document;
import org.dom4j.Element;
public class Test {
public static void main(String[] args) {
//定义响应报文
String responseXML="<?xml version=\"1.0\" encoding = \"GBK\"?>\n" +
"<SCHOOL>\n" +
"<number>0001</number>\n" +
"<name>xxx实验小学</name>\n" +
"<province>北京市</province>\n" +
"<address>西城区</address>\n" +
" <students>\n" +
" <student>\n" +
" <stuclass>高三二班</stuclass>\n" +
" <stuname>李四</stuname>\n" +
" <stuscore>100</stuscore>\n" +
" </student>\n" +
" <student>\n" +
" <stuclass>高三三班</stuclass>\n" +
" <stuname>张三</stuname>\n" +
" <stuscore>95</stuscore>\n" +
" </student>\n" +
" <student>\n" +
" <stuclass>高三四班</stuclass>\n" +
" <stuname>王五</stuname>\n" +
" <stuscore>0</stuscore>\n" +
" </student>\n" +
" </students>\n" +
"</SCHOOL>";
//这里我直接使用构造方法(实际开发应以线程安全的单例模式)
XmlUtil xmlUtil = new XmlUtil();
Document document = xmlUtil.getDocument(responseXML);
Element rootElement = document.getRootElement();
RspSchool rspSchool = new RspSchool();
xmlUtil.parseXml(rootElement,"2",rspSchool);
System.out.println(JSON.toJSONString(rspSchool));
}
}
三、Android的xml pull解析
pom.xml
<dependency>
<groupId>xmlpull</groupId>
<artifactId>xmlpull</artifactId>
<version>1.1.3.1</version>
</dependency>
XmlParseUtil.java
import java.io.Reader;
import java.io.StringReader;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserFactory;
public class XmlParseUtil {
public static Map<String,String> xmlParse(Reader reader){
Map<String,String> map = new HashMap<>();
try {
// 获得一个XmlPullParser解析器
XmlPullParser newPullParser = XmlPullParserFactory.newInstance().newPullParser();
// 设置解析输入流
// 解析xml文件:parse.setInput(new FileInputStream("receive.xml"),"UTF-8");
// 解析字符串:parse.setInput(new StringReader(text));
newPullParser.setInput(reader);
// 获取当前事件类型
int eventType = newPullParser.getEventType();
/*
文档开始标识
public static final int START_DOCUMENT = 0;
文档结束标识
public static final int END_DOCUMENT = 1;
标签开始标识
public static final int START_TAG = 2;
标签结束标识
public static final int END_TAG = 3;
*/
// 判断当前事件类型
while(eventType!=XmlPullParser.END_DOCUMENT){
// 当前标签的名字
String name = newPullParser.getName();
if(!"xml".equals(name)&&eventType==XmlPullParser.START_TAG){
// 当前标签对应的值
String nextText = newPullParser.nextText();
map.put(name, nextText);
}
// 改变当前的eventType
eventType=newPullParser.next();
}
} catch (Exception e) {
e.printStackTrace();
}
return map;
}
// 测试代码
public static void main(String[] args) {
String xml = "<xml><ToUserName><![CDATA[gh_55e547acb71e]]></ToUserName>"
+ "<FromUserName><![CDATA[o9cEf0iZn8aKK4-MKWmqO2fs36xE]]></FromUserName>"
+ "<CreateTime>1505114547</CreateTime>" + "<MsgType><![CDATA[text]]></MsgType>"
+ "<Content><![CDATA[这是一个测试]]></Content>" + "<MsgId>6464417756529124601</MsgId>" + "</xml>";;
Map<String, String> map = XmlParseUtil.xmlParse(new StringReader(xml));
Set<Entry<String,String>> entrySet = map.entrySet();
for (Entry<String, String> entry : entrySet) {
System.out.println(entry.getKey()+" : "+entry.getValue());
}
}
}
import com.alibaba.fastjson.JSON;
import com.example.demo.dto.Init;
import com.example.demo.socket.Accept;
import com.example.demo.socket.Param;
import com.example.demo.socket.Receive;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Administrator on 2017/7/11.
*/
public class PullparseXml {
public static Init initXmlToJavaBean(String text) throws IOException, XmlPullParserException {
//1.导入pull驱动
//2.创建pull解析工厂
XmlPullParserFactory factory= XmlPullParserFactory.newInstance();
//3.创建pull解析器
XmlPullParser parse=factory.newPullParser();
//4.设置输入流
// parse.setInput(new FileInputStream("receive.xml"),"utf-8");
//4.设置字符串
parse.setInput(new StringReader(text));
//存储事件类型
int eventType=-99;
Receive receive = null;
Param param = null;
Accept accept = new Accept();
List<Param> params = null;
Init init = new Init();
//遍历XML文档
while ((eventType=parse.getEventType())!=XmlPullParser.END_DOCUMENT){
//获取元素的名称
String elementName=parse.getName();
//判断元素是否是开始元素
if(eventType==XmlPullParser.START_TAG){
//当读取到事件的类型为start_tag时且元素名称为books的时候创建集合对象
if("receive".equals(elementName)){
//创建集合对象
// books=new ArrayList<Book>();
}else if("accept".equals(elementName)){
//第一个参数:表示命名空间
//第二个参数:XML文档中元素的属性名称
// String isbn=parse.getAttributeValue(null,"isbn");
// book.setIsbn(isbn);
param = new Param();
params = new ArrayList<>();
}else if("param".equals(elementName)){
String id = parse.getAttributeValue(0);
String value = parse.getAttributeValue(1);
System.out.println(id);
if("answer-code".equals(id)){
init.setAnswerCode(value);
}
if("answer-txt".equals(id)){
init.setAnswerTxt(value);
}
if("answer-txt-spez".equals(id)){
init.setAnswerTxtSpez(value);
}
if("asynchronous".equals(id)){
init.setAsynchronous(value);
}
if("channel-name".equals(id)){
init.setChannelName(value);
}
if("codetable".equals(id)){
init.setCodetable(value);
}
if("currency".equals(id)){
init.setCurrency(value);
}
if("currency-exp".equals(id)){
init.setCurrencyExp(value);
}
if("customer-codetable".equals(id)){
init.setCustomerCodetable(value);
}
if("force-print".equals(id)){
init.setForcePrint(value);
}
if("language".equals(id)){
init.setLanguage(value);
}
if("merchant_language".equals(id)){
init.setMerchant_language(value);
}
if("mti".equals(id)){
init.setMti(value);
}
if("receipt".equals(id)){
init.setReceipt(value);
}
if("receipt-copies".equals(id)){
init.setReceiptCopies(value);
}
if("shift".equals(id)){
init.setShift(value);
}
if("ta-date".equals(id)){
init.setTaDate(value);
}
if("ta-time".equals(id)){
init.setTaTime(value);
}
if("terminal-id".equals(id)){
init.setTerminalId(value);
}
// param.setId(id);
// param.setValue(value);
// params.add(param);
}
}else if(eventType==XmlPullParser.END_TAG){
//表示结束元素
if("receive".equals(elementName)){
accept.setParam(params);
}
}
parse.next();
}
// System.out.println(JSON.toJSON(accept));
System.out.println(JSON.toJSON(init));
return init;
}
}