Java JAXB:将不同的XML元素封送到一个类或从一个类中封送/取消封送
比方说,我有以下课程:Java JAXB:将不同的XML元素封送到一个类或从一个类中封送/取消封送,java,xml,jaxb,marshalling,xmlbeans,Java,Xml,Jaxb,Marshalling,Xmlbeans,比方说,我有以下课程: @XmlRootElement class Payment { @XmlElement int amount; @XmlElement Currency currency; @XmlElement IResponse response; } 如果response==null,则元素为“请求”,否则-元素为“响应”。请求时,当响应-to(from)PaymentResponse时,元素应(取消)封送到(从)名为Paymen
@XmlRootElement
class Payment {
@XmlElement
int amount;
@XmlElement
Currency currency;
@XmlElement
IResponse response;
}
如果response==null
,则元素为“请求”,否则-元素为“响应”。请求时,当响应-to(from)PaymentResponse
时,元素应(取消)封送到(从)名为PaymentRequest
的根元素
如何配置这种封送处理算法?如果JAXB做不到,也许其他引擎可以?创建并封送根元素,如下所示:
JAXBElement<Payment> jbe;
if( payment.getResponse() != null ){
jbe = wrap( null, "PaymentResponse", payment );
} else {
jbe = wrap( null, "PaymentRequest", payment );
}
m.marshal( jbe, sw );
JAXBElement-jbe;
if(payment.getResponse()!=null){
jbe=wrap(null,“PaymentResponse”,付款);
}否则{
jbe=wrap(null,“PaymentRequest”,付款);
}
m、 元帅(jbe,西南);
使用简单助手方法
<T> JAXBElement<T> wrap( String ns, String tag, T o ){
QName qtag = new QName( ns, tag );
Class<?> clazz = o.getClass();
@SuppressWarnings( "unchecked" )
JAXBElement<T> jbe = new JAXBElement( qtag, clazz, o );
return jbe;
}
JAXBElement包装(字符串ns、字符串标记、to){
QName qtag=新的QName(ns,标签);
Class clazz=o.getClass();
@抑制警告(“未选中”)
JAXBElement jbe=新的JAXBElement(qtag、clazz、o);
返回jbe;
}
使解组成为可能的一种简单方法是创建两个子类PaymentResponse和PaymentRequest,它们充当@XmlRootElements。ObjectFactory包含
@XmlElementDecl(namespace = "", name = "PaymentRequest")
public JAXBElement<PaymentRequest>
createPaymentRequest(PaymentRequest value) {
return new JAXBElement<PaymentRequest>(_Payment_QNAME, PaymentRequest.class, null, value);
}
@XmlElementDecl(namespace = "", name = "PaymentResponse")
public JAXBElement<PaymentResponse>
createPaymentResponse(PaymentResponse value) {
return new JAXBElement<PaymentResponse>(_Payment_QNAME, PaymentResponse.class, null, value);
}
@xmlementdecl(namespace=”“,name=“PaymentRequest”)
公共交通
createPaymentRequest(PaymentRequest值){
返回新的JAXBElement(_Payment_QNAME,PaymentRequest.class,null,value);
}
@xmlementdecl(名称空间=”,name=“PaymentResponse”)
公共交通
createPaymentResponse(PaymentResponse值){
返回新的JAXBElement(_Payment_QNAME,PaymentResponse.class,null,value);
}
解组:
JAXBContext jc = JAXBContext.newInstance( PACKAGE );
Unmarshaller m = jc.createUnmarshaller();
JAXBElement<?> tb = null;
try {
Payment payment = readFrom( Payment.class );
} catch( Exception e ){
}
JAXBContext jc=JAXBContext.newInstance(包);
解组器m=jc.createUnmarshaller();
JAXBElement tb=null;
试一试{
Payment Payment=读取自(Payment.class);
}捕获(例外e){
}
以及从中读取的方法:
public <T> T readFrom( Class<T> type ) throws Exception {
try {
JAXBContext jc = JAXBContext.newInstance( PACKAGE );
Unmarshaller u = jc.createUnmarshaller();
JAXBElement<T> jbe = (JAXBElement<T>)u.unmarshal( new File( XMLIN ) );
return type.cast( jbe.getValue() );
} catch (JAXBException e) {
e.printStackTrace();
}
return null;
}
public T readFrom(类类型)引发异常{
试一试{
JAXBContext jc=JAXBContext.newInstance(包);
解组器u=jc.createUnmarshaller();
JAXBElement jbe=(JAXBElement)u.unmarshal(新文件(XMLIN));
返回类型.cast(jbe.getValue());
}捕获(JAXBEException e){
e、 printStackTrace();
}
返回null;
}
创建并封送根元素,如下所示:
JAXBElement<Payment> jbe;
if( payment.getResponse() != null ){
jbe = wrap( null, "PaymentResponse", payment );
} else {
jbe = wrap( null, "PaymentRequest", payment );
}
m.marshal( jbe, sw );
JAXBElement-jbe;
if(payment.getResponse()!=null){
jbe=wrap(null,“PaymentResponse”,付款);
}否则{
jbe=wrap(null,“PaymentRequest”,付款);
}
m、 元帅(jbe,西南);
使用简单助手方法
<T> JAXBElement<T> wrap( String ns, String tag, T o ){
QName qtag = new QName( ns, tag );
Class<?> clazz = o.getClass();
@SuppressWarnings( "unchecked" )
JAXBElement<T> jbe = new JAXBElement( qtag, clazz, o );
return jbe;
}
JAXBElement包装(字符串ns、字符串标记、to){
QName qtag=新的QName(ns,标签);
Class clazz=o.getClass();
@抑制警告(“未选中”)
JAXBElement jbe=新的JAXBElement(qtag、clazz、o);
返回jbe;
}
使解组成为可能的一种简单方法是创建两个子类PaymentResponse和PaymentRequest,它们充当@XmlRootElements。ObjectFactory包含
@XmlElementDecl(namespace = "", name = "PaymentRequest")
public JAXBElement<PaymentRequest>
createPaymentRequest(PaymentRequest value) {
return new JAXBElement<PaymentRequest>(_Payment_QNAME, PaymentRequest.class, null, value);
}
@XmlElementDecl(namespace = "", name = "PaymentResponse")
public JAXBElement<PaymentResponse>
createPaymentResponse(PaymentResponse value) {
return new JAXBElement<PaymentResponse>(_Payment_QNAME, PaymentResponse.class, null, value);
}
@xmlementdecl(namespace=”“,name=“PaymentRequest”)
公共交通
createPaymentRequest(PaymentRequest值){
返回新的JAXBElement(_Payment_QNAME,PaymentRequest.class,null,value);
}
@xmlementdecl(名称空间=”,name=“PaymentResponse”)
公共交通
createPaymentResponse(PaymentResponse值){
返回新的JAXBElement(_Payment_QNAME,PaymentResponse.class,null,value);
}
解组:
JAXBContext jc = JAXBContext.newInstance( PACKAGE );
Unmarshaller m = jc.createUnmarshaller();
JAXBElement<?> tb = null;
try {
Payment payment = readFrom( Payment.class );
} catch( Exception e ){
}
JAXBContext jc=JAXBContext.newInstance(包);
解组器m=jc.createUnmarshaller();
JAXBElement tb=null;
试一试{
Payment Payment=读取自(Payment.class);
}捕获(例外e){
}
以及从中读取的方法:
public <T> T readFrom( Class<T> type ) throws Exception {
try {
JAXBContext jc = JAXBContext.newInstance( PACKAGE );
Unmarshaller u = jc.createUnmarshaller();
JAXBElement<T> jbe = (JAXBElement<T>)u.unmarshal( new File( XMLIN ) );
return type.cast( jbe.getValue() );
} catch (JAXBException e) {
e.printStackTrace();
}
return null;
}
public T readFrom(类类型)引发异常{
试一试{
JAXBContext jc=JAXBContext.newInstance(包);
解组器u=jc.createUnmarshaller();
JAXBElement jbe=(JAXBElement)u.unmarshal(新文件(XMLIN));
返回类型.cast(jbe.getValue());
}捕获(JAXBEException e){
e、 printStackTrace();
}
返回null;
}
我终于通过拦截StAX事件实现了解组。代码如下:
JAXBContext jc = JAXBContext.newInstance(RootElement.class, A.class, B.class, C.class, D.class, E.class);
Unmarshaller unmarsh = jc.createUnmarshaller();
XMLStreamReader xs = XMLInputFactory.newInstance().createXMLStreamReader(new StringReader(etalonRs));
XMLStreamReader xd = new StreamReaderDelegate(xs) {
public static final String ROOT_ELEMENT = "TestRoot";
public static final int REPLACEABLE_LEVEL = 2;
public final Collection<String> sufficesToDelete = Arrays.asList("Rq", "Rs");
protected Stack<String> elementNamesStack = new Stack<>();
protected Set<String> replaceableNames = new HashSet<>();
@Override
public String getLocalName() {
String realName = super.getLocalName();
if (replaceableNames.contains(realName) && elementNamesStack.size() == REPLACEABLE_LEVEL) {
for (String suffix : sufficesToDelete) {
if (realName.endsWith(suffix)) {
return realName.substring(0, realName.lastIndexOf(suffix));
}
}
}
return realName;
}
@Override
public int next() throws XMLStreamException {
final int eventCode = super.next();
processLevel(eventCode);
return eventCode;
}
@Override
public int nextTag() throws XMLStreamException {
final int eventCode = super.nextTag();
processLevel(eventCode);
return eventCode;
}
private void processLevel(int eventCode) {
switch (eventCode) {
case XMLStreamReader.START_ELEMENT:
final String origElementName = super.getLocalName();
if ((elementNamesStack.size() + 1) == REPLACEABLE_LEVEL && elementNamesStack.peek().equals(ROOT_ELEMENT))
replaceableNames.add(origElementName);
elementNamesStack.push(origElementName);
break;
case XMLStreamReader.END_ELEMENT:
assert(elementNamesStack.pop().equals(super.getLocalName()));
break;
}
}
};
Object o = unmarsh.unmarshal(xd);
封送处理可以以相同的方式实现,但您必须从头开始编写“StreamWriterDelegate”。我终于通过拦截StAX事件实现了封送处理。代码如下:
JAXBContext jc = JAXBContext.newInstance(RootElement.class, A.class, B.class, C.class, D.class, E.class);
Unmarshaller unmarsh = jc.createUnmarshaller();
XMLStreamReader xs = XMLInputFactory.newInstance().createXMLStreamReader(new StringReader(etalonRs));
XMLStreamReader xd = new StreamReaderDelegate(xs) {
public static final String ROOT_ELEMENT = "TestRoot";
public static final int REPLACEABLE_LEVEL = 2;
public final Collection<String> sufficesToDelete = Arrays.asList("Rq", "Rs");
protected Stack<String> elementNamesStack = new Stack<>();
protected Set<String> replaceableNames = new HashSet<>();
@Override
public String getLocalName() {
String realName = super.getLocalName();
if (replaceableNames.contains(realName) && elementNamesStack.size() == REPLACEABLE_LEVEL) {
for (String suffix : sufficesToDelete) {
if (realName.endsWith(suffix)) {
return realName.substring(0, realName.lastIndexOf(suffix));
}
}
}
return realName;
}
@Override
public int next() throws XMLStreamException {
final int eventCode = super.next();
processLevel(eventCode);
return eventCode;
}
@Override
public int nextTag() throws XMLStreamException {
final int eventCode = super.nextTag();
processLevel(eventCode);
return eventCode;
}
private void processLevel(int eventCode) {
switch (eventCode) {
case XMLStreamReader.START_ELEMENT:
final String origElementName = super.getLocalName();
if ((elementNamesStack.size() + 1) == REPLACEABLE_LEVEL && elementNamesStack.peek().equals(ROOT_ELEMENT))
replaceableNames.add(origElementName);
elementNamesStack.push(origElementName);
break;
case XMLStreamReader.END_ELEMENT:
assert(elementNamesStack.pop().equals(super.getLocalName()));
break;
}
}
};
Object o = unmarsh.unmarshal(xd);
封送处理可以以相同的方式实现,但您必须从头开始编写“StreamWriterDelegate”。谢谢!然而,我在这里看到两个问题。在封送处理期间,必须显式指定根元素的名称。要实现解组,您需要更改类的结构(通过为请求和响应创建不同的类)——不幸的是,我不能这样做。因此,我找到了另一个解决方案,请看下一个答案。请求和响应的“不同类”不会影响应用程序的其余部分,它们在其他地方不可见。谢谢!然而,我在这里看到两个问题。在封送处理期间,必须显式指定根元素的名称。要实现解组,您需要更改类的结构(通过为请求和响应创建不同的类)——不幸的是,我不能这样做。因此,我找到了另一个解决方案,请看下一个答案。请求和响应的“不同类”不会影响应用程序的其余部分,它们在其他地方不可见。