READING AND WRITING TEXT FILES

Previous blog posts have shown how a plain text file can be used as part of a workflow for importing images or text into InDesign. Writing and reading text files can be useful for a number of other automation issues. One workflow might use a plain text file to write tab/return delimited for use in tables or a number of other scenarios. Think of a table in InDesign where individual columns have text colored differently. To use this text in another table or document, you might want the text to be saved as comma/return delimited text without styling. Place the file into another location as needed and convert to table using different styling: fonts, colors, and other attributes. A solution to this workflow could be as simple as having a script convert the table to text and save as a plain text file. We will work through some of the issues involved in writing the script.

Our example script will expect the user to either select a table, or a text frame that contains the table.

Get Selected Table

property errStr: "Requires table or text frame with table to be selected"
try
   set tableRef to getSelectedTable()
on error errStr
   activate
   display alert ("Error: " & errStr)
end try
(*Returns reference to table selected or table of selected text frame*)
on getSelectedTable()
   set errStr to "Requires a table or text frame containing a table to be selected."
   tell application "Adobe InDesign CC 2019"
      set selList to selection
	if selList is {} then error errStr
	set selItem to item 1 of selList
	set classTest to class of selItem
	if classTest is not in {text frame, table} then
	   error errStr
	end if
	if classTest is text frame then
	   set tableRef to table 1 of selItem 
	else
	   set tableRef to selItem
	end if
   end tell
   return tableRef
end getSelectedTable

Notice in the above that the error string (errStr) is defined in one of two events:

  • the variable selList is empty (no selection made)
  • the class of item 1 of the selection list (selList) is not a table or text frame

A third error can be generated should a text frame be selected that does not have a table. In this event, a system error is generated.

To test, create a simple table in an InDesign document. Copy the script above and paste in a new Script Editor file. Compile and run the script with the text frame containing the table selected.

Once you have verified that this part of the script works as anticipated, you are ready to have the script convert the table to text. Since you do not want to modify the existing document, this portion of the script will copy the text frame, and have its table (table 1) convert to text and then remove the copied text frame.

To test, Copy the following to a new script. This assumes the user has a text frame selected that contains a table. Select the text frame with the table and run the script. The result window should display the text from the table as tab delimited text.

Convert to Text

tell application "Adobe InDesign CC 2019"
   copy
   paste
   set frameRef to item 1 of selection
   set tableRef to table 1 of frameRef
   tell tableRef to convert to text
   set textStr to contents of contents of frameRef
   delete frameRef
end tell
textStr

Write Text to File

All that is left for the script is to write the text to a plain text file. Writing text to a text file has a few requirements:

  • a path to where the file will be generated needs to be defined
  • an open for access command with write permission creates the file
  • the file is closed after writing the text to the file

A handler (subroutine) will work nicely for this purpose.

(*Writes text to file designated by filePath variable*) 
on writeToFile(textStr, filePath)
   if filePath does not end with ".txt" then
      set filePath to filePath & ".txt"
   end if
   set fileRef to open for access file filePath with write permission
   write textStr to fileRef as «class utf8»
   close access fileRef
   return filePath as alias
end writeToFile 

To test the handler, add the following at the top of the script to define the filename and the text to write. Next, add code to call the handler and place the result in the variable myTest.

set thePrompt to "Select folder and name for text file"
set filePath to (choose file name with prompt thePrompt) as string
set textStr to "just testing"
set myTextFile to my writeToFile(textStr, filePath)
set myTest to info for myTextFile 

THE COMPLETE SCRIPT

Now that the three pieces for the script are tested and work as designed, it is time to tie them together into a workable script.

property errStr : "Requires table or text frame with table to be selected"
set thePrompt to "Select folder and name for text file"
try
   set tableRef to getSelectedTable()
   --convert to text
   tell application "Adobe InDesign CC 2019"
	copy
	paste
	set frameRef to item 1 of selection
	set tableRef to table 1 of frameRef
        tell tableRef to convert to text
	set textStr to contents of contents of frameRef
	delete frameRef
   end tell
   --write to file
   set filePath to (choose file name with prompt thePrompt) as string
   set myTextFile to my writeToFile(textStr, filePath)
   set myTest to info for myTextFile
on error errStr
   activate
   display alert ("Error: " & errStr)
end try 
--Add the handlers from Above: getSelectedTable() and WriteToFile()

There is one thing you might want to add to the script to make it more user friendly: Because the user is not going to be able to read the Result window to verify the file being created, you may decide to create a log file with the file information:

LOG FILE

The write command for AppleScript has some interesting optional parameters one of which is as. In addition to allowing text to be written in different formats, lists and records can also to be written to plain text files. This is great for saving script preferences and data such as the result of the info for command above. A simple example script using part of the the file info record from above can get you started.

Write Log

set logRec to {name:"LastTest.txt", ¬
creation date:date "Tuesday, May 14, 2019 at 1:18:02 AM", file type:"TEXT", ¬
file creator:"ttxt", type identifier:"public.plain-text", locked:false, busy status:false}
set monthNum to month of (current date) as number
set mm to (text -1 thru -2 of ("0" & monthNum)) as string
set dayNum to day of (current date)
set dd to (text -1 thru -2 of ("0" & dayNum)) as string
set yy to year of (current date)
set dateStr to (dd & mm & yy)
set folderPath to path to desktop from user domain as string
set logPath to folderPath & "Log " & dateStr
set fileRef to open for access file logPath with write permission
write logRec to fileRef as list
close access fileRef
--read back 
set fileRef to open for access file logPath
set newList to read fileRef as list
close access fileRef
set newRec to item 1 of newList
set newStr to "File Created:" & return
set newStr to newStr & "Name: " & name of newRec & return
set newStr to newStr & "Date: " & (creation date of newRec as string) & return
set newStr to newStr & "File type: " & file type of newRec
activate
display alert newStr 

Notice how the date string (dateStr) is put together using the (text -1 thru -2 of ("0" & dayNum)) convention to add a zero to the front of the month and day number when only one digit.

ONWARD AND UPWARD

How would you add the code for the log file to the script above? Hint: Place the code inside a handler. Remove the line that sets the value for logRec and replace it by passing the variable myTest to the handler. Make sure the variable in the handler that receives the passed value is named logRec.

--the handler
on writeLog (logRec)
--handler code here
end writeLog
--the call to the handler
writeLog (myTest) 

Now that you have an idea of writing to plain text files, you might want to add the ability to log errors to a log file as part of your next script.

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.