拆分 XML 并将其转换为一个或多个 SOAP 信封

Split XML and transform it in one or more SOAP Envelope

TL;DR;序列收到一条 XML 消息,我需要根据收到的 <product> 个标签的数量构建许多 SOAP 信封。

我有一个序列接收以下 XML(消息 1):

<?xml version="1.0" encoding="UTF-8"?>
<pricing>
    <product>
        <idFF>1</idFF>        
        <skuPartner>abc</skuPartner>        
        <original>123</original>        
        <new>123</new>      
    </product>
    <product>
        <idFF>2</idFF>        
        <skuPartner>aba</skuPartner>        
        <original>123</original>        
        <new>123</new>      
    </product>
    <product>
        <idFF>3</idFF>        
        <skuPartner>ae</skuPartner>        
        <original>123</original>        
        <new>123</new>      
    </product>
</pricing>

我想重复此消息,并为每个 <product> 节点使用以下合同调用 SOAP 服务:

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:tem="http://tempuri.org/">
   <soap:Header/>
   <soap:Body>
      <tem:ProductPriceUpdate>
         <!--Optional:-->
         <tem:safeKey>?</tem:safeKey>
         <tem:storeId>?</tem:storeId>
         <tem:articleId>?</tem:articleId>
         <!--Optional:-->
         <tem:barcode>?</tem:barcode>
         <!--Optional:-->
         <tem:sku>?</tem:sku>
         <tem:price>?</tem:price>
         <tem:discount>?</tem:discount>
      </tem:ProductPriceUpdate>
   </soap:Body>
</soap:Envelope>

在上面的这条消息中,我需要替换

<tem:articleId>?</tem:articleId>
<tem:sku>?</tem:sku>
<tem:price>?</tem:price>

使用收到的 XML 消息的节点中包含的值

<idFF>1</idFF>        
<skuPartner>abc</skuPartner>                
<new>123</new>

所以,面对描述的问题我做了(至少尝试过):

我很确定我离解决方案还有点距离。这是我试过的。

<iterate expression="//produto" id="iterateXML" sequential="true xmlns:ns="http://org.apache.synapse/xsd">
        <target>
            <sequence>
                <payloadFactory media-type="xml">
                    <format>
                        <ProductPriceUpdate>
                            <safeKey>nExd8CzMRDo=</safeKey>
                            <storeId>123</storeId>
                            <articleId></articleId>
                            <barcode>1</barcode>
                            <sku></sku>
                            <price></price>
                            <discount>1</discount>
                        </ProductPriceUpdate>
                    </format>
                    <args>
                        <arg evaluator="xml" expression="//idFF"/>
                        <arg evaluator="xml" expression="//skuPartner"/>
                        <arg evaluator="xml" expression="//new"/>
                    </args>
                </payloadFactory>
                <callout action="ProductPriceUpdate"
                    initAxis2ClientOptions="false" serviceURL="http://url-url.url.info/pub/url.asmx">
                    <source xpath="*"/>
                    <target key="Result"/>
                </callout>
            </sequence>
        </target>
    </iterate>

这是控制台的输出:

[2016-02-11 11:04:52,982] ERROR - SequenceMediator Expecting an implementation of SOAP Envelope as the parent. But received some other implementation
org.apache.axiom.soap.SOAPProcessingException: Expecting an implementation of SOAP Envelope as the parent. But received some other implementation
        at org.apache.axiom.soap.impl.llom.SOAPHeaderImpl.checkParent(SOAPHeaderImpl.java:408)
        at org.apache.axiom.soap.impl.llom.SOAPElement.setParent(SOAPElement.java:81)
        at org.apache.axiom.om.impl.llom.OMElementImpl.addChild(OMElementImpl.java:296)
        at org.apache.axiom.om.impl.llom.OMElementImpl.addChild(OMElementImpl.java:212)
        at org.apache.axiom.soap.impl.llom.SOAPBodyImpl.addChild(SOAPBodyImpl.java:231)
        at org.apache.synapse.mediators.builtin.CalloutMediator.mediate(CalloutMediator.java:161)
        at org.apache.synapse.mediators.AbstractListMediator.mediate(AbstractListMediator.java:81)
        at org.apache.synapse.mediators.AbstractListMediator.mediate(AbstractListMediator.java:48)
        at org.apache.synapse.mediators.base.SequenceMediator.mediate(SequenceMediator.java:149)
        at org.apache.synapse.mediators.eip.Target.mediate(Target.java:106)
        at org.apache.synapse.mediators.eip.splitter.IterateMediator.mediate(IterateMediator.java:163)
        at org.apache.synapse.mediators.AbstractListMediator.mediate(AbstractListMediator.java:81)
        at org.apache.synapse.mediators.AbstractListMediator.mediate(AbstractListMediator.java:48)
        at org.apache.synapse.mediators.base.SequenceMediator.mediate(SequenceMediator.java:149)
        at org.apache.synapse.mediators.MediatorWorker.run(MediatorWorker.java:69)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
        at java.lang.Thread.run(Thread.java:745)
