XML FOR BUSINESS

Business cards, that is. In this week’s blog post we will use what we have learned about XML and Adobe InDesign to create a project for printing business cards 8-up on a page. The cards will be “butt-cut” meaning that there is no trim provided between the cards.

As we have seen in this blog series to date, the success of an XML automated project depends on two factors:

  • A properly formatted XML file
  • An InDesign document structured to receive the file

Although the process of setting up the InDesign document can be done manually, we will use a couple of scripts to automate some of the process.

THE XML FILE

To keep things simple, our XML file will define the following elements:

Root
   Employees
      Employee
         Name
         Title
         Cel  

The Cel element is for the cell phone number of the employee. The XML file provided, reads similar to the following which shows a single entry:

<root><employees><employee><name>Rob Bray</name><title>Consultant</title><cel>Cel 000 000-0000</cel></employee>
      </employees></root>

This is slightly different than the XML file used in our previous example where each individual element for an entry was followed by a line return. Thankfully, this structure will not be a problem as InDesign’s XML import preferences can be set up to add the line returns.

NOW TO CREATE THE DOCUMENT.

Our document will be a single page document, set up for print intent with Primary Text Frame enabled.
Size will be 42 picas wide by 3 picas high, having 2 columns with a 4 pica gutter.
Margins for the document will be top: 1 pica, bottom: 1 pica, left: 2 picas, right: 2 picas

A-Master

Most of the work will be on the master page. We will use three layers:

  • Layer 1 – The layer that contains the dynamic text
  • Static – The layer that contains all of the information that does not change
  • Dieline – A non printing layer to indicate the outline for the individual cards

Lock Layer 1 to make it easier to work on the other two layers. Set up the Dieline layer as shown below:

nec ullamcorper mattis, pulvinar dapibus leo.

Dieline Layer

On page 1 of the master page, make sure you are on the Dieline layer. Create a rectangle starting in the upper left hand corner of the page (0,0). Make the rectangle 21 picas wide by 12 picas high. Give it an outline stroke of 1 pt.

Copy the following to a new script in AppleScript Editor:

Duplicate Grid

set numCols to 2
   set numRows to 4
   set horiz to 252
   set vert to 144
   set y0 to 0 --top move to
   set x0 to 0 --left move to
   set beginX to 0 --reset value for x0
   set counter to 0
   tell application "Adobe InDesign CC 2015"
      set measurement unit of script preferences to points
      set docRef to document 1
      set selList to selection
      set selItem to item 1 of selection
      tell docRef
         repeat with i from 1 to numRows
            repeat with j from 1 to numCols
               if counter > 0 then
                  duplicate selItem
                  move selItem to {x0, y0}
               end if
               set x0 to x0 + 252
               set counter to counter + 1
            end repeat
            set x0 to beginX
            set y0 to y0 + 144
         end repeat
      end tell
   end tell

Save the script and run it with the rectangle selected.

Lock the Dieline layer and switch to the Static layer. Save the document.

Static Layer

Create the static items for your first business card as needed and group them.

Now, change the values of y0, x0, and beginX at the top of the Duplicate Grid script to the top y and left x values for your static text group. Settings for a group butting to the top and left margins would be as follows:

   set y0 to 12
   set x0 to 18
   set beginX to 18 

With the group selected, run the Duplicate Grid script again.

Layer 1

Lock the Static layer and unlock Layer 1. Save the document.

With Layer 1 active, resize the Primary Text Frame to accommodate your dynamic text items.

Change column count in Text Frame Options (Command+B) to 1.

Add Tags and Placeholder Text

On page 1 of the document (not the master page), you should have the Primary Text Frame available.

Add placeholder text for Name, Title, and Cel to the Primary Text Frame.

Add paragraph styles for Name, Title, and Cel.
Notice that the placeholder text and paragraph style names are exactly the same and correspond with the XML tags in the XML file.

Style the placeholder text. Make sure that the Name paragraph style includes Keep Option “Start Paragraph: In Next Frame”.

Adding XML Tags

You can add XML tags manually or use our script LoadTags.scpt (introduced in our previous script blog). Using the script assures that tags will be named as needed, and all tags needed will be added. If using the script, select the XML file when prompted.

You should now have the following tags in InDesign’s Tags panel.

From the Context Menu for the Tags panel, select Map Tags to Styles.

Click on the Map by Name button.

ave the document.

Markup the Document

Marking up your document for a multiple-item XML can be a tedious and error-prone process. To eliminate this, use our script XML_Tag Markup.scpt. The following code assumes that tags, paragraph styles, and all have been set up as described above. Little error checking is provided, so use with caution.

