Sep 272008

I have come across this a lot and finally was sick of it enough to write about it.

The situation is I have an input that has a bunch of optional fields, and the output is normally a fixed length record file. In my case it is normally an EDI file of some kind that I am mapping to a flat file layout. When I start testing the map, I get the following error produced by the flat file assembler:

Error details: Unable to read the stream produced by the pipeline. Details: Cannot find definition for the input: Address

The reason is that there was no Address in the source data, but the output required it to be there to conform to the flat file layout. If you look at this page from msdn on how to force the creation of elements that are optional. Yes, this is possible, but in my case, I would be creating a script for every element I am creating, which would amount to hundreds of scripting functiods.

Underlying logic: The mapper when dragging optional source items to a required destination item creates the following logic in XSLT:

<xsl:template match="/s0:File"> <ns0:File> <xsl:if test="@Name"> <Name> <xsl:value-of select="@Name" /> </Name> </xsl:if> <xsl:if test="@Address"> <Address> <xsl:value-of select="@Address" /> </Address> </xsl:if> <xsl:if test="@City"> <City> <xsl:value-of select="@City" /> </City> </xsl:if> <xsl:if test="@State"> <State> <xsl:value-of select="@State" /> </State> </xsl:if> <xsl:if test="@Zip"> <Zip> <xsl:value-of select="@Zip" /> </Zip> </xsl:if> <xsl:value-of select="./text()" /> </ns0:File> </xsl:template>

The easy solution, create a second map that maps the destination input to the destination output (and easy way to do this is by following these autolink directions). This creates the following XSLT:

<xsl:template match="/ns0:File"> <ns0:File> <Name> <xsl:value-of select="Name/text()" /> </Name> <Address> <xsl:value-of select="Address/text()" /> </Address> <City> <xsl:value-of select="City/text()" /> </City> <State> <xsl:value-of select="State/text()" /> </State> <Zip> <xsl:value-of select="Zip/text()" /> </Zip> <xsl:value-of select="./text()" /> </ns0:File> </xsl:template>

Notice that there are not any if tests.

You can chain the maps together in an orchestration, or you can place the map in the receive port and the straight thru map in the send port.

What would be nice is to have a map setting called Force Optional Creation Mapping set default to No to leave the behavior as currently is, but if set to Yes, the underlying logic would remove the xsl:if from the map an force the creation of the destination elements regardless of the presence of the input.