Jump to content

Composing Several Non-Sequential Records


JPalchak

Recommended Posts

I'm almost positive that there isn't a way to do this in the current FusionPro build but I find myself having to do this quite often.

 

I usually get clients that like to see one of each of say 5 different "backgrounds" for letters/postcards or whatever. So currently I'm having to search for the record number (1, 5, 17, 68, 250) for example then having to manually compose one record at a time, change the file name and then repeat the process X times.

 

Is there a way to do this at all?

 

Is there a way to make this a feature request?

 

Thanks

 

- Jason

Link to comment
Share on other sites

Create a javascript global with:

var DupeArray = [];

 

Create an OnRecordStart with:

if (DupeArray.indexOf(Field("[color="Red"]bg[/color]")) > -1 ){
  FusionPro.Composition.composeThisRecord = false;
}
else{
   FusionPro.Composition.composeThisRecord = true;
   DupeArray = DupeArray.concat(Field("bg"));
   }

Link to comment
Share on other sites

What exactly is it that you want to do? Please be more specific.

 

Do you mean that you want to have your data file sorted into multiple output files? You can do that now* with some special JavaScript code to load the data file into an ExternalDataFileEx object.

* "Now" depends on the version of FusionPro you're running.

 

Here's an example of how sort the output of the Frodo Travel tutorial job into multiple output files, by the Destination field:

 

Add this code to the JavaScript Globals:

function Field(name)
{
   var rec = mainDataRecords[FusionPro.Composition.inputRecordNumber-1];
   return mainDataFile.GetFieldValue(rec.record, name);
}

And add this code to OnJobStart:

mainDataFile = new ExternalDataFileEx(PrimaryInputFile());
mainDataSortField = "Destination";
mainDataRecords = [];
for (var r = 1; r <= mainDataFile.recordCount; r++)
   mainDataRecords.push({value:mainDataFile.GetFieldValue(r, mainDataSortField), record:r});

mainDataRecords.sort(function(a,b){if (a.value > b.value) return 1; if (a.value < b.value) return -1; return 0;});

And this code to OnRecordStart:

var rec = mainDataRecords[FusionPro.Composition.inputRecordNumber-1];
for (var fieldName in FusionPro.Fields)
   FusionPro.Composition.AddVariable(fieldName, mainDataFile.GetFieldValue(rec.record, fieldName), FusionPro.inputTreatFlatDataAsTagged);

var sortFieldValue = rec.value;
var rec_previous = mainDataRecords[FusionPro.Composition.inputRecordNumber-2];
var previousSortFieldValue = rec_previous ? rec_previous.value : "";
if (sortFieldValue != previousSortFieldValue)
   FusionPro.Composition.OpenNewOutputFile(FusionPro.Composition.MakeValidFileName(Field(mainDataSortField)) + "." + FusionPro.Composition.outputFormatExtension);

 

This could likely be adapted to your job, by changing the sort field name in OnJobStart.

 

A few caveats about this:

  • This assumes flat-file (delimited) data, where the first row contains the field names.
  • It also assumes that you're composing all the records (not a range subset).
  • Preview will work, but the record being previewed may not match the data in the Record Selector dialog.

 

We are looking at some enhancements along these lines for an upcoming version of FusionPro VDP (possibly version 10), so that you can just check a couple of boxes to accomplish sorting the main data file, without having to write all of this JavaScript code.

Link to comment
Share on other sites

Hi guys, thanks for the replies. I'm pretty new to FusionPro, only a couple months working with it, I'll try and explain it a little better.

 

Here's a job that I just got in.

 

http://i.imgur.com/IgUMNeX.png

 

 

Now normally to send soft proofs I would just pick records 1-9 and compose those. However since there are multiple backs the client has decided that they want to see a sample of each: REFER, PAY, MOBILE etc.

 

So I am currently picking out a record from the data, for example record 5 in my data would pull up the REFER back, and then I compose from record 5 to 5 to get just that record.

 

