Copy link to clipboard
Copied
Hi there,
I'm in a process to convert loads of old non structured FM manuals into structured formats, and though it all works fine there is a lot of repetition involved I'd like to get rid off. I'm having a bit of experience with extendscript for indesign, but the documentation for FM is rather poor. So if someone can get me started or provide some codesnippets to make my job a bit more pleasant it would be highly appreciated 🙂
My processes :
First I open a book, and for each file I run the 'Generate conversion Table' command. The missing paragraph tags need to be added to an existing Conversion table called 'conversion_table'.
Question 1 : Can I use some code to do this automatically ? So all fm files in the book get opened (silent or not does not really matter) , missing tags are added to the existing table, and fm file is closed again.
Second : I clean up the conversion table so output is a bit streamlined. That's a manual process anyway so no issues
Third : I structure the book using the table. Pretty straight forward also so no problem here
Last step : I save all fm files as docbook 2.1 format, but again this requires me to open all fm files one by one, select 'save as XML', select docbook as format and save the file itself.
Question 2 : Can I also here use some code so all fm files in the book are opened, saved as XML using docbook format , and closed again with me leaning back and looking at my PC doing the dirty job for me. To push my luck it would be great if I could also integrate step 3
I guess all of this would be rather simple for a seasoned programmer, but I'm cracking my teeth on it. Therefore anybody that can point me in the right direction or provide some code that could get me running would make my day for sure
Thanks in advance!
K.
I agree with Russ; you have a lot going on. I would suggest splitting your question into multiple posts, one for each step in the process. Most of us like to help, but I do this for a living so I can't spend too much time posting complete solutions for free. But here is some code that will automate your third step:
CallClient ("Structure Generator", "InputDocId " + inputId);
CallClient ("Structure Generator", "RuleDocId " + convId);
CallClient ("Structure Generator", "StructureDoc");
The inputId
...Copy link to clipboard
Copied
Hi K,
Since nobody has responded, I thought I would add a little something, although probably not what you are asking for. Your requirements are well-suited for ExtendScript automation; however, they represent a fairly advanced usage of it. It could take some time to develop these scripts, more time than somebody can likely give you on a simple user-to-user forum post. So, I think that might be why you are having trouble getting responses.
This is a good place to ask specific questions about ES code, but yours is quite broad. I'm almost sure you would need to pay someone to write all that code. My suggestion is to back up a bit and start learning about ES at a lower level, then maybe the way forward will eventually start to make more sense to you.
Russ
Copy link to clipboard
Copied
I agree with Russ; you have a lot going on. I would suggest splitting your question into multiple posts, one for each step in the process. Most of us like to help, but I do this for a living so I can't spend too much time posting complete solutions for free. But here is some code that will automate your third step:
CallClient ("Structure Generator", "InputDocId " + inputId);
CallClient ("Structure Generator", "RuleDocId " + convId);
CallClient ("Structure Generator", "StructureDoc");
The inputId and convId variables are the id properties of the input document and the conversion table document, respectively. For example, if you are structuring the active document, you would do this to get the inputId:
var inputId = app.ActiveDoc.id;
There are also commands to add new entries to an existing conversion table. The best place to get this information is in the FDK manuals. You will have to "translate" the information from C to ExtendScript, but at least you have something to start with. I don't think any of the Structure Generator information is in the ExtendScript documentation.
Rick
Copy link to clipboard
Copied
Thanks both,
Fully understand and agree that I probably pushed my luck a bit 🙂
Let's try again on some part already. I'm able to run a script to save it as XML, and I probably can figure outhow to get it done on booklevel with the examples available, but I'm still struggling with the structured save part. Saving as XML works fine, and I found some example for the SDK, but I can't find the right syntax to do it on the extendscript Toolkit as that's a bit less intimidating for me.
This is what I have now :
var doc, name, saveParams, i;
doc = app.ActiveDoc;
name = doc.Name;
fullName = name.replace(".fm",".xml");
saveParams = GetSaveDefaultParams();
returnParams = new PropVals();
i = GetPropIndex(saveParams, Constants.FS_FileType);
saveParams.propVal.ival =Constants.FV_SaveFmtXml;
i = GetPropIndex(saveParams, Constants.FS_StructuredSaveApplication);
saveParams.val.propVal.ival = "XDocBook"; <- this doesnt'work, any advice on what the exact syntax would be ?
doc.Save(fullName, saveParams, returnParams);
doc.Close(Constants.FF_CLOSE_MODIFIED);
Regards,
Koen
Copy link to clipboard
Copied
Since XDocBook is a string, it is probably .sval:
saveParams.val.propVal.sval = "XDocBook";
Copy link to clipboard
Copied
Actualy I was too fast with copy paste activity from c to extend, so after some tweeking I got this to work :
saveParams.propVal.sval = "XDocBook";
After some further playing around I got a full flow working now for the save as xml part, all files of the book are now opened silently, each document is saved with structured fomat and closed. Below full working code in case someone could use it also
------------------------------------------------------------------------
// Save all compontents as XML
bookTraverse ();
// Traverse through book components and save them when valid, thanks to the original creator !
function bookTraverse ()
{
var book = app.ActiveBook
if (!book.ObjectValid() )
{
// kind reminder to select the book before we get started
Alert ("Select book first" ,Constants.FF_ALERT_CONTINUE_WARN)
return
}
// Quick warning up front...
var ret = Alert ("All files in this book will be saved as XML: Press <OK> to continue or <cancel> to abort",Constants.FF_ALERT_OK_DEFAULT)
if (ret == -1)
{
return
}
var compBook = book.FirstComponentInBook
while(compBook.ObjectValid() )
{
var compName = compBook.Name
var compType = compBook.BookComponentFileType
var doc = open(compName)
if (compType == Constants.FV_BK_BOOK)
{
bookTraverse (doc)
}
if (doc.ObjectValid() )
{
// component is valid so we save as XML
saveDocAsXML (doc, doc.Name)
doc.Close (1)
}
compBook = compBook.NextBookComponentInDFSOrder
}
Alert ("All are saved" ,Constants.FF_ALERT_CONTINUE_WARN)
}
function open(filename)
{
var openProp = GetOpenDefaultParams()
var i=GetPropIndex(openProp,Constants.FS_FileIsOldVersion)
openProp.propVal.ival=Constants.FV_DoOK
i=GetPropIndex(openProp,Constants.FS_FontNotFoundInCatalog)
openProp.propVal.ival=Constants.FV_DoOK
i=GetPropIndex(openProp,Constants.FS_FontNotFoundInDoc)
openProp.propVal.ival=Constants.FV_DoOK
i=GetPropIndex(openProp,Constants.FS_FileIsInUse)
openProp.propVal.ival=Constants.FV_DoCancel
i=GetPropIndex(openProp,Constants.FS_AlertUserAboutFailure)
openProp.propVal.ival=Constants.FV_DoCancel
i=GetPropIndex(openProp,Constants.FS_LockCantBeReset)
openProp.propVal.ival=Constants.FV_DoOK
i=GetPropIndex(openProp,Constants.FS_MakeVisible)
openProp.propVal.ival=false
var retParm = new PropVals()
var fileObj=Open(filename,openProp,retParm);
return fileObj
}
function saveDocAsXML(doc,name) {
var fullName = name.replace(".fm",".xml");
var saveParams = GetSaveDefaultParams();
var returnParams = new PropVals();
var i = GetPropIndex(saveParams, Constants.FS_FileType);
saveParams.propVal.ival =Constants.FV_SaveFmtXml;
i = GetPropIndex(saveParams, Constants.FS_StructuredSaveApplication);
saveParams.propVal.sval = "DocBook 2.1";
doc.Save(fullName, saveParams, returnParams);
}
Copy link to clipboard
Copied
Koen,
You've done well! I think maybe you didn't really need help at all, maybe you just wanted to talk to somebody
Russ
Copy link to clipboard
Copied
Yeah, sometimes just thinking out loud get's you started also 🙂
Copy link to clipboard
Copied
Thanks Rick, this helped me quite a lot.
I was able to figure out how to add the missing entries to my conversion table using below mentioned booktraverser in combination with following :
function UpdateConvTable(doc,name,ConvTableID ){
// get current doc id
var docId = doc.id;
// add missing tags to conversion table
CallClient("Structure Generator", "SourceDocId " + docId);
CallClient("Structure Generator", "UpdateTable " + ConvTableID );
// and save the documents so it's up to date with latest version
var params = GetSaveDefaultParams();
var returnParamsp =new PropVals();
var i = GetPropIndex(params, Constants.FS_FileType);
params.propVal.ival =Constants.FV_SaveFmtBinary;
doc.Save(name, params, returnParamsp)
return
}
It does nicely what I want, it opens all the bookcomponents, adds the missing ones to my conversion table, saves the component and does all of this without nagging me with errors etc.
But..
I got the id of my conversion table by opening it, giving it the scope, and then retrieving the app.ActiveDoc.id. But this is a bit of unreliable method, for starters I'm not even sure if this id is unique and fixed, or can just be changed over time. What would therefore be a better to get the id of the conversion table, rather than having it hardcoded as I did now ?
Scenario I am thinking of is as follows
Book is selected, and script starts
-> if page with name "conversion_table" is not opened (using IsOnScreen ?), open the page (located at "C:\\conversion_table.fm)
-> if opened get the id , and run all code magic on all the book components (above function)
seems like fairly simple, but i can't find back any examples on how to use IsOnScreen, or opening a single document (my conversion table) without losing focus on selected book. Any advice / support would be welcome.
Copy link to clipboard
Copied
This may not be the best approach, but you could loop through the open documents and test its name to see if it is the conversion table. You should probably put this in a function.
var doc = app.FirstOpenDoc;
while (doc.ObjectValid() === 1) {
if (/Conversion/.test(doc.Name) === true) {
var convId = doc.id;
}
doc = doc.NextOpenDocInSession;
}
Rick
Copy link to clipboard
Copied
Thanks again Rick, it looks like a good alternative, but I'm not familiar with the /conversion/.test syntax.
I've tried a few things with above code, but it didn't give me results. Playing with the script I can get the name of the open docs etc, but the test thing puzzles me.
What would I need to change in (/Conversion/.test(doc.Name) === true) to make it work ? Assume I would have a document called conversion_table.fm, located at C:/folder/conversion_table.fm
Copy link to clipboard
Copied
This is where you get into core JavaScript versus FrameMaker ExtendScript. /Conversion/ is a JavaScript regular expression that matches the literal string "Conversion" somewhere in the file path or name. You can use /Conversion/i.test to give you a case-insensitive search; this is probably why it is failing for you. JavaScript has other ways of matching strings that you may find more convenient. I like the test method because it returns true or false.
Rick
Copy link to clipboard
Copied
ah, brilliant... the case insentive did the trick indeed.
Copy link to clipboard
Copied
Hi Expert,
I've tried above scripts, and thought it works great when updating the conversion table, it doesn't seem to do much when I want to structure my book. Below is the script I have, and I think i'm overlooking something obvious, as I believe that in theory it should work
function structureBook(){
var bookID = app.ActiveBook.id;
var bookName = app.ActiveBook.Name;
//set path to current folder, and add struc
var x=bookName.lastIndexOf("\\");
var dirPath=bookName.substring(0, x )
dirPath += "\\struc"
//If no convTableId get it
if(convTableId===0){
getConvTableId();
}
//alert(convTableId + " - " + bookID + " - " + dirPath)
//Structure current book using above values
CallClient("Structure Generator", "InputBookId " + bookID);
CallClient("Structure Generator", "RuleDocId " + convTableId);
CallClient("Structure Generator", "OutputDirName " + dirPath);
CallClient("Structure Generator", "GenerateBook");
}
I get all my inputs correctly (book ID, Conversion table ID), the folder where I'd like to save the structured content does exist etc (anyway, commenting the outputdir part doesn't make a difference).
Yet nothing seems to happen, the script runs and gives no failure, but also no output. Any idea on what i might have missed (or how I could check where things go wrong ?)
Thanks again !
Copy link to clipboard
Copied
Koen,
I could be wrong, but I don't think there is any such command as InputBookId. I think you need to go document-by-document with InputDocId.
Russ
Copy link to clipboard
Copied
Hi Russ, I found it in the FDK reference :
F_ApiCallClient() calls to structure a book
F_ApiCallClient("Structure Generator", "InputBookId objectID");
where objectID is the ID of the input book.
I know I can do it on document base, but then i need to generate the book again if i want to keep my original files, so it would be nice if i could get the book thing running
Copy link to clipboard
Copied
Interesting. Never knew about that... I guess I never had a need. I've done it a single document at a time and it works.
Here is an idea, but it is a long shot. In some older versions of the FDK doc, there was a mistake where it said "GenerateDoc" instead of "StructureDoc", which caused the single doc conversion to fail. I see that the latest version of the FDK doc has fixed that, but it still says "GenerateBook" for the book conversion. I wonder if there is any chance that it should actually be "StructureBook"? Maybe give that a try. If that doesn't work, I don't have any other suggestions at the moment. I'm a bit tied up to try it myself right now.
Copy link to clipboard
Copied
Haha, brilliant ! Using StructureBook indeed did the trick. Thanks a lot Russ
Copy link to clipboard
Copied
Maybe not so brilliant, just that I've been around too long. Has it been that long?
Thanks for marking my answer as correct, but Rick definately deserves more credit. He was originally much more helpful than me.
Copy link to clipboard
Copied
Yeah, it's a small annoyance of the system that you can't mark more than one correct answer. But you sure both helped me a lot !