[2016-02-11 11:04:53,031]  INFO - LogMediator To: , WSAction: urn:mediate, SOAPAction: urn:mediate, MessageID: urn:uuid:481ca0ce-8502-486a-b501-350bda23f263, Di
rection: request, MESSAGE = Executing default 'fault' sequence, ERROR_CODE = 0, ERROR_MESSAGE = Expecting an implementation of SOAP Envelope as the parent. But
received some other implementation, Envelope: <?xml version='1.0' encoding='utf-8'?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body><pricing>
        <product>
        <idFF>1</idFF>
        <skuPartner>abc</skuPartner>
        <original>123</original>
        <new>123</new>
    </product>
    <product>
        <idFF>2</idFF>
        <skuPartner>aba</skuPartner>
        <original>123</original>
        <new>123</new>
    </product>
    <product>
        <idFF>3</idFF>
        <skuPartner>ae</skuPartner>
        <original>123</original>
        <new>123</new>
    </product>
</pricing></soapenv:Body></soapenv:Envelope>

我错过了什么?我是否应该使用其他调解器,例如 Enrich? 我感谢每一个提示,谢谢。 =)

编辑:

按照@Jean-Michel 的建议,我替换了 callout mediator 中的 xpath 表达式和 SOAP 实现的错误,消失了。虽然我仍然无法满足要求。当我转到我的 WSO2 的监视器 -> SOAP 跟踪时,我看到以下请求:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
   <soapenv:Header/>
   <soapenv:Body>
      <text xmlns="http://ws.apache.org/commons/ns/payload">IDFF;SKUPARTNER;ORIGINAL;NEW&#xd;11035073;BOBSKU11035073;185.99;200&#xd;</text>
   </soapenv:Body>
</soapenv:Envelope>

编辑 2:

经过一些修改,我才意识到我在标注调解器中发送的消息与我在序列开头收到的 SOAP 信封内的消息相同。如下(请不要考虑xpath错误,这是故意的):

[2016-02-11 12:44:43,197]  INFO - LogMediator To: , WSAction: urn:mediate, SOAPAction: urn:mediate, MessageID: urn:uuid:c3bda9c7-157e-46db-ae9f-f5b687d11848, Di
rection: request, MESSAGE = Executing default 'fault' sequence, ERROR_CODE = 0, ERROR_MESSAGE = The evaluation of the XPath expression : body did not result in
an OMElement, Envelope: <?xml version='1.0' encoding='utf-8'?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"><soapenv:Body><pricing>
        <product>
        <idFF>1</idFF>        
        <skuPartner>abc</skuPartner>        
        <original>123</original>        
        <new>123</new>      
    </product>
    <product>
        <idFF>2</idFF>        
        <skuPartner>aba</skuPartner>        
        <original>123</original>        
        <new>123</new>      
    </product>
    <product>
        <idFF>3</idFF>        
        <skuPartner>ae</skuPartner>        
        <original>123</original>        
        <new>123</new>      
    </product>
</pricing></soapenv:Body></soapenv:Envelope>

编辑 3:

我将标注的地址更改为 http://localhost:1205,这是使用 TCPMon 的结果。似乎一切都还好。

我没有使用标注调解器,但是 <source xpath="*"/> 看起来很奇怪:它的意思是 "all nodes for the source payload"(必须发送的消息)。

您应该考虑像 <source xpath="$body/*[1]"/> 这样的东西来发送第一个主体的 child(即当前肥皂主体的内容),例如...

我能够解决问题。谢谢@Jean-Michel 帮助我度过难关。

我做了以下事情:

  • 创建了直通代理
  • 将 Callout Mediator 更改为调用 PassThroug Proxy 的 Send Mediator
  • 添加了 Header 调解器并定义了 SOAP 操作 - 最重要!