Then I find the record that would pull PAY and so on.

 

The process to do this is tedious because I have to find the record (if it exists for the back) and then input it, compose, save, find next record, change save name, compose and so on.

 

What would be really optimal would be a compose records 1,2,3... kind of how a print dialogue box would ask for which pages to print; a range or specific pages (in this case records).

Link to comment
Share on other sites

What would be really optimal would be a compose records 1,2,3... kind of how a print dialogue box would ask for which pages to print; a range or specific pages (in this case records).

 

You can do this by creating an array of records you want to compose and then comparing the inputRecordNumber against that array to determine whether a record should be suppressed or not:

var records = [1, 8,'4-6']; // Records to compose

records = records.map(function(s){ s = String(s); var [a,b] = s.split('-'); a = Int(a); b = Int(b || a); s = [a]; while (a < b) s.push(++a); return s.join('|'); }).join('|');

FusionPro.Composition.composeThisRecord = new RegExp(records, '').test(FusionPro.Composition.inputRecordNumber);

Note that the order doesn't matter and that you specify a range of records as long as the range is a string (within quotes) – otherwise the numbers will just be subtracted. The above code would compose records 1,4,5,6, and 8.

 

Alternatively it seems like you could only compose records that have a unique back by setting up a global array:

var backs = [];

And then comparing the back to be used for a specific record to the array. If it's not in the array, that means it's unique so compose the record and push it into the array. If it exists in the array, then you can skip that record because you've already composed a record with that back. To me, that seems easier than searching through your data for records to build a "proof" list but I may be missing something.

var back = Field("Back"); // Field to determine which back page to turn on

if (backs.indexOf(back) > -1)
   FusionPro.Composition.composeThisRecord = false;
backs.push(back);

Link to comment
Share on other sites

Maybe index unique outside of FusionPro creating a proof data set, then feeding that into FusionPro.

 

In excel there's a de-dupe option on data tab, so if there's a field indicating the version, select just the version field and de-dupe will return you one of each version - remember to save it as a new filename and not overwrite the original.

Link to comment
Share on other sites

You can do this by creating an array of records you want to compose and then comparing the inputRecordNumber against that array to determine whether a record should be suppressed or not:

var records = [1, 8,'4-6']; // Records to compose

records = records.map(function(s){ s = String(s); var [a,b] = s.split('-'); a = Int(a); b = Int(b || a); s = [a]; while (a < b) s.push(++a); return s.join('|'); }).join('|');

FusionPro.Composition.composeThisRecord = new RegExp(records, '').test(FusionPro.Composition.inputRecordNumber);

Note that the order doesn't matter and that you specify a range of records as long as the range is a string (within quotes) – otherwise the numbers will just be subtracted. The above code would compose records 1,4,5,6, and 8.

 

Alternatively it seems like you could only compose records that have a unique back by setting up a global array:

var backs = [];

And then comparing the back to be used for a specific record to the array. If it's not in the array, that means it's unique so compose the record and push it into the array. If it exists in the array, then you can skip that record because you've already composed a record with that back. To me, that seems easier than searching through your data for records to build a "proof" list but I may be missing something.

var back = Field("Back"); // Field to determine which back page to turn on

if (backs.indexOf(back) > -1)
   FusionPro.Composition.composeThisRecord = false;
backs.push(back);

 

Thanks for the help outlining this! I used the first method by declaring the records manually in the array fine however when I try this method I get a fatal error when trying to compose:

 

A body page does not have master page assigned.
A blank page is emitted since no record is composed properly.

dlpdfdocwritepdf, progress "Doc->PageCount is zero", error: Bad parameter.

PDF Library Document Write Error: Bad parameter.

pdf_om_WriteDoc, dtl_pdf_WritePdf returned "-2"

Job aborted with error.

 

Is this just because I don't have a blank "null" page set-up if there isn't a record for a body?

