获取XML中未在XSD中指定的属性 – JAXB

huangapple go评论69阅读模式
英文:

JAXB - getting attributes from XML that not specified in XSD

问题

下午好,

在我的服务中,我必须调用一个下游服务,其SOAP响应包含许多属性,如下所示:

<section name="AA1">
<grp name="..." AB1001="1.5" AB1002="..." .../>
<grp name="..." CD1001="1.5" CD1F002="..." .../>
...
</section>
<section name="AB1">
<grp name="..." AB1001="1.5" AB1002="..." .../>
<grp name="..." CD1001="1.5" CD1F002="..." .../>
...
</section>
<section name="AB2">
...
</section>
...

在我的服务的响应中,我必须检索相同的结构。然而,由于属性的数量庞大,所以我认为不会将所有这些属性添加到我的服务的XSD中,而是会在下游服务的响应中遍历属性,并将我找到的任何属性添加到我的服务的SOAP响应中。

困难在于,我使用JAXB,因此Java XML bean是从XSD生成的。由于XML属性不在我的服务的XSD中,所以我应该以一种'手动'的方式(在JAXB bean被编组为XML(SOAP响应)之后)添加它们。

请问是否有一种方法可以做到这一点?

我使用Spring和Spring Integration。

出站网关配置如下:

@Configuration
public class MppWebServiceGatewayConfig {

...

@Bean(name=&quot;serviceOutboundGateway&quot;)
public MessageHandler serviceOutboundGateway() {
	final MarshallingWebServiceOutboundGateway gateway = new ExceptionHandlingMarshallingWebServiceOutboundGateway(url, mppMarshaller(), mppUnMarshaller());
	gateway.setMessageSender(httpPoolingWebServiceMessageSender);
	return gateway;
}

@Bean
public Marshaller mppMarshaller() {
	final Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
	marshaller.setContextPath(CONTEXTPATH);
	return  marshaller;
}

@Bean
public Unmarshaller mppUnMarshaller() {
	final Jaxb2Marshaller unmarshaller = new Jaxb2Marshaller();
	unmarshaller.setContextPath(CONTEXTPATH);
	return  unmarshaller;
}

...

}

谢谢!

英文:

Good afternoon,

In my service I have to call a downstream service whose SOAP response contains lots of attributes like

&lt;section name=&quot;AA1&quot;&gt;
	&lt;grp name=&quot;...&quot; AB1001=&quot;1.5&quot; AB1002=&quot;...&quot; .../&gt;
	&lt;grp name=&quot;...&quot; CD1001=&quot;1.5&quot; CD1F002=&quot;...&quot; .../&gt;
	...
&lt;/section&gt;
&lt;section name=&quot;AB1&quot;&gt;
	&lt;grp name=&quot;...&quot; AB1001=&quot;1.5&quot; AB1002=&quot;...&quot; .../&gt;
	&lt;grp name=&quot;...&quot; CD1001=&quot;1.5&quot; CD1F002=&quot;...&quot; .../&gt;
	...
&lt;/section&gt;
&lt;section name=&quot;AB2&quot;&gt;
	...
&lt;/section&gt;
...

In my service's response I have to retrieve this same structure.
However as the number of the attributes are enormous so I thought I won't add all these attributes to my service's XSD but I'll go through the attributes in the response of the downstream service and whatever I'll find there will add them to my service's SOAP response.

The difficulty is that I use JAXB so Java XML beans are generated from the XSD. As the XML attributes are not in my service's XSD so somehow I should add them 'manually' (after the JAXB beans marshalled to XML (SOAP response)).

Is there a way of doing that please?

I use Spring & Spring Integration.

The outbound gateway is specified like

@Configuration
public class MppWebServiceGatewayConfig {

	...
	
	@Bean(name=&quot;serviceOutboundGateway&quot;)
	public MessageHandler serviceOutboundGateway() {
		final MarshallingWebServiceOutboundGateway gateway = new ExceptionHandlingMarshallingWebServiceOutboundGateway(url, mppMarshaller(), mppUnMarshaller());
		gateway.setMessageSender(httpPoolingWebServiceMessageSender);
		return gateway;
	}