在这里你可以找到我的WSO2-Config.XML:

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://ws.apache.org/ns/synapse">
    <registry provider="org.wso2.carbon.mediation.registry.WSO2Registry">
        <parameter name="cachableDuration">15000</parameter>
    </registry>
    <taskManager provider="org.wso2.carbon.mediation.ntask.NTaskTaskManager"/>
    <proxy name="smook_proxy" startOnLoad="true" trace="disable" transports="https http vfs">
        <description/>
        <target>
            <inSequence>
                <property name="FORCE_SC_ACCEPTED" scope="axis2"
                    type="STRING" value="true"/>
                <property name="OUT_ONLY" scope="default" type="STRING" value="true"/>
                <clone>
                    <target sequence="pricing"/>
                </clone>
            </inSequence>
        </target>
        <parameter name="transport.PollInterval">5</parameter>
        <parameter name="transport.vfs.ActionAfterProcess">MOVE</parameter>
        <parameter name="transport.vfs.MoveAfterProcess">file:///C:\Users\victor.viola\Desktop\out</parameter>
        <parameter name="transport.vfs.FileURI">file:///C:\Users\victor.viola\Desktop\in</parameter>
        <parameter name="transport.vfs.MoveAfterFailure">file:///C:\Users\victor.viola\Desktop\error</parameter>
        <parameter name="transport.vfs.FileNamePattern">.*.csv</parameter>
        <parameter name="transport.vfs.ContentType">text/plain</parameter>
        <parameter name="transport.vfs.ActionAfterFailure">MOVE</parameter>
    </proxy>

    <proxy name="PS_PRICING" startOnLoad="true" trace="disable" transports="https http">
        <description/>
        <target>
            <endpoint name="wsFF">
                <address trace="disable" uri="ADRESSTOTHEBACKEND.asmx"/>
            </endpoint>
            <inSequence/>
            <outSequence>
                <send/>
            </outSequence>
            <faultSequence/>
        </target>
    </proxy>

    <localEntry key="smooks-csv.xml" src="file:C:/wso2esb-4.9.0/repository/resources/smooks/smooks-csv.xml">
        <description/>
    </localEntry>
    <endpoint name="PS_PRICING">
        <address uri="http://localhost:8280/services/PS_PRICING"/>
    </endpoint>

    <sequence name="pricing" statistics="enable" trace="enable">
        <smooks config-key="smooks-csv.xml">
            <input type="text"/>
            <output type="xml"/>
        </smooks>
        <iterate expression="//product" id="iterateXML"
            sequential="true" xmlns:ns="http://org.apache.synapse/xsd">
            <target>
                <sequence>
                    <payloadFactory media-type="xml">
                        <format>
                            <ProductPriceUpdate>
                                <safeKey>******</safeKey>
                                <storeId>*****</storeId>
                                <articleId></articleId>
                                <barcode/>
                                <sku></sku>
                                <price></price>
                                <discount>100</discount>
                            </ProductPriceUpdate>
                        </format>
                        <args>
                            <arg evaluator="xml" expression="//idFF"/>
                            <arg evaluator="xml" expression="//skuPartner"/>
                            <arg evaluator="xml" expression="//new"/>
                        </args>
                    </payloadFactory>
                    <property name="messageType" scope="axis2" value="text/xml"/>
                    <in>
                        <header name="Action" scope="default" value="http://tempuri.org/ProductPriceUpdate"/>
                        <send>
                            <endpoint key="PS_PRICING"/>
                        </send>
                        <drop/>
                    </in>
                    <out>
                        <send/>
                    </out>
                </sequence>
            </target>
        </iterate>
    </sequence>
</definitions>

这是我的smooks.xml

<?xml version="1.0" encoding="UTF-8"?><smooks-resource-list xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd" xmlns:csv="http://www.milyn.org/xsd/smooks/csv-1.2.xsd" xmlns:ftl="http://www.milyn.org/xsd/smooks/freemarker-1.1.xsd" xmlns:file="http://www.milyn.org/xsd/smooks/file-routing-1.1.xsd">
  <params>
    <param name="stream.filter.type">SAX</param>
    <param name="default.serialization.on">true</param>
  </params>
  <csv:reader fields="idFF,skuPartner,original,new" separator=";" skipLines="1"/>
  <ftl:freemarker applyOnElement="#document">
    <ftl:template><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
<pricing>
    <#list .vars["csv-set"]["csv-record"] as csv_record>
    <product>
        <idFF>${.vars["csv_record"]["idFF"]}</idFF>        
        <skuPartner>${.vars["csv_record"]["skuPartner"]}</skuPartner>        
        <original>${.vars["csv_record"]["original"]}</original>        
        <new>${.vars["csv_record"]["new"]}</new>      
    </product>
    </#list>    
</pricing>]]></ftl:template>
  </ftl:freemarker>
  <resource-config selector="#document">
    <resource>org.milyn.delivery.DomModelCreator</resource>
  </resource-config>
</smooks-resource-list>

另一件对解决问题非常重要的事情是在 log4j.properties (wso2home/repository/conf)

中启用这两个日志
log4j.logger.org.apache.synapse.transport.http.headers=DEBUG
log4j.logger.org.apache.synapse.transport.http.wire=DEBUG