Sep 122008
 

I have come across this issue eleventeen million times, so I figure I would write about it (finally).

The issue: I want to extract data from a repeating record, but I need the output records based on something that is higher up the food chain. If I simply use the logical equals and value mapping or value mapping (flattening) funtiods, if the qualifier is the first occurrence it will successfully extract the data, otherwise it will not pull the data out.

Here is a screen shot of an 837 map that shows the issue in the 2000 REF segment:

innerlooping

 

For simplicity’s sake, I have created a smaller map:

smallInnerloop

Here is the input:

<ns0:Root xmlns:ns0="http://Schemas.Input"> <Record> <SubRecord Qualifier="AA"> <Data>Here is AA Data</Data> </SubRecord> <SubRecord Qualifier="ZZ"> <Data>Here is ZZ Data</Data> </SubRecord> </Record> </ns0:Root>

I want to extract the /Root/Record/SubRecord/Data where the Qualifier is ZZ, but I want to create it driven on the /Root/Record

By using the out of the box functiods, I get the following output:

<ns0:Root xmlns:ns0="http://Schemas.Output"> <Record> </Record> </ns0:Root>

Which is not what I wanted.

There are two ways to extract the data. The first is to use three functiods, a string concatenate functiod to a cumulative concatenate functiod, to a script functiod like this:

  innerloopinganswer1

The string concatenate functiod’s arguments are the following:

concatonatearguments

The cumulative concatenate functiod:

cumulativeconcatonate

And the arguments to the script functiod:

scriptarguments

And the C# script inside the script functiod:

public static string extractFromInnerLoop(string qualifier, string segmentTerminator, string data) { string actualdata=""; int posOfDelimiter = qualifier.Length; if(posOfDelimiter>data.Length) goto end; string delimiterValue = data.Substring(posOfDelimiter, 1); string fullQualifier = qualifier + delimiterValue; int locOfFullQualifier = data.IndexOf(fullQualifier); if (locOfFullQualifier < 0) { actualdata = ""; goto end; } int posOfSegment = data.IndexOf(fullQualifier); int segmentEnd = data.IndexOf(segmentTerminator, posOfSegment); int elementLength = segmentEnd-posOfSegment-fullQualifier.Length; actualdata = data.Substring(posOfSegment+fullQualifier.Length,elementLength); end: return actualdata; }

It works, but I thought that there must be a better approach. A second approach is to use Inline XSLT Call Template:

xsltscript

The arguments to the script:

xsltarguments

and the Inline XSLT Call Template script:

<xsl:template name="SubLoopExtract"> <xsl:param name="qual" /> <xsl:element name="Data"> <xsl:value-of select="SubRecord[@Qualifier = $qual]/Data/text()" /> </xsl:element> </xsl:template>

Both of them create the following output:

<ns0:Root xmlns:ns0="http://Schemas.Output"> <Record> <Data>Here is ZZ Data</Data> </Record> </ns0:Root>