Exploiting FrameMaker MIF as XML, Reading Bookfiles
[Read this for an introduction to what I'm talking about].
Now that we’ve got our FrameMaker documents in XML, how can we exploit their new format? One of the first things I did was to create new ways of reading (eventually changing) the simple data stored within them. This isn’t all that earth-shattering, but when you consider how difficult it is to find and change some values in the FrameMaker UI this is a big win. Where to start? Bookfiles.
To be able to apply stylesheets or data-collection tools to books (rather than individual files), I need to be able to collect a books components. So, convert your bookfile to MX (yeah, it works on bookfiles as well as chapter files), and search through it for one of the filenames you know is a part of the book (you’ll probably want to pretty-print the XML first). I get something like this:
<BookComponent>
<FileName>`<c\>ch01'</FileName>
<Unique>27107</Unique>
<StartPageSide>StartRightSide</StartPageSide>
<PageNumbering>Restart</PageNumbering>
<PgfNumbering>Continue</PgfNumbering>
<PageNumPrefix>`'</PageNumPrefix>
<PageNumSuffix>`'</PageNumSuffix>
<DefaultPrint>Yes</DefaultPrint>
<DefaultApply>Yes</DefaultApply>
</BookComponent>
MX in this case has a pretty comprehensible structure, so we’ll need to grab a BookComponent/FileName, do a little text processing to remove the funky characters, and potentially append our MX file extension (I chose “.mx”). Here’s a very simple stylesheet to do just that:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="@*|node()">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="/">
<xsl:element name="components">
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
<xsl:template match="//BookComponent/FileName">
<xsl:param name="extension" select="'.mx'"/>
<xsl:variable name="str-after">
<xsl:value-of select="substring-after(., '>')"/>
</xsl:variable>
<xsl:element name="component">
<xsl:value-of select="substring($str-after,
1,
string-length($str-after) - 1)"/>
<xsl:value-of select="$extension"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
When you run that on a MX bookfile, you should see an output like this (note that the file extension is customizable above):
<?xml version="1.0"?> <components> <component>svcTOC.fm.mx</component> <component>foreword.mx</component> <component>ch00.mx</component> <component>ch01.mx</component> <component>ch02.mx</component> <component>ch03.mx</component> <component>ch04.mx</component> <component>ch05.mx</component> <component>ch06.mx</component> <component>ch07.mx</component> <component>ch08.mx</component> <component>ch09.mx</component> <component>appa.mx</component> <component>appb.mx</component> <component>appc.mx</component> <component>appd.mx</component> <component>appe.mx</component> <component>svcIX.fm.mx</component> <component>svcAPL.fm.mx</component> <component>svcLOR.fm.mx</component> </components>
That’ll give us a nice structure to direct other processes to the individual component files.
The code is also available here or darcs get http://kfahlgren.com/code/mx/.