Introducing AbstractIdmlDocument

May 22nd, 2010 by afink

In version 1.0 there has only been support for container-based IDML document (.idml), which has been represented by the de.fhcon.idmllib.api.elements.Document object. As outlined in our first IDMLlib article, snippets support was one of the major features for the next IDMLlib release. Besides the obvious InDesign-Snippet (.idms) we support InCopy-Assignment (.icma) and InCopy-Markup-Language (.icml) files. For more information about different IDML files types  see this article from Adobe’s Heath Lynn.

The fundamental difference between .idml and .idms,icma,icml is the fact that only .idml is a container based format, all other IDML files are single .xml files that expose their contents by just openening them in a simple text-editor. Where .idml files use references to other files for Spreads among other objects, the single file format has all the information right inside the file.

An good example of the different handling in .idml and .idms is the Story node. Where you will find something like this in an .idml file as a direct child of the <Document/> node:

<idPkg:Story src="Stories/Story_uce.xml"/>

The same story in an .idms file will look like this and is also a direct child of the <Document/> node :

<Story AppliedNamedGrid="n" AppliedTOCStyle="n" Self="uce" StoryTitle="$ID/" TrackChanges="false">
    <StoryPreference FrameType="TextFrameType"
        OpticalMarginAlignment="false" OpticalMarginSize="12"
        StoryDirection="LeftToRightDirection" StoryOrientation="Horizontal"/>
    <InCopyExportOption IncludeAllResources="false" IncludeGraphicProxies="true"/>
    <ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Body">
        <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/$ID/[No character style]">
            <Content>This is a simple Test</Content>
        </CharacterStyleRange>
    </ParagraphStyleRange>
</Story>

This means loading a Story from an .idml is a complete different thing than loading it from a snippet.

To handle the differences between these document types, it was necessary to introduce a new object, the de.fhcon.idmllib.api.elements.SnippetDocument which encapsulates the different logic. Our first approach to handle the different document types were added to the de.fhcon.idmllib.api.elements.Idml object in the form of 3 additional methods:

  • getAsSnippetDocument():SnippetDocument
  • isSnippetDocument():boolean
  • isZipContainer():boolean

Together with the already existing getDocument():Document method is was very easy to distinguish between container and single IDML documents and doing further processing using the correct document object.

However, after the functionality was introduced we noticed that the approach was practical but added a lot of boilerplate code to every loaded idml if you do mixed (.idml and .idms) document processing. So we introduced the de.fhcon.idmllib.api.elements.AbstractIdmlDocument which encapsulates the methods that both document objects share and added additional methods:

  • isSnippetDocument:boolean
  • isContainerDocument():boolean
  • getAsSnippetDocument():SnippetDocument
  • getAsDocument():Document
  • getAsAbstractDocument():AbstractIdmlDocument

Same stuff only in a different object, could be your first thought. But this new object togehter with the DocumentUtil class made processing of .idml and .idms really comfortable as you will see, soon. The only methods that are specific to the respective document object are the ones that access or modify objects that are either referenced or included, roughly around 12 methods.
The new DocumentUtil class deals with some of these methods and provide a unified interface to both document types by deciding when a document needs to be casted to the concrete document object.

The following code can either be used to load an .idms or and .idml file and process all PageItems on all Spreads by only changing the path of the loaded file to an .idml or an .idms:

Idml idml = new Idml("many_different_pageitems.idml");
SpreadIterator spreadIterator = DocumentUtil.getSpreadIterator(idml.getAbstractDocument());
System.out.println("idml.getAbstractDocument().getCMYKProfile() = " + idml.getAbstractDocument().getCMYKProfile());
System.out.println("idml.getAbstractDocument().getSelf() = " + idml.getAbstractDocument().getSelf());
System.out.println("idml.getAbstractDocument().getDOMVersion() = " + idml.getAbstractDocument().getDOMVersion());
while(spreadIterator.hasNext()) {
 Spread spread = spreadIterator.next();
 PageItemIterator pageItemIterator = SpreadUtil.getPageItemIterator(spread);
 while(pageItemIterator.hasNext()) {
   AbstractIdmlPageItem pageItem = pageItemIterator.next();
   System.out.println("I am a "+ pageItem.getPageItemType().toString()+" with id "+pageItem.getSelf());
 }
}

I hope this sheds some light on the new AbstractIdmlDocument object, again feedback is very welcome.
Register yourself with a valid email address and put your thoughts in the comments.
The code used in this article is part of the IDMLlib distribution.

Stay tuned for more and have nice weekend.

Leave a Reply

You must be logged in to post a comment.