事情处理结果
直接将命名空间给replace掉
xml.replace("xmlns=\"http://www.aaa.bb.ccc\"", "")
起因
因为系统对接需要,现在需要将一段xml解析出来,虽然可以使用dom方式去解析,但是总感觉很麻烦,想通过jaxb的这种方式,直接将xml映射到JavaBean上,通过get和set去取对应的值,感觉这样比较顺手,所以直接开干
同事不知道从哪借鉴(抄)过来一个工具类,代码如下
package net.wdm.tools.xml;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author heshengchao@qq.com
* @since 2013-7-26 下午4:41:53
*/
public class XmlConvert {
private static final Logger log = LoggerFactory.getLogger(XmlConvert.class);
public static XmlConvert instance = new XmlConvert();
private static final Map<Class<?>, Marshaller> JAXB_MARSHALL_MAP = Collections
.synchronizedMap(new HashMap<Class<?>, Marshaller>());
private static final Map<Class<?>, Unmarshaller> JAXB_UNMARSHALL_MAP = Collections
.synchronizedMap(new HashMap<Class<?>, Unmarshaller>());
/**
* @param xml
* @param clazz
* @return
*/
@SuppressWarnings("unchecked")
public <X> X toBean(String xml, Class<X> clazz) {
try {
JAXBContext context = JAXBContext.newInstance(clazz);
Unmarshaller unmarshaller = context.createUnmarshaller();
StringReader sw = new StringReader(xml);
return (X) unmarshaller.unmarshal(sw);
} catch (Exception e) {
log.warn("异常对象:" + xml);
log.error(e.getMessage(), e);
JAXB_UNMARSHALL_MAP.put(clazz, null);
}
return null;
}
@SuppressWarnings("unchecked")
public <X> X toBean(InputStream xmlStream, Class<X> clazz) {
try {
Unmarshaller msl = JAXB_UNMARSHALL_MAP.get(clazz);
if (msl == null) {
JAXBContext context = JAXBContext.newInstance(clazz);
msl = context.createUnmarshaller();
JAXB_UNMARSHALL_MAP.put(clazz, msl);
}
synchronized (msl) {
return (X) msl.unmarshal(xmlStream);
}
} catch (Exception e) {
log.error(e.getMessage(), e);
// 解决出现异常后,该信息一直出现的问题
JAXB_UNMARSHALL_MAP.put(clazz, null);
}
return null;
}
/**
* @param bean
* @return
*/
public String toXML(Object bean) {
if (bean == null) {
log.error("传入对象为空!请检查程序。");
return null;
}
try {
Marshaller msl = JAXB_MARSHALL_MAP.get(bean.getClass());
if (msl == null) {
JAXBContext context = JAXBContext.newInstance(bean.getClass());
msl = context.createMarshaller();
msl.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
JAXB_MARSHALL_MAP.put(bean.getClass(), msl);
}
StringWriter sw = new StringWriter();
synchronized (msl) {
msl.marshal(bean, sw);
}
return sw.toString();
} catch (Exception e) {
log.error(e.getMessage(), e);
// 解决出现异常后,该信息一直出现的问题
JAXB_MARSHALL_MAP.put(bean.getClass(), null);
}
return null;
}
/**
* @param bean
* @return
*/
public void toXML(Object bean, OutputStream out) {
try {
Marshaller msl = JAXB_MARSHALL_MAP.get(bean.getClass());
if (msl == null) {
JAXBContext context = JAXBContext.newInstance(bean.getClass());
msl = context.createMarshaller();
// 是否格式化生成的字符串
msl.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
JAXB_MARSHALL_MAP.put(bean.getClass(), msl);
}
synchronized (msl) {
msl.marshal(bean, out);
}
} catch (JAXBException e) {
log.error(e.getMessage(), e);
// 解决出现异常后,该信息一直出现的问题
JAXB_MARSHALL_MAP.put(bean.getClass(), null);
}
}
}
因为有public <X> X toBean(InputStream xmlStream, Class<X> clazz)
这个方法,感觉toBean是个很容易的事情,事实上并没有这么简单
经过
首先,我有两个类
package com.wdm.pang.entity.xintong.IOrder;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "CEB312Message", namespace = "http://www.aaa.bb.ccc")
public class CEB312Message {
@XmlElement(name = "OrderReturn")
private OrderReturn orderReturn;
public OrderReturn getOrderReturn() {
return this.orderReturn;
}
public void setOrderReturn(OrderReturn orderReturn) {
this.orderReturn = orderReturn;
}
@Override
public String toString() {
return "CEB312Message [orderReturn=" + orderReturn + "]";
}
}
package com.wdm.pang.entity.xintong.IOrder;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "OrderReturn")
public class OrderReturn {
@XmlElement(name = "guid")
private String guid;
@XmlElement(name = "ebpCode")
private String ebpCode;
@XmlElement(name = "ebcCode")
private String ebcCode;
@XmlElement(name = "orderNo")
private String orderNo;
@XmlElement(name = "returnStatus")
private Integer returnStatus;
@XmlElement(name = "returnTime")
private String returnTime;
@XmlElement(name = "returnInfo")
private String returnInfo;
public String getGuid() {
return this.guid;
}
public void setGuid(String guid) {
this.guid = guid;
}
public String getEbpCode() {
return this.ebpCode;
}
public void setEbpCode(String ebpCode) {
this.ebpCode = ebpCode;
}
public String getEbcCode() {
return this.ebcCode;
}
public void setEbcCode(String ebcCode) {
this.ebcCode = ebcCode;
}
public String getOrderNo() {
return this.orderNo;
}
public void setOrderNo(String orderNo) {
this.orderNo = orderNo;
}
public Integer getReturnStatus() {
return returnStatus;
}
public void setReturnStatus(Integer returnStatus) {
this.returnStatus = returnStatus;
}
public String getReturnTime() {
return this.returnTime;
}
public void setReturnTime(String returnTime) {
this.returnTime = returnTime;
}
public String getReturnInfo() {
return this.returnInfo;
}
public void setReturnInfo(String returnInfo) {
this.returnInfo = returnInfo;
}
@Override
public String toString() {
return "OrderReturn [guid=" + guid + ", ebpCode=" + ebpCode + ", ebcCode=" + ebcCode + ", orderNo=" + orderNo
+ ", returnStatus=" + returnStatus + ", returnTime=" + returnTime + ", returnInfo=" + returnInfo + "]";
}
}
然后我有一个字符串:
<?xml version="1.0" encoding="UTF-8" xmlns="http://www.aaa.bb.ccc" ? >
<OrderReturn>
<guid>83B32909-6855-46BD-ACED-B153BC252446</guid>
<ebpCode>1</ebpCode>
<ebcCode>1</ebcCode>
<orderNo>1</orderNo>
<returnStatus>5</returnStatus>
<returnTime>20180926165332552</returnTime>
<returnInfo>预处理成功</returnInfo>
</OrderReturn>
按照我正常的思路,只需要这样CEB312Message message = XmlConvert.instance.toBean(xml, CEB312Message.class);
message对象里面就会有值,然而并不是,System.out.println(message );
的结果只是CEB312Message [orderReturn=null]
,那么问题就来了,究竟是什么原因导致的呢?
抱着疑问,我把原来的类上的注解@XmlRootElement(name = "CEB312Message", namespace = "http://www.aaa.bb.ccc")
中的命名空间删除,直接改为@XmlRootElement(name = "CEB312Message")
,然后就可以了么?不,事情并没有那么简单,报错了。。。
javax.xml.bind.UnmarshalException: 意外的元素 (uri:"http://www.aaa.bb.ccc", local:"CEB312Message")。所需元素为<{}CEB312Message>,<{}OrderReturn>
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.handleEvent(UnmarshallingContext.java:726)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.Loader.reportError(Loader.java:247)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.Loader.reportError(Loader.java:242)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.Loader.reportUnexpectedChildElement(Loader.java:109)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext$DefaultRootLoader.childElement(UnmarshallingContext.java:1131)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext._startElement(UnmarshallingContext.java:556)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.startElement(UnmarshallingContext.java:538)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.SAXConnector.startElement(SAXConnector.java:153)
at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.startElement(AbstractSAXParser.java:509)
at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.scanStartElement(XMLNSDocumentScannerImpl.java:374)
at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl$NSContentDriver.scanRootElementHook(XMLNSDocumentScannerImpl.java:613)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(XMLDocumentFragmentScannerImpl.java:3132)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$PrologDriver.next(XMLDocumentScannerImpl.java:852)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:602)
at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:112)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:505)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:841)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:770)
at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:141)
at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1213)
at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:643)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:243)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:214)
at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:157)
at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:214)
at com.wdm.pang.controller.entity.dto.Test.toBean(Test.java:72)
at com.wdm.pang.controller.entity.dto.Test.main(Test.java:41)
那怎么办呢,改回去吧。
我又在想,难道是我的JavaBean注解没对?
那我从Bean生成一个xml对比一下看看效果先,于是乎一把梭
CEB312Message ceb312Message = new CEB312Message();
CEB312Message stringToObject = XmlConvert.instance.toBean(back, CEB312Message.class);
System.out.println(stringToObject);
OrderReturn orderReturn = new OrderReturn();
orderReturn.setGuid("83B32909-6855-46BD-ACED-B153BC252446");
orderReturn.setEbcCode("1");
orderReturn.setEbpCode("1");
orderReturn.setOrderNo("1");
orderReturn.setReturnInfo("预处理成功");
orderReturn.setReturnStatus(5);
orderReturn.setReturnTime("20180926165332552");
ceb312Message.setOrderReturn(orderReturn);
String xml = XmlConvert.instance.toXML(ceb312Message);
System.out.println(xml);
-----------------------输出结果-----------------------------
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:CEB312Message xmlns:ns2="http://www.aaa.bb.ccc">
<OrderReturn>
<guid>83B32909-6855-46BD-ACED-B153BC252446</guid>
<ebpCode>1</ebpCode>
<ebcCode>1</ebcCode>
<orderNo>1</orderNo>
<returnStatus>5</returnStatus>
<returnTime>20180926165332552</returnTime>
<returnInfo>预处理成功</returnInfo>
</OrderReturn>
</ns2:CEB312Message>
那么问题又来了,这个ns2:是个什么鬼,好像我也没有什么地方写了这个东西啊,真是头大,一顿疯狂的百度,然后找到下面的这些资料:
这些资料都写的很好,非常有效的解决了ns2:这个前缀问题,然而我的目的并不是要生成xml,我的初衷是要去解析xml到javaBean
所以,我又回到了正题,既然我是因为namespace的问题导致的解析不正确问题,那我可不可以不要这个namespace,直接删掉试试,于是就有了如下代码:
CEB312Message ceb312Message = XmlConvert.instance.toBean(xml.replace("xmlns=\"http://www.chinaport.gov.cn/ceb\"", ""),CEB312Message.class);
System.out.println(ceb312Message);
----------------------输出结果---------------------------
CEB312Message [orderReturn=OrderReturn [guid=83B32909-6855-46BD-ACED-B153BC252446, ebpCode=1, ebcCode=1, orderNo=1, returnStatus=5, returnTime=20180926165332552, returnInfo=预处理成功]]
然后居然有值了,emmmm简直是。
附上Maven引用
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-core</artifactId>
<version>2.2.11</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.3.0.1</version>
</dependency>
虽然这个方法太草率了,先将就用着,毕竟时间紧任务重,如果有大佬做过,并且很好的解决了这个问题,欢迎留言告诉我,3Q