Say in our 850 example, you're down in the N1 group (2/350), child of PO1 (2/010) and you need to iterate through your REF segment (2/390). It happens.
Even if you have prudently cleaned up the segment and group id's, you still have this nuisance of trying to do this:
$2390_REF[index(1)][index(2)][idx_REF].#0128 ...
Those index values can get confusing and can lead to performance questions if they are needed frequently. While the code may look simple enough, it is not clearly obvious from the code what the segment group hierarchy really is. Furthermore, there is a temptation to copy such code from another section in which the indices may not apply and thus produce questionable results.
The convention I follow is to maintain a running group level, grplvl, and an index. I want to avoid hardcoding the group level and keep it relative to its parent group.
We would like to capture those values for their scope and hold them in variables., and we would like these variables to follow a fixed convention.
This is where our document_grplvl = 0 comes into play. A group at the document level is a child of the document. Let us take a look at the entry to the header level N1 group (1/310).
In the group's onBegin() rule I define a standard preamble:
integer this_N1_grplvl, this_N1;
this_N1_grplvl = document_grplvl + inc;
this_N1 = index(this_N1_grplvl);
Now, anytime in my group that I need the current index, I do not need to use the index function and run the risk of using the wrong index number. The variable this_N1 will have the value that I need.
If I had reason in there to reference the REF segment (1/350), then my code is simply like this:
qual = $1350_REF[this_N1][idx_REF].#0128;
This code is also very portable. If I am going to work with the detail level N1 (2/350), the preamble is copied with only a simple change:
integer this_N1_grplvl, this_N1;
this_N1_grplvl = this_PO1_grplvl + inc;
this_N1 = index(this_N1_grplvl);
Now you see, it is taken for granted that the PO1 group (2/010) had its preamble in place. Since this N1 group is a child of PO1, we simply increment off PO1's grplvl.
Another case: say we need to flag that the bill-to and ship-to addresses were actually present in the header, and then report an error at document.onEnd() if one was missing. Or consider a real-life case I had in which the ship-to and ship-from were optional in themselves, but if either one was used they were both required. Also, if carrier was present, then ship-from and ship-to were both required. We could use booleans to flag that the N1 entity was present, but since the segment groups are 1-based, I like to keep a variable capturing the group that had it, and 0 (zero) if it is not present. This way if I want to use it at document.onEnd(), I can.
What I do for this is at the document.onBegin() rule, I define index capture variables, like this:
Now when I am in the N1 group, I can then do my test. There is a little gotcha here in that if you are going to be testing for validation, you must capture the value at the field level. Such a rule is really in proper context in the group.onEnd() rule, since it concerns the overall group. But in the validation pass on the map, field data isn't always visible in the onEnd() rule, and so errors are falsely reported.
integer the_N1_CA, the_N1_SF, the_N1_ST;
the_N1_CA = zero;
the_N1_SF = zero;
the_N1_ST = zero;
What I do for this is in the N1 group's preamble, I add another variable called this_N1_entity.
string[3] this_N1_entity;
this_N1_entity = "";
In N1's 0098 element, all I have is this_N1_entity = #0098; Now I can use that variable in my onEnd() rule safely. I can also use it further down, as the current N1 entity may influence which REF's I am interested in capturing. So now, to tie this back to our the_N1_... variables, our N1 group's onEnd() may look like this now:
if this_N1_entity = "CA" then begin
the_N1_CA = this_N1;
end
else if this_N1_entity = "SF" then begin
the_N1_SF = this_N1;
end
else if this_N1_entity = "ST" then begin
the_N1_ST = this_N1;
end
This code will always remember the last occurrence of any of these entities. But if we wanted to capture only the first occurrence and ignore others, we can do that too, very easily, as shown with a modified CA test:
if this_N1_entity = "CA" then begin
if the_N1_CA = zero then begin
// capture it
end
else begin
// call this an error or ignore it
end
end
The test at the document.onEnd() is now greatly simplified:
By keeping proper indices for the group hierarchy, it greatly simplifies your group array index codes whenever you need to reference them. The extended rules retain very high portability. They can be copied from one group to another with only simple and well-represented changes.
if the_N1_CA <> zero then begin
if the_N1_SF = zero | the_N1_ST = zero then begin
// CA present, but SF or ST is missing
end
end
else if the_N1_SF <> zero & the_N1_ST = zero then begin
// SF present without ST
end
else if the_N1_SF = zero & the_N1_ST <> zero then begin
// ST present without SF
end
No comments:
Post a Comment