CREATING AN XML TEMPLATE FROM AN EXISTING DOCUMENT

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.

Document Setup

To support XML import the sample document needs to be set up as follows:

  1. All of the child elements for a parent XML element need to reside in a single text frame or threaded text frames
  2. Paragraph styles need to be named consistent with XML naming convention (no spaces or special characters)
  3. All text styling needs to be with Paragraph and character styles. A nested paragraph style can be used as has been done in the sample document for the dollar amount
  4. The image to be imported needs to be sized to fit within the text frame column and will reside in a folder named Images inside the same folder as the XML file to be imported.

XML Tagging

To set this document up for XML import manually takes a little doing.

  1. Create an XML tag for the enclosing text frame
  2. Select each paragraph in order and create an XML tag with the same name as its paragraph style. Note: Make sure that you do not select the paragraph return at the end of the paragraph.

Import XML

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

DEMONSTRATION SCRIPT

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.

Get Selected Container

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

Get Tag Name for Container

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

Tag Selected Frame

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

Map Tags to Paragraph Styles

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

 

ONWARD AND UPWARD

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.