JDoe
JDoe

Reputation: 33

BizTalk 2010 Conditional Mapping Issue (from two different recurring source nodes to same destination node)

I have an EDI 810 file, from which I have to conditionally map certain values from two different repeating SAC nodes, which occur multiple times in different spots in the document. Please note that the SAC_2 occurs at a lower level when compared to the SAC_3 node. A sample fragment of the source document looks like this:

<ns1:IT1Loop1>
  <ns1:SLNLoop1>
    <ns1:SAC_2>
      <SAC01>C</ID>
      <SAC05>3443</Name>
      <SAC15>Service A</ID>
    </ns1:SAC_2>
  </ns1:SLNLoop1>
  <ns1:SLNLoop1>
    <ns1:SAC_2>
      <SAC01>C</ID>
      <SAC05>120</Name>
      <SAC15>Service B</ID>
    </ns1:SAC_2>
  </ns1:SLNLoop1>
  <ns1:SLNLoop1>
    <ns1:SAC_2>
      <SAC01>A</ID>
      <SAC05>243</Name>
      <SAC15>Service D</ID>
    </ns1:SAC_2>
  </ns1:SLNLoop1>
</ns1:IT1Loop1>
<ns1:IT1Loop1>
  <ns1:SLNLoop1>
    <ns1:SAC_2>
      <SAC01>A</ID>
      <SAC05>567</Name>
      <SAC15>Service C</ID>
    </ns1:SAC_2>
  </ns1:SLNLoop1>
  <ns1:SLNLoop1>
    <ns1:SAC_2>
      <SAC01>F</ID>
      <SAC05>4558</Name>
      <SAC15>Service M</ID>
    </ns1:SAC_2>
  </ns1:SLNLoop1>
</ns1:IT1Loop1>
<ns1:SACLoop2>
  <ns1:SAC_3>
    <SAC01>A</ID>
    <SAC05>-1234</Name>
    <SAC15>Adjustment</ID>
  </ns1:SAC_3>
</ns1:SACLoop2>
<ns1:SACLoop2>
  <ns1:SAC_3>
    <SAC01>D</ID>
    <SAC05>24567</Name>
    <SAC15>Balance Forward</ID>
  </ns1:SAC_3>
</ns1:SACLoop2>

Here are the conditions: From the SAC_2, I need to map the values of the SAC05 (to Amount) and SAC15 (to Description) elements, IF SAC_2/SAC01 has the values "C" or "A". From the SAC_3, I need to map the values of the SAC05 (to Amount) and SAC15 (to Description) elements, IF SAC_3/SAC01 has the values "C" or "A" AND the SAC15 != "Balance Forward". So it is supposed to generate as many "MeasureItems" as there are any of these segments with criteria fulfilled. Here is what the output should look like for the sample input:

<Root>
  <HeaderItems>
  ...
  </HeaderItems>
  <MeasureItems>
    <Description>Service A</Description>
    <Amount>3443</Amount>
  </MeasureItems>
  <MeasureItems>
    <Description>Service B</Description>
    <Amount>120</Amount>
  </MeasureItems>
  <MeasureItems>
    <Description>Service D</Description>
    <Amount>243</Amount>
  </MeasureItems>
  <MeasureItems>
    <Description>Service C</Description>
    <Amount>567</Amount>
  </MeasureItems>
  <MeasureItems>
    <Description>Adjustment</Description>
    <Amount>-1234</Amount>
  </MeasureItems>
  <ReadItems>
  ...
  </ReadItems>
</Root>

There is no way to do this easily through only functoids alone so I have tried a combination of the EqualTo, NotEqualTo, LogicalOR, ValueMapping functoids along with the scripting functoid (inline C#) to choose between inputs (if conditions held true), but nothing gave me the correct output.

Image: http://i68.tinypic.com/2dj5d2c.jpg

With this arrangement (shown in image) functoid I would always get everything mapped correctly from the SAC_2 repetitions but it would completely ignore the SAC_3 elements.

And with inline XSLT it would always map only from the first occurrence of SAC_2 segment, from each recurring IT1Loop1 parent. And, of course, it would completely ignore the SAC_3 elements again.

Here is one version of the inline XSLT code I used:

<xsl:element name = "Description">

  <xsl:choose>
    <xsl:when test=".//*[local-name()='SAC_2']/SAC01 = 'C' or .//*[local-name()='SAC_2']/SAC01 = 'A'">
      <xsl:value-of select = ".//*[local-name()='SAC_2']/SAC15[preceding-sibling::SAC01='C' or preceding-sibling::SAC01='A']"/>
    </xsl:when>
    <xsl:when test=".//*[local-name()='SAC_3']/SAC01 = 'C' and not(.//*[local-name()='SAC_3']/SAC15 = 'Balance Forward')">
      <xsl:value-of select = ".//*[local-name()='SAC_3']/SAC15[preceding-sibling::SAC01='C' or preceding-sibling::SAC01='A']"/>
    </xsl:when>
  </xsl:choose>

</xsl:element>

I'm guessing switch statements and loops don't work the same way in XSLT as they do in other languages. Also, I tried the same logic through inline C# alone too. It did not yield correct results.

I'm quite sure there should be a way to do this using inline XSLT or some other custom code solution.

Additionally, I don't understand why the SAC_3 elements keep getting ignored.

Could someone please help me with this?

Upvotes: 2

Views: 1101

Answers (1)

Dan Field
Dan Field

Reputation: 21641

You should be able to do this with a looping functoid and a couple logical functoids. Connect the ITLoop1 and the SACLoop2 as inputs to the looping functoid, and have it output to your destination repeating node (MeasurementItems). Then like SAC05 and SAC15 to the correct destinations. Finally, add some Equals functoids to the map, with SAC1 as the input, 'A' as the second parameter, and output to the MeasurementItems. Add the same functoid for both SAC1 elements, and another set that uses C as the second input. See the documentation for more information.

If you want to do this in XSLT, it will have to generate the entire MeasurementItems node, which may or may not be more difficult than its worth (or might be worth jus tdoing the whole map in XSLT). Your template would look something like this:

<xsl:template match="//ns1:SAC_2[SAC01='A' or SAC01='C'] | //ns1:SAC_3[(SAC01 = 'A' or SAC01= 'C') and SAC15 != 'Balance Forward']" xmlns:ns1='REPLACE_WITH_REAL_NAMESPACE'>
  <Amount>
    <xsl:value-of select="SAC05" />  
  </Amount>
  <Description>
    <xsl:value-of select="SAC15" />  
  </Description>
</xsl:template>

Upvotes: 1

Related Questions