1

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?

HSN
  • 121
  • 6
  • 1
    Before we go any further, your output sample is not valid XML so producing this with any tool would be difficult. Are you sure that's what you need? – Johns-305 Apr 15 '15 at 15:44
  • 1
    To add to @Johns-305's comment: Specifically, [***well-formed***](http://stackoverflow.com/a/25830482/290085) XML must have a single root element. You also forgot a `>` in a closing `SIZE` tag. Finally, it would be easier to give you better help if you posted your XSLT. Thanks. – kjhughes Apr 15 '15 at 16:08
  • I hoped it would be clear from my wording, that I only gave the possible structure of the repeating node. This is just part of a larger XML and of course there's a root node around, somewhere. – HSN Apr 15 '15 at 22:06
  • As to the XSLT: since I tried several options and neither gave the desired result (and since I actually think the visual mappers should suffice), I don't see how this would add anything to the question. Feel free to correct me! Instead of giving any actual schema: for purposes of this question, just doing the most straightforward thing possible is alright: add a root, add your favourite namespace, make FRUIT or item a ComplexType with maxoccurs unbounded; sort, size or colour elements. And give everything that needs a type the type string. – HSN Apr 15 '15 at 22:18

1 Answers1

0

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.

Dan Field
  • 20,885
  • 5
  • 55
  • 71
  • FRUIT is indeed a child of something, which I hoped to be clear from the context I provided. Alas, it wasn't. However, even then this doesn't answer my question. I don't want to have one corresponding FRUIT node for each item node, I want that and added to that, one more node FRUIT (with subtree). (And indeed, I wished to avoid having to use xpaths in the orchestration.) – HSN Apr 15 '15 at 22:08
  • Suggested edit: Rename your question to be "How to make sure a looping functoid loops at least twice" or something, and make it clearer from the beginning of the question that you want your destination nodes to occur at least twice. – Dan Field Apr 16 '15 at 12:31