Search code examples
xsdbiztalkbiztalk-mapper

Adding a single repeating node to target schema using BizTalk mapper


I'm currently working on a BizTalk project and I encountered a problem which I'm sure should be solvable within a mapping. However, I don't seem to be able to figure out how. Hopefully someone can help me out.

The situation is as follows: in both the source and the target schema, there's a repeating node with roughly the same child elements underneath it (no records or attributes involved). The repeating node within the source has a structure like this:

<fruit>
    <item>
        <sort>Apple</sort>
        <size>5cm</size>
        <colour>red</colour>
    </item>
    <item>
        <sort>Pear</sort>
        <size>8cm</size>
        <colour>green</colour>
    </item>
</fruit>

While the repeating node in the target looks more like this:

<FRUIT>
    <SORT>Apple</SORT>
    <SIZE>5cm</SIZE>
    <COLOUR>red</COLOUR>
</FRUIT>
<FRUIT>
    <SORT>Pear</SORT>
    <SIZE>8cm</SIZE>
    <COLOUR>green</COLOUR>
</FRUIT>

What I need the mapping to do, is ensure that if there's any fruit available, there are at least two records 'fruit' available in the target. This should be achieved by adding a generic fruit (just think of some arbitrary pineapple, if you like) to the target, if there's only one fruit available at the source.

As a first step, I tried just adding one more fruit node to the target and failed to do so. I'm pretty confident that if I know how to do this, I can solve the actual problem by combining it with the 'count records' and 'logical equality'(=1) functoids.

So the question boils down to: how do I add a single record to the target inside a mapping?

I've tried several options (and combinations of these), namely:

  • using a looping functoid over the elements "fruit" or "item", together with some extra value mapping.
  • directly adding an extra value mapping
  • adding direct links between "item" or "fruit" and "FRUIT", either with or without looping functoid inbetween.

In most of these cases, either I got a result containing children like

<FRUIT>
    <SORT>Pear</SORT>
    <SORT>Pineapple</SORT>
    <SIZE>8cm</SIZE>
    <COLOUR>green</COLOUR>
</FRUIT>

(and a corresponding error since this doesn't satisfy the schema - which doesn't allow for multiple elements SORT), or a whole bunch of pineapples. Neither of which is wished for.

Can anyone help me out?


Solution

  • Unfortunately, there's no easy way to do this in the BizTalk mapper. When you use a looping functoid, it will create an xsl:for-each and will create the destination node exactly the number of times it appears in the source schema.

    Since your destination nodes aren't that complex, your best bet is probably to use a Scripting Functoid with inline XSLT, using the following:

    <xsl:for-each select="/fruit/item">
        <FRUIT>
            <SORT><xsl:value-of select="sort"/></SORT>
            <SIZE><xsl:value-of select="size"/></SIZE>
            <COLOUR><xsl:value-of select="colour"/></COLOUR>
        </FRUIT>
        <xsl:if test="last() = 1"> <!-- there's only one node here, we want at least two -->
            <FRUIT>
                <SORT>pineapple</SORT>
                <SIZE>8cm</SIZE>
                <COLOUR>green</COLOUR>
            </FRUIT>
        </xsl:if>
    </xsl:for-each>
    

    Link the output of that go to the FRUIT node in your destination schema.