简体   繁体   中英

Automate the process of saving Framemaker documents (*.fm) as Xml Files

We have a list of Framemaker document files (*.fm files) coming into a folder. We need to pick up these files and convert to xml format (same as the saveAs opertion from the File menu).

I have written the follwing function to Save fm files to xml

Code to Save fm files to xml files
function saveAsXml (doc) {
   // Get required parameters for the save function.
    var params = GetSaveDefaultParams();
    var returnParamsp = new PropVals();

    // Replace the .fm extension with .mif.
    var saveName = doc.Name.replace (/\.[^\.\\]+$/,".xml");


    var i = GetPropIndex(params, Constants.FS_FileType);
    params[i].propVal.ival = Constants.FV_SaveFmtXml;

    // Save the document as XML.
    doc.Save(saveName, params, returnParamsp);

}

How to automate this process so that code checks -

  1. New fm files in the folder
  2. Saves the fm file as xml
  3. Moves the saved fm file to a different folder

Thanks

如果您在Windows上,则可以编写一个简单的批处理文件,以通过命令行中的批处理文件(.bat)在循环中运行您的扩展脚本。

I needed to save a set of FrameMaker .book files as .xml files. To do this, I wrote a perl script that runs under Windows 10 WSL (Windows Subsystem for Linux). It takes two arguments: a .book file filename , and an XML output directory name :

fm2xml.pl /foo/bar/mybook.book ./xmldir/mybook/

This perl script writes out a temporary ExtendScript file into the Adobe Scripts directory in My Documents (to avoid security dialog boxes), then runs it, then prints the console output from the XML save. You'll need the ExtendScript Toolkit installed as well as FrameMaker.

Here's the fm2xml.pl script:

#!/usr/bin/perl
use strict;
use warnings;
use File::Basename;
use File::Path qw(make_path remove_tree);

my $book_file = shift;
my $bookname = (basename($book_file));
$bookname =~ s!\.book$!!;

my $xml_dir = (shift or "./${bookname}_xml");
my $xml_dir_temp = $xml_dir.'_TEMP';
my $xml_file_temp = $xml_dir_temp."/${bookname}.xml";

my $maker_ini = <<'EOS';
[Frame]
ProductInterface=Structured FrameMaker
[Preferences]
ThorMessageShown=On
UnavailableFontsDialog=Off
EOS
`echo "$maker_ini" > /mnt/c/Users/$ENV{USER}/AppData/Roaming/Adobe/FrameMaker/14/maker.ini`;

my $jsx_script = <<'EOS';
#target framemaker-14.0

var books = [
"BOOK_FILE",
];

main();

function main() {
  var count = books.length;
  for (i = 0; i < count; i+= 1) {
    Console("Converting " + books[i]);
    convertBook(books[i]);
  }
//  alert("Finished");
//  app.Close(Constants.FF_CLOSE_MODIFIED);
}

function convertBook (bookname) {
  Console("  Opening book " + bookname);
  SimpleOpen(bookname);
  var book = app.ActiveBook;
  Console("  Opened book " + book.Name);
  fixLinks(book);
  Console("  Saving as XML...");
  var xmlName = saveAsXml (book);
  Console("  Closing everything in " + book.Name);
  CloseAll();
}

function fixLinks (book) {
  var comp = book.FirstComponentInBook;
  var docs = [];
  while(comp.ObjectValid()) {
    Console("  Opening doc " + comp.Name);
    var doc = OpenFile(comp.Name);
    Console("  Opened doc " + doc.Name);
    docs.push(doc);
    comp = comp.NextBookComponentInDFSOrder;
  }
  Console("  Fixing links...");
  CallClient("XRefWizard", "SetIDs---" + book.Name + "---DoReporting");
  Console("  Fixed links...");
}

function saveAsXml (doc) {
  // Get required parameters for the save function.
  var params = GetSaveDefaultParams();
  var returnParamsp = new PropVals();
  // Replace the .fm extension with .xml
  var saveName = "XML_FILE";
  Console("  Saving to '" + saveName + "'...");
  var i = GetPropIndex(params, Constants.FS_FileType);
  params[i].propVal.ival = Constants.FV_SaveFmtXml;
  // Save the document as XML.
  doc.Save(saveName, params, returnParamsp);
}

