2012-11-13

multi mapping and split message with XSLT in SAP PI

应用场景是主数据的复制,从SAP到Salesforce,即:
SAP --RFC--> PI --SOAP-->Salesforce

在调用Salesforce的upsert时,一次最多只能包含200个对象,所以当PI接收到超过200个对象的数据时,需要把一个message分成多个messages,即1 --> n。Operation Mapping包括三个步骤:
  1. message mapping,从源数据结构映射到Salesforce的upsert结构
  2. Java mapping,从value mapping中取出有效的sessionID和serverURL,在dynamic configuration里设置相应的值
  3. XSLT mapping,生成多个SOAP request,每个request里的upsert包括最多200个objects,其中要注意output的结构和正确的namespace
在第三步要注意ouput的正确结构为
<message>
 <message1>
  <soapenv:Envelope>
   ...
  </soapenv:Envelope>
  <soapenv:Envelope>
   ...
  </soapenv:Envelope>
  </message1>
<message>

 上面的例子会被adapter正确的解释成2个messages。

如果XSLT生成的结构像下面这样:

<message>
 <message1>
  <soapenv:Envelope>
  ...
  </soapenv:Envelope>
 </message1>
  <message1>
  <soapenv:Envelope>
   ...
  </soapenv:Envelope>
  </message1>
<message>

那么在monitoring里会得到下面的错误:

<SAP:Category>XIServer</SAP:Category>
  <SAP:Code area="MAPPING">MISSING_INTERFACE</SAP:Code>
  <SAP:P1>2</SAP:P1>
  <SAP:P2 />
  <SAP:P3 />
  <SAP:P4 />
  <SAP:AdditionalText />
  <SAP:Stack>No interface specified for parameter 2</SAP:Stack>


在测试时还需注意,如果是在Repository(design time)里测试operation mapping或message mapping,source input里需要构造
<message> <message1> ...</message1><message>这样的结构,但是在directory里或RWB(runtime)里测试时,payload里都不应该出现<message> <message1> ...</message1></message>这样的结构,否则会得到类似下面的错误:
sap.aii.mappingtool.tf7.IllegalInstanceException: Cannot create target element /ns0:Messages. Values missing in queue context.
第3步的XSLT:

<?xml version="1.0" encoding="UTF-8"?><xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:urn="urn:enterprise.soap.sforce.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns="http://pi.cceag.de/SFDC" xmlns:ns0="http://sap.com/xi/XI/SplitAndMerge">
    <xsl:output indent="yes" method="xml"/>
    <xsl:template match="/">
        <ns0:Messages>
        <ns0:Message1>
            <xsl:for-each select="//sObjects[position() mod 200 = 1]">
                    <soapenv:Envelope>
                        <xsl:call-template name="header"/>
                        <soapenv:Body>
                            <urn:upsert>
                                <externalIDFieldName>
                                    <xsl:value-of select="//upsert/externalIDFieldName"/>
                                </externalIDFieldName>
                                <xsl:for-each select=". | following-sibling::sObjects[position() &lt; 200]">
                                    <xsl:call-template name="sObjects" />
                                </xsl:for-each>
                            </urn:upsert>
                        </soapenv:Body>
                    </soapenv:Envelope>
            </xsl:for-each>
         </ns0:Message1>       
        </ns0:Messages>
    </xsl:template>

    <xsl:template match="soapenv:Header" name="header">
        <xsl:copy-of select="/soapenv:Envelope/soapenv:Header"/>
    </xsl:template>

    <xsl:template match="sObjects" name="sObjects">
        <urn:sObjects xsi:type="Account">
        <xsl:for-each select="./*">
            <xsl:element name="{local-name()}">
                <xsl:value-of select="./text()" />
            </xsl:element>
         </xsl:for-each>
         </urn:sObjects>
    </xsl:template>
</xsl:stylesheet>

没有评论:

发表评论