Link to comment
Share on other sites

A body page does not have master page assigned.
A blank page is emitted since no record is composed properly.

dlpdfdocwritepdf, progress "Doc->PageCount is zero", error: Bad parameter.

PDF Library Document Write Error: Bad parameter.

pdf_om_WriteDoc, dtl_pdf_WritePdf returned "-2"

Job aborted with error.

 

Is this just because I don't have a blank "null" page set-up if there isn't a record for a body?

This means that FP tried to output a record with no body pages turned on. You'd have to post the actual code that you're using in your OnRecordStart rule for me to tell you how to fix it. The code that I wrote simply tells FusionPro to compose a record or not to compose a record; it does not handle turning turning on/off body pages. But I imagine if you added the following line to turn on at least the first page, the error would go away:

FusionPro.Composition.SetBodyPageUsage(1, true);

 

By the way, after reviewing the code that I posted earlier, I noticed a problem with the regular expression that triggered the records composition. You should make the below alterations for more reliable results (I also commented what is happening in the code for better grasp of the concept):

var records = [1, 8,'4-6'];         // Records to compose

// Turn the array into a Regular Expression
records = records[color="Red"].filter(String)[/color].map(function(s){ 
       s = Str(s);                 // convert the value to a string
       var [a,b] = s.split('-');   // Split the string into an array if there is a dash 
       a = Int(a);                 // Set lower range limit (a) to an integer
       b = Int(b || a);            // Set upper range limit (b) to an integer (b == a if b is null)
       s = [a];                    // Array to hold all values for a range
       while (a < b)               // Until we reach the upper range limit (b),
           s.push(++a);            // increment 'a' and push it into the array of values (s)
       return s.join('|');         // Convert the array back to a string, delimited by a pipe (|)
   }).join('|');                   // Convert the entire 'records' array into a string delimited by a pipe (|)

// Determine if we should compose this record
FusionPro.Composition.composeThisRecord = new RegExp([color="red"]'^(' +[/color] records [color="red"]+ ')$'[/color], '').test(FusionPro.Composition.inputRecordNumber);

[color="red"]FusionPro.Composition.SetBodyPageUsage(1, true); // Turn on page 1[/color]

/*
   The above example output:
   records = '1|8|4|5|6'

   The Regular Expression used will be:
   /^(1|8|4|5|6)$/

   Testing the input number against the above Regular Expression
   will return 'true' if it's one of the numbers in the regex and
   'false' if it's not. Therefore, the 'composeThisProperty' will 
   in turn reflect the presence of a given record in 'records'. 
*/

Link to comment
Share on other sites

What would be really optimal would be a compose records 1,2,3... kind of how a print dialogue box would ask for which pages to print; a range or specific pages (in this case records).

Oh, okay, if that's all you want to do, that's even easier.

 

In fact, the same question has already been answered here on this very forum.

 

With a search for "FusionPro record range", like so:

http://google.com/search?q=fusionpro+record+range

 

One would find this thread:

http://forums.pti.com/showthread.php?t=363

 

And at the end of my first post there:

http://forums.pti.com/showpost.php?p=1157&postcount=4

 

One would find this code to add to OnRecordStart:

 
var ranges = [ 2, [345,351], 657, [987,998] ];
function CheckRanges(val)
{
 for (var i in ranges)
   if (val == ranges[i] || ((ranges[i] instanceof Array) && val >= ranges[i][0] && val <= ranges[i][1]))
     return true;
 return false;
}
FusionPro.Composition.composeThisRecord = CheckRanges(CurrentRecordNumber());
return FusionPro.Composition.composeThisRecord;

So, all you need to do to modify the ranges you want to recompose is to change this single line:

var ranges = [ 7, [15,34], [75,83] ]; //etc.

It wouldn't be much harder to simply read the record numbers from a secondary data file with ExternalDataFileEx.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...