自动将Framemaker文档(* .fm)保存为Xml文件的过程

时间:2015-04-17 10:41:42

标签: javascript adobe extendscript framemaker

我们有一个进入文件夹的Framemaker文档文件(* .fm文件)列表。我们需要获取这些文件并转换为xml格式(与“文件”菜单中的saveAs opertion相同)。

我已经编写了以下函数来将fm文件保存到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);

}

如何自动化此过程以便代码检查 -

  1. 文件夹中的新fm文件
  2. 将fm文件另存为xml
  3. 将保存的fm文件移动到其他文件夹
  4. 由于

2 个答案:

答案 0 :(得分:0)

如果您使用的是Windows,则可以编写一个简单的批处理文件,通过命令行中的批处理文件(.bat)循环运行您的extendscript。

答案 1 :(得分:0)

我需要将一组FrameMaker .book文件另存为.xml文件。为此,我编写了一个在Windows 10 WSL(Linux的Windows子系统)下运行的perl脚本。它有两个参数:.book文件文件名和XML输出目录名

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

此perl脚本将一个临时ExtendScript文件写到“我的文档”中的Adobe Scripts目录中(以避免出现安全对话框),然后运行它,然后从XML保存打印控制台输出。您将需要安装ExtendScript Toolkit以及FrameMaker。

这是fm2xml.pl脚本:

#!/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);
}

随心所欲的人:整个方法都是很棘手的。 “错误检查”是一个十秒的超​​时,在此之后如果没有看到FrameMaker的生命迹象,它将举起手来。

请注意,就我而言,我使用Russ Ward's excellent XRef Wizard plugin来修复使XML输出混乱的重复ID。如果您有此插件,请取消注释上面的fixLinks(book)行。

如果运行的版本不同于FrameMaker 2017,则需要在嵌入式JSX脚本中更改#target注释。

如果您是贪食的惩罚者,也可以尝试使用我用来自动执行此操作的Makefile:

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} ${<} ${@}

但是,如果屏住呼吸并且不动,那一切都会起作用。 :)