XML_Tag Markup

   set tagName to "Employee"
   tell application "Adobe InDesign CC 2015"
      set docRef to document 1
      tell docRef
         set mTagRef to my getTag(docRef, tagName)
         set selList to selection
         set frameRef to item 1 of selList
         set rootElement to XML element 1
      end tell
      set parentElement to my tagFrame(docRef, frameRef, tagName)
      set paraCount to count of paragraphs of frameRef
      repeat with i from paraCount to 1 by -1
         tell frameRef
            set paraRef to object reference of paragraph i
            set styleRef to applied paragraph style of paraRef
            set styleName to name of styleRef
            set tagRef to my getTag(docRef, styleName)
            set textRef to object reference of text from character 1 to character -2 of paraRef
         end tell
         tell parentElement
            set elementRef to make XML element with properties {markup tag:tagRef}
            markup textRef using elementRef
         end tell
         tell docRef to make XML import map with properties {mapped style:styleRef, markup tag:tagRef}
      end repeat
   end tell --application
   (*Tags the selected text frame. Use with Primary Text Frame selected on page 1*)
   on tagFrame(docRef, frameRef, tagName)
	set masterName to tagName & "s"
	set tagRef to getTag(docRef, tagName)
	set mTagRef to getTag(docRef, masterName)
	tell application "Adobe InDesign CC 2015"
	   tell docRef
	      set rootElement to XML element 1
	      set name of frameRef to tagName
	   end tell
	   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
   (*Checks for existence of tag. If it doesn't exist, it is created*)
   on getTag(docRef, tagName)
	set tagRef to missing value
	tell application "Adobe InDesign CC 2015"
	   tell docRef
		if exists XML tag tagName then
		   return XML tag tagName
		else
		   set tagRef to make XML tag with properties {name:tagName}
		end if
	   end tell
	end tell
	return tagRef
   end getTag

Select the text frame with the placeholder text and run the script. When prompted, enter “Employee”. This is the name for the parent element of the XML text elements.

If you did everything right to this point, the Structure panel (Command + Option + 1) and Story Editor (Command+Y with text selected) should look like the following.

If your Structure and Story Editor look correct, save the document. Switch to A-Master. Unlock Layer 1 if still locked.

Duplicate the Primary Text Frame

Because you cannot duplicate the Primary Text Frame, you will use another script: Primary Grid.scpt. This gets the bounds of the chosen text frame (the Primary Text Frame on the master page) and creates multiple text frames for the remaining business cards on the page. As part of the script, the text frames are threaded.

Primary Grid Script

   set numCols to 2
   set numRows to 4
   set horiz to 252
   set vert to 144
   set counter to 0
   tell application "Adobe InDesign CC 2015"
      set measurement unit of script preferences to points
         tell document 1
            set frameStyle to "[Basic Text Frame]"
            set selList to selection
            set selItem to item 1 of selection
            set lastFrame to selItem
            copy geometric bounds of selItem to {y0, x0, y1, x1}
            set beginX to x0
            set beginX1 to x1
               tell page 1 of master spread "A-Master"
                  repeat with i from 1 to numRows
                     repeat with j from 1 to numCols
                        if counter > 0 then
                           set thisFrame to make text frame with properties {geometric bounds:{y0, x0, y1, x1}, applied object style:frameStyle}
                           if counter < (numRows * numCols) then
                              set previous text frame of thisFrame to lastFrame
                              set lastFrame to thisFrame
                           end if
                        end if
                     set x0 to x0 + 252
                     set x1 to x1 + 252
                     set counter to counter + 1
                 end repeat
                 set x0 to beginX
                 set x1 to beginX1
                 set y0 to y0 + 144
                 set y1 to y1 + 144
            end repeat
         end tell
      end tell
   end tell 

With the Primary Text frame selected, run the Primary Grid script. Activate Show Text Threads (Command+Option+Y). Your document should now look similar to the following:

If all went well, save the document.

Document after running Primary Grid script

Set XML Import Preferences and Import the XML file

The script ImportToRoot (below) sets up XML import preferences for an XML file that does not include paragraph returns after individual text elements. Notice that for this set ignore whitespace is set to true.

Make sure you have Smart Test Reflow and Limit to Primary Text Frames checked for InDesign’s Type Preferences. Add Pages should also be set to End of Document.

Import To Root

   (*Relies on Primary Text Frame being named as defined in variable frameName*)
   set frameName to "Employee"
   try
      set fileRef to getXMLFile()
      tell application "Adobe InDesign CC 2015"
         set docRef to document 1
         my setImportPrefs(docRef)
         set rootElement to XML element 1 of docRef
         tell rootElement to import XML from fileRef
         set frameRef to text frame frameName of docRef
         tell frameRef
            place XML using rootElement with autoflowing
         end tell
         tell docRef to map XML tags to styles
      end tell
      on error errStr
         activate
         display alert errStr
      end try
   (*Sets import prefeences for XML that does not include paragraph returns*)
   on setImportPrefs(docRef)
      tell application "Adobe InDesign CC 2015"
         tell XML import preferences of docRef
            set allow transform to false
            set import style to merge import
            set repeat text elements to true
            set create link to XML to false
            set import to selected to false
            set ignore whitespace to true
            set import CALS tables to false
            set import text into tables to false
            set ignore unmatched incoming to true
            set remove unmatched existing to true
         end tell
      end tell
   end setImportPrefs
   (*Has user select file and checks to make sure file is an XML file*)
   on getXMLFile()
      set fileRef to choose file with prompt ("Select XML file for placing") without invisibles and multiple selections allowed
      set fileInfo to info for fileRef
      if name extension of fileInfo is not "XML" then
         error "Wrong file type chosen"
      end if
      return fileRef
   end getXMLFile

Save the document.

ON YOUR OWN

There you have it. Business cards are created to conform to the XML file. This can include any number of XML entries.

Our final document.

You may have noticed that we saved the document after each major step above, that is, if all went well. If there was a problem, revert the document back to its last save. (File > Revert). Review your last step to discover the problem.

Again, to keep the code pared down to the bare essentials, values for variables in the scripts have been hard-coded. This should be replaced with a custom dialog. You will also want to add error handling to take care of a situation such as the user not having a text frame or rectangle selected when running a script that requires a selected item.

If creating business cards (or other multiple item documents) are something you do quite often, you may want to set keyboard shortcuts for your script (once you have replaced hard-coded values with a user dialog).

Again, the scripts used here as well as the XML file are provided in a download available from the AppleScript page of this site.

See if you can modify the business card layout to include an image of the employee. The image will need to be an anchored page item (see our blog post for March 28). The big caveat for this is that the images need to be sized at 100% and the text frame to which it will be anchored needs to be large enough to accommodate the image when it is first placed. Good luck.