	@Bean
	public Marshaller mppMarshaller() {
		final Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
		marshaller.setContextPath(CONTEXTPATH);
		return  marshaller;
	}

	@Bean
	public Unmarshaller mppUnMarshaller() {
		final Jaxb2Marshaller unmarshaller = new Jaxb2Marshaller();
		unmarshaller.setContextPath(CONTEXTPATH);
		return  unmarshaller;
	}

	...
}

Thanks!

答案1

得分: 0

我可能找到了一个答案,但它不够优雅,所以一般我不建议使用它,但有人可能会发现它有用:

@EnableWs
@Configuration
public class WebServiceConfig extends CommonWsConfigurerAdapter {

	...

	@Override
	public void addInterceptors(List<EndpointInterceptor> interceptors) {
		interceptors.add(new CustomEndpointInterceptor());
	}
}


@Component
class CustomEndpointInterceptor implements EndpointInterceptor {

	...
	
	@Override
	public boolean handleResponse(MessageContext messageContext, Object endpoint) throws Exception {
		String responseXmlString = toString(messageContext.getResponse());
		Document doc = convertStringToDocument(responseXmlString);

		// manipulting the response
		...

		// SaajSoapMessageFactory is thread safe so make sure the message factory is initialized only once
		SaajSoapMessageFactory saajSoapMessageFactory = new SaajSoapMessageFactory();
		saajSoapMessageFactory.afterPropertiesSet();
		
		SaajSoapMessage saajSoapMessage = saajSoapMessageFactory.createWebServiceMessage();
		saajSoapMessage.setDocument(doc);
		
		messageContext.clearResponse();
		messageContext.setResponse(saajSoapMessage);
		return true;
	}

	...

	private String toString(WebServiceMessage msg) throws IOException {
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		msg.writeTo(out);
		return new String(out.toByteArray());
	}

	private Document convertStringToDocument(String xmlStr) throws Exception {
        // also the DocumentBuilderFactory is supposed to be thread-safe
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		DocumentBuilder builder = factory.newDocumentBuilder();
		Document doc = builder.parse( new InputSource( new StringReader( xmlStr ) ) );
		return doc;
	}

}
英文:

I might have found an answer but it is not too elegant so generally I wouldn't recommend to use it but someone might find it useful:

@EnableWs
@Configuration
public class WebServiceConfig extends CommonWsConfigurerAdapter {
...
@Override
public void addInterceptors(List&lt;EndpointInterceptor&gt; interceptors) {
interceptors.add(new CustomEndpointInterceptor());
}
}
@Component
class CustomEndpointInterceptor implements EndpointInterceptor {
...
@Override
public boolean handleResponse(MessageContext messageContext, Object endpoint) throws Exception {
String responseXmlString = toString(messageContext.getResponse());
Document doc = convertStringToDocument(responseXmlString);
// manipulting the response
...
// SaajSoapMessageFactory is thread safe so make sure the message factory is initialized only once
SaajSoapMessageFactory saajSoapMessageFactory = new SaajSoapMessageFactory();
saajSoapMessageFactory.afterPropertiesSet();
SaajSoapMessage saajSoapMessage = saajSoapMessageFactory.createWebServiceMessage();
saajSoapMessage.setDocument(doc);
messageContext.clearResponse();
messageContext.setResponse(saajSoapMessage);
return true;
}
...
private String toString(WebServiceMessage msg) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
msg.writeTo(out);
return new String(out.toByteArray());
}
private Document convertStringToDocument(String xmlStr) throws Exception {
// also the DocumentBuilderFactory is supposed to be thread-safe
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse( new InputSource( new StringReader( xmlStr ) ) );
return doc;
}
}

huangapple
  • 本文由 发表于 2023年7月6日 21:53:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/76629591.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定