Your prescription for increased productivity and profitability
In the last two posts we created an InDesign template for importing XML files. In the first, a script created the template from scratch, in the second, we started with a document and used the script to add and map the XML tags. Chances are you may have a document that you have created and later decide to set it up for XML import. In this blog we will demonstrate how this can be done. To start, you will need to make sure the document is set up to facilitate the process.
To support XML import the sample document needs to be set up as follows:
To set this document up for XML import manually takes a little doing.
Remember that XML structure starts with a root element with each major element represented in a parent-child relationship. For our sample document there is only one major XML element resulting in the following structure.
Root Products Product Image Brand Name Desc Price Color Packaging Details Product Products Root
The XML text file will need to be structured as shown above. With the document open, choose Import XML from InDesign’s file menu. If the XML file is correctly formed it will import into InDesign’s Structure pane for the document. (Open the Structure pane using the keyboard shortcut Command+Option+1.)
..document XML structure
The XML tagging is added to the document but, as you can see, the text is not styled
…Document tagged but not styled
To add text styling you will next need to map the XML tags to the corresponding paragraph styles.Map Styles
If the Tags panel is not open, choose Utilities > Tags from InDesign’s Window menu. From its menu select Map Tags to Styles.
…Open Map Tags to Styles panel
For each child XML element in the Structure pane named the same as a paragraph style, select the paragraph style name to correspond.
…Mapping XML tag to paragraph style
The good news is that once you have connected the Product element to its main container and mapped tags to styles these will save with the document. With this done you will want to save the document as a template, ready to receive the next XML import.
…After mapping tags to styles
If creating tags and mapping tags to styles seems like a lot of work. You can use the following script to perform the work for you. It’s almost magic. Open the document to be modified, select the container for the story to be tagged, and run the script. Enter the tag name for the story when prompted and the script does the work for you.
try set frameRef to textFrameSelected() on error errStr activate display alert "Error: " & errStr end try (*Returns reference to text frame if frame or insertion point is selected.*) on textFrameSelected() tell application "Adobe InDesign CC 2019" set selList to selection if length of selList = 0 then error "Requires text frame or insertion point selection" end if if class of item 1 of selList = text frame then set frameRef to item 1 of selList else if class of item 1 of selList = insertion point then set frameRef to item 1 of parent text frames of item 1 of selList else error "Requires text frame or insertion point selection" end if end tell return frameRef end textFrameSelected
Define the following variables at the top of the script above:
set promptStr to "Enter tag for story element" set displayTitle to "XML Tag" set dAnswer to "Product"
Add the following statement before the on error statement in the script above:
set tagName to getString(promptStr, dAnswer, displayTitle)
Add the handler at the bottom of the script.
(*Gets string response from user; otherwise throws error*) on getString(promptStr, dAnswer, displayTitle) set userResponse to display dialog promptStr default answer dAnswer default button 2 if text returned of userResponse = "" then error "Valid string not entered" end if return text returned of userResponse end getString
Next, the script creates XML elements for mapping the selected text frame. Add this statement before the on error statement above:
set parentElement to tagFrame (frameRef, tagName)
This calls a handler named tagFrame which in turn calls a handler (getTag) that adds the needed XML tag to the document. Add these handlers to the script.
(*Creates parent XML elements and associates selected frame with its XML element*) on tagFrame(frameRef, tagName) set masterName to tagName & "s" tell application "Adobe InDesign CC 2019" set docRef to document 1 if (count of XML elements of docRef) > 1 then error ("Structure has already been created") end if set mTagRef to my getTag(docRef, masterName) set tagRef to my getTag(docRef, tagName) set rootElement to XML element 1 of docRef tell rootElement set masterElement to make XML element with properties {markup tag:mTagRef} end tell tell masterElement set parentElement to make XML element with properties {markup tag:tagRef} end tell tell parentElement to markup using frameRef end tell return parentElement end tagFrame (*Creates tag given tagName that is checked using checkName handler. If error can return missing value*) on getTag(docRef, tagName) set tagRef to missing value tell application "Adobe InDesign CC 2019" tell docRef if exists XML tag tagName then set tagRef to XML tag tagName else set tagRef to make XML tag with properties {name:tagName} end if end tell end tell return tagRef end getTag
All that is left is to map the paragraph styles to XML tags to implement text styling. A handler named tagParagraphs will go through the paragraphs of the story and map XMl tags of the same name to the styles. Adding a call to this handler, the try block at the top of the script should now read as follows:
try set frameRef to textFrameSelected() set tagName to getString(promptStr, dAnswer, displayTitle) set parentElement to tagFrame(frameRef, tagName) tagParagraphs(frameRef, parentElement) on error errStr activate display alert "Error: " & errStr end try
Finally, add the tagParagraphs handler to the bottom of the script
on tagParagraphs(frameRef, parentElement) tell application "Adobe InDesign CC 2019" set docRef to active document set storyRef to parent story of frameRef tell storyRef set paraCount to count of paragraphs repeat with i from 1 to paraCount set paraRef to object reference of paragraph i set styleName to name of applied paragraph style of paraRef if styleName is not in {"[Basic Paragraph]"} then set styleRef to paragraph style styleName of docRef set tagRef to my getTag(docRef, styleName) tell parentElement set elementRef to make XML element with properties {markup tag:tagRef} end tell set textRef to object reference of text from character 1 to character -2 of paraRef tell elementRef markup using textRef end tell tell docRef make XML import map with properties {mapped style:styleRef, markup tag:tagRef} end tell end if end repeat end tell end tell end tagParagraphs
Working with XML takes a little discipline. A simple thing like a mismatched capital for a tag or an image incorrectly sized can cause havoc when it comes to importing your XML file. Until you get comfortable with the process, it is a good idea to open the XML file in a text editor and compare its structure with the document XML structure prior to importing.
Disclaimer:
Scripts provided are for demonstration and educational purposes. No representation is made as to their accuracy or completeness. Readers are advised to use the code at their own risk.