我在WSO2 ESB中构建了一个代理,它接收xml,转换它,转发到WSO2数据服务,转换结果并将其返回给请求者。
根据日志,正在调用DataService,因为打印了结果XML。问题在于结果的转换,发生这种情况:
ERROR - XSLTMediator Unable to perform XSLT transformation using : Value {name ='null', keyValue ='GetAppointmentSchedulePortalReqCS_Response'} against source XPath : s11:Body/child::*[position()=1] | s12:Body/child::*[position()=1]
java.lang.NullPointerException
at org.apache.synapse.util.jaxp.StreamSourceBuilder.getSource(StreamSourceBuilder.java:55)
at org.apache.synapse.mediators.transform.XSLTMediator.performXSLT(XSLTMediator.java:289)
at org.apache.synapse.mediators.transform.XSLTMediator.mediate(XSLTMediator.java:191)
at org.apache.synapse.mediators.AbstractListMediator.mediate(AbstractListMediator.java:71)
at org.apache.synapse.mediators.base.SequenceMediator.mediate(SequenceMediator.java:114)
at org.apache.synapse.core.axis2.Axis2SynapseEnvironment.injectMessage(Axis2SynapseEnvironment.java:230)
at org.apache.synapse.core.axis2.SynapseCallbackReceiver.handleMessage(SynapseCallbackReceiver.java:443)
at org.apache.synapse.core.axis2.SynapseCallbackReceiver.receive(SynapseCallbackReceiver.java:166)
at org.apache.axis2.engine.AxisEngine.receive(AxisEngine.java:180)
at org.apache.synapse.transport.passthru.ClientWorker.run(ClientWorker.java:217)
at org.apache.axis2.transport.base.threads.NativeWorkerPool$1.run(NativeWorkerPool.java:172)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
at java.lang.Thread.run(Thread.java:662)
XLST文件是:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://ws.wso2.org/dataservice" version="2.0"
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xpath-default-namespace="http://www.algartelecom.com.br/SOA/Service/GetAppointmentSchedulePortalReqCS">
<xsl:output method="xml" indent="yes" />
<xsl:template match="//xs:GetAppointmentResponse">
<AppointmentRequest>
<serviceOrderID>
<xsl:value-of select="xs:NewAppointment" />
</serviceOrderID>
<opportunityID>
<xsl:value-of select="xs:ServiceTOA" />
</opportunityID>
<customerOrderID>
<xsl:value-of select="xs:MinimalTime" />
</customerOrderID>
</AppointmentRequest>
</xsl:template>
</xsl:transform>
DataService返回的XML是:
<?xml version='1.0' encoding='utf-8'?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<GetAppointmentResponse xmlns="http://ws.wso2.org/dataservice">
<NewAppointment>147</NewAppointment>
<ServiceTOA>TT_P</ServiceTOA>
<MinimalTime>1</MinimalTime>
<ReturnCode>0</ReturnCode>
<ErrorMessage>SUCESSO</ErrorMessage>
</GetAppointmentResponse>
</soapenv:Body>
</soapenv:Envelope>
我已经在其他工具中使用XML测试了XSLT,并且转换工作正常! = /
我认为这可能是由DSS添加到GetAppointmentResponse
标记的内联命名空间引起的。
使用JRE1.6.0_43,ESB 4.6.0和DSS 3.1.0。请帮忙。
修改
我注意到这个问题确实是由响应中的空体引起的,正如@Kallja所说。
恢复,我有以下情况:
PROXY1 -> PROXY2 -> PROXY3 -> ENDPOINT
in xslt->log1->header->send log2->header->send xslt->log3 address web service
out log6->xslt->send log5->send xslt->log4->send
通过soapUI直接调用PROXY3
,正确调用Web服务并收到响应
但是,调用PROXY2
时,日志序列按以下顺序显示:log2
,log3
,log5
,log4
这意味着PROXY2
正在对PROXY3
进行异步调用。在返回soapUI之前,它不会等待响应的XML。它会产生一个空体。
那么,如何让它同步?我试图通过Callout介体替换Send mediator,但结果是一样的。
答案 0 :(得分:1)
你得到的NullPointerException似乎表明XPath表达式(在这种情况下,当没有提供任何其他东西时是WSO2 ESB默认值)指向你想要转换的数据返回null。在这种情况下,这意味着您有一个空白的SOAP主体。
您尚未发布您的序列配置,因此我真的没有太多可以使用的工作。
我的建议是你添加一个完整的日志(下面),它将整个SOAP信封以及几个属性打印到ESB控制台和碳日志文件中,就在XSLT中介之前,看看你是否确实有内容在你的有效载荷中。
<log category="INFO" level="full" separator=","/>
我使用以下配置测试了您的转换,并且执行完美。
<?xml version="1.0" encoding="UTF-8"?>
<proxy xmlns="http://ws.apache.org/ns/synapse"
name="XsltTestProxy"
transports="https,http"
statistics="disable"
trace="disable"
startOnLoad="true">
<target>
<inSequence>
<payloadFactory>
<format>
<GetAppointmentResponse xmlns="http://ws.wso2.org/dataservice">
<NewAppointment>147</NewAppointment>
<ServiceTOA>TT_P</ServiceTOA>
<MinimalTime>1</MinimalTime>
<ReturnCode>0</ReturnCode>
<ErrorMessage>SUCESSO</ErrorMessage>
</GetAppointmentResponse>
</format>
<args/>
</payloadFactory>
<log level="custom">
<property name="message" value="Before XSLT transformation"/>
<property name="payload" expression="$body"/>
</log>
<xslt key="gov:GetAppointmentSchedulePortalReqCS_Response"/>
<log level="custom">
<property name="message" value="After XSLT transformation"/>
<property name="payload" expression="$body"/>
</log>
<property name="RESPONSE" value="true"/>
<header name="To" action="remove"/>
<send/>
</inSequence>
</target>
<description/>
</proxy>
作为旁注,我建议您将以下属性添加到xsl:stylesheet元素中,以从XSLT输出中删除不必要的SOAP xmlns声明。
exclude-result-prefixes="soapenv"
的修改
这个简单的示例配置基于编辑到问题中的执行流程的描述。它显示了如何正确实现相关流程。调用Proxy1时,日志语句按预期顺序显示。
<definitions xmlns="http://ws.apache.org/ns/synapse">
<proxy name="Proxy1" statistics="disable" trace="disable">
<target endpoint="Proxy2Endpoint">
<inSequence>
<!-- Do some XSLT here -->
<log category="INFO" level="custom" separator=",">
<property name="message" value="Proxy1 in (1)"/>
<property expression="$body" name="body"/>
</log>
<!-- Do some header magic here -->
<!-- Implicit send to the endpoint specified in the target element -->
</inSequence>
<outSequence>
<log category="INFO" level="custom" separator=",">
<property name="message" value="Proxy1 out (6)"/>
<property expression="/*" name="body"/>
</log>
<!-- Do some more XSLT here -->
<send/>
</outSequence>
</target>
</proxy>
<proxy name="Proxy2" statistics="disable" trace="disable" transports="https http">
<target endpoint="Proxy3Endpoint">
<inSequence>
<log category="INFO" level="custom" separator=",">
<property name="message" value="Proxy2 in (2)"/>
<property expression="$body" name="body"/>
</log>
<!-- Do some header magic here -->
<!-- Implicit send to the endpoint specified in the target element -->
</inSequence>
<outSequence>
<log category="INFO" level="custom" separator=",">
<property name="message" value="Proxy2 out (5)"/>
<property expression="/*" name="body"/>
</log>
<send/>
</outSequence>
</target>
</proxy>
<proxy name="Proxy3" statistics="disable" trace="disable">
<target endpoint="ImaginaryWebServiceEndpoint">
<inSequence>
<!-- Do some XSLT here -->
<log category="INFO" level="custom" separator=",">
<property name="message" value="Proxy3 in (3)"/>
<property expression="$body" name="body"/>
</log>
</inSequence>
<outSequence>
<!-- Do some more XSLT here -->
<log category="INFO" level="custom" separator=",">
<property name="message" value="Proxy3 out (4)"/>
<property expression="/*" name="body"/>
</log>
<send/>
</outSequence>
</target>
</proxy>
<proxy name="ImaginaryWebService" statistics="disable" trace="disable">
<target>
<inSequence>
<log category="INFO" level="custom" separator=",">
<property name="message" value="Imaginary WebService in"/>
<property expression="$body" name="body"/>
</log>
<payloadFactory>
<format>
<proxy3Response xmlns="">This is the response from the Imaginary WebService</proxy3Response>
</format>
<args/>
</payloadFactory>
<log category="INFO" level="custom" separator=",">
<property name="message" value="Imaginary WebService out"/>
<property expression="/*" name="body"/>
</log>
<header action="remove" name="To"/>
<property action="set" name="RESPONSE" scope="default"
type="STRING" value="true"/>
<send/>
</inSequence>
</target>
</proxy>
<endpoint name="Proxy2Endpoint">
<address statistics="disable" trace="disable" uri="http://localhost:8280/services/Proxy2" />
</endpoint>
<endpoint name="Proxy3Endpoint">
<address statistics="disable" trace="disable" uri="http://localhost:8280/services/Proxy3" />
</endpoint>
<endpoint name="ImaginaryWebServiceEndpoint">
<address statistics="disable" trace="disable" uri="http://localhost:8280/services/ImaginaryWebService" />
</endpoint>