Hi all
Some times people need to convert a list of elements into a comma separated list of values. In the forums this questions arises every now and then, so here goes a solution.
Suppose this input:
<ns0:MultipleElementsRoot xmlns:ns0="http://MapCommaSeparatedValue.MultipleElementsSchema">
<MyField>Jan</MyField>
<MyField>Eliasen</MyField>
<MyField>BizTalk</MyField>
</ns0:MultipleElementsRoot>
And I want this output:
<ns0:CommaSeparatedRoot xmlns:ns0="http://MapCommaSeparatedValue.CommaSeparatedSchema">
<CommaField>Jan,Eliasen,BizTalk</CommaField>
</ns0:CommaSeparatedRoot>
Inside a map I would handle it like this (2 approached, that share the first two functoids):
The reoccurring element is used as input to a string concatenate functoid. The functoid takes a comma as the second input. The output of the concatenate functoid is then used as input for a cumulative concatenate functoid, effectively creating a comma separated list of values. The issue with this list is, that it will have a comma at the end of the line, which needs to be removed.
One way of doing this is to use three functoids to pull this last comma away. First, I take the length of the string, then I subtract one from that, and use the string extract functoid to extract the string beginning at position 1 and ending at (length - 1) and send that to the destination element. Works like a charm.
Now, plenty of people out there (Henrik, you know who you are) would have no moral qualms using a C# scripting functoid to get rid of the extra comma. Like this:
public string RemoveLastComma(string input)
{
return input.Substring(0, input.Length-1);
}
That one scripting functoid would eliminate the last three functoids I added to remove the last comma. But I still prefer the functoid way of doing it, mostly for maintenance reasons. A new BizTalk developer looking at a map with lots of scripting functoids has no idea what is happening, and even after looking at the code in all the scripting functoids, he can’t remember what is happening in more than a couple of them. In my opinion; Always use the built-in functoids if possible.
Now, just for the kick, I thought that some times the opposite could be the case – going from a comma separated list to lots of elements. This, I cannot solve using built-in functoids, unfortunately, so the map ended up like this:
Just one scripting functoid. The type is an “Inline XSLT Call Template” and the script is:
<xsl:template name="MyXsltSplitTemplate">
<xsl:param name="param1" />
<xsl:if test="$param1 != ''">
<xsl:element name="MyField">
<xsl:choose>
<xsl:when test="contains($param1, ',')">
<xsl:value-of select="substring-before($param1, ',')" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$param1" />
</xsl:otherwise>
</xsl:choose>
</xsl:element>
<xsl:call-template name="MyXsltSplitTemplate">
<xsl:with-param name="param1" select="substring-after($param1, ',')" />
</xsl:call-template>
</xsl:if>
</xsl:template>
Basically, the function substring-before is used to get any string before a comma and output it. If no comma is in the string, the string is output. The string to the right of a comma is then used as a recursive call to the same template. Again; Works like a charm
So, with any luck, this question can be answered by googling soon instead of asking in the forums
Edit on 27’th June:
--
eliasen