function OpenFile(path) {
  props = new PropVals();
  props = GetOpenDefaultParams();
  props[GetPropIndex(props, Constants.FS_AlertUserAboutFailure)].propVal.ival = false;
  props[GetPropIndex(props, Constants.FS_FileIsInUse)].propVal.ival = Constants.FV_ResetLockAndContinue;
  props[GetPropIndex(props, Constants.FS_BookIsInUse)].propVal.ival = Constants.FV_ResetLockAndContinue;
  props[GetPropIndex(props, Constants.FS_LockCantBeReset)].propVal.ival = Constants.FV_DoOK;
  props[GetPropIndex(props, Constants.FS_FileIsOldVersion)].propVal.ival = Constants.FV_DoOK;
  props[GetPropIndex(props, Constants.FS_FontChangedMetric)].propVal.ival = Constants.FV_DoOK;
  props[GetPropIndex(props, Constants.FS_FontNotFoundInCatalog)].propVal.ival = Constants.FV_DoOK;
  props[GetPropIndex(props, Constants.FS_FontNotFoundInDoc)].propVal.ival = Constants.FV_DoOK;
  props[GetPropIndex(props, Constants.FS_LanguageNotAvailable)].propVal.ival = Constants.FV_DoOK;
  props[GetPropIndex(props, Constants.FS_UpdateXRefs)].propVal.ival = Constants.FV_DoNo;
  props[GetPropIndex(props, Constants.FS_UseRecoverFile)].propVal.ival = Constants.FV_DoNo;
  props[GetPropIndex(props, Constants.FS_UseAutoSaveFile)].propVal.ival = Constants.FV_DoNo;
  props[GetPropIndex(props, Constants.FS_OpenFileNotWritable)].propVal.ival = Constants.FV_DoOK;
  returnp = new PropVals();
  var file = Open(path, props, returnp);
  return file;
}

function CloseAll()
{
  doc=app.FirstOpenDoc
  while(doc.id !=0)
  {
    doc2=doc.NextOpenDocInSession;
    Console("  Closing doc " + doc.Name + "...");
    doc.Close(Constants.FF_CLOSE_MODIFIED);
    doc = doc2;  
  }

  book=app.FirstOpenBook
  while(book.id !=0)
  {
    book2=book.NextOpenBookInSession;
    Console("  Closing book " + book.Name + "...");
    book.Close(Constants.FF_CLOSE_MODIFIED);
    book=book2
  }
}

EOS

print "Processing book '$book_file'...\n";
`echo -n '' > /mnt/c/users/$ENV{USER}/AppData/Roaming/Adobe/FrameMaker/14/consfile.txt`;  # empty out the log file

my $jsx_file = "/mnt/c/Users/$ENV{USER}/Documents/Adobe Scripts/fm_to_xml.jsx";  # script must be here to avoid Adobe security warnings
remove_tree($xml_dir, $xml_dir_temp);
make_path($xml_dir_temp);

chomp (my $book_file_win = `wslpath -a -w '$book_file'`);
chomp (my $xml_file_win = `wslpath -a -w '$xml_file_temp'`);
chomp (my $jsx_file_win = `wslpath -a -w '$jsx_file'`);

$book_file_win =~ s!\\!\\\\!g;
$xml_file_win =~ s!\\!\\\\!g;

$jsx_script =~ s!BOOK_FILE!$book_file_win!;
$jsx_script =~ s!XML_FILE!$xml_file_win!;

open(JSX_FILE, '>', "${jsx_file}") or die "Can't open '${jsx_file}': $!";
print JSX_FILE $jsx_script;
close JSX_FILE;

my $book_dir = dirname($book_file);
`find '$book_dir' -name '*.lck' -print0 | xargs -0r rm`;  # try to remove lingering lock files

my $cmd = "\"/mnt/c/Program\ Files\ \(x86\)/Adobe/Adobe\ ExtendScript\ Toolkit\ CC/ExtendScript\ Toolkit.exe\" -run '$jsx_file_win'";
print "Running:\n  $cmd\n";
`$cmd`;

my $start_time = time();
while (!-e "${book_file}.lck" && (time() - $start_time) < 10) {`sleep 2`;}

print "Waiting for book lock file to disappear...\n";
while (-e "${book_file}.lck") {`sleep 2`;}

print `cat /mnt/c/users/chrispy/AppData/Roaming/Adobe/FrameMaker/14/consfile.txt | egrep -v '(is not available|will be used in this session)'`;  # strip out missing font messages
if (-e $xml_file_temp) {
`sed -i 's!\\]\\]>!]]\\&gt;!' $xml_dir_temp/*.e*`;  # ']]>' must be escaped in XML, but FrameMaker doesn't
 print "\n*** XML write for '$bookname' succeeded.\n\n";
 rename($xml_dir_temp, $xml_dir);
} else {
 print "\n*** XML write for '$bookname' FAILED.\n\n";
 remove_tree($xml_dir_temp);
}

Caveat emptor: This whole approach is hacky. The "error-checking" is a ten-second timeout after which it throws up its hands if it sees no signs of life from FrameMaker.

Note that in my case, I use Russ Ward's excellent XRef Wizard plugin to fix duplicate IDs that mess up XML output. If you have this plugin, uncomment the fixLinks(book) line above.

If you're running a different version than FrameMaker 2017, you'll need to change the #target comment in the embedded JSX script.

If you're a glutton for punishment, you can also try the Makefile I used to automate this:

FM2XML = $(shell which fm2xml.pl)

fm_book_files := \
 some/dir/book1.book \
 /yet/another/book2.book

book_names := $(patsubst %.book, %, $(notdir $(fm_book_files)))
xml_dirs := $(foreach b, $(book_names), ./xml/$b)
dirs := $(dir ${fm_book_files})

vpath %.book $(dir $(fm_book_files))


all: $(xml_dirs)
print-%: ; @echo $* = $($*)

.SECONDEXPANSION:
$(xml_dirs): ./xml/%: %.book
        ${FM2XML} ${<} ${@}

But if you hold your breath and don't move, it all works. :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM