AppleScript Record "type" for JSON files

Hello!

I am trying to create an AppleScript that will process only JSON files. As part of the selection-filtering, I used the following snippet:

set this_selection to the selection
	if this_selection is {} then error "Please select some content."
	
	repeat with this_item in this_selection
		set current_name to the name of this_item
		set docPath to path of item 1 of this_item
		
		-- Using the 'txt' from 'type2' enumeration to select the JSON file
		-- This is not ideal, but gets me at least part of the way
		-- Additional filtering (such as document 'kind') can be done
		if type of this_item is txt then
		-- …
		-- Do the processing here
		-- …
		else
			display alert "DEVONThink Pro" message "No JSON selected." as warning giving up after 3
		end if
	
	end repeat

The issue is that the type is not being set to txt, even though the DevonThink3 AppleScript dictionary indicates that this should be the value for all text files (as part of the type2 enumeration).

Using Script Debugger, I can see that the type value for the selected JSON file is indeed a text file.

Screen Shot 2020-07-20 at 2.29.46 PM

I have been able to work around this by using this if condition instead:

…
if kind of this_item is "JSON File" then
…

but wanted to check if the earlier type check for txt types is incorrect, or a bug? The corresponding DT3 dictionary for type2 enumeration is:

Screen Shot 2020-07-20 at 2.30.45 PM

Thanks @ngan,

This did the trick! I replaced the if condition to be:

		if (type of this_item as string) is "text" then

and the script is now working.

Thanks again for the quick response. Much appreciated.

As this is certainly feasible, I think it might be a lot (a lot, lot, lot) easier doing with a JavaScript file. You could wrap JSON.parse() into a try - catch block so that you don’t need to check for JSON first. Like so

let app=Application("DEVONthink 3");
app.includeStandardEditions = true;
let sel = app.selection();
sel.forEach(file => {
  /* no need for these two to process JSON */
  let name = el.name();
  let path = el.path();
  try {
    let result =  JSON.parse(file.plainText());
  } catch(e) {
    // process exception
 }
})

As a side note: I’m not sure, why you use path of item 1 of this_item in your AppleScript to get at the path of the current item – the item is not a list, I think, so you could just refer to it directly, as you did with name in the line directly before.

AFAIK from many trial and errors, this is necessary sometimes. In scripting DT, you don’t always get a list when it is an array of reference objects. Sometimes the array becomes a list of list with each item being a list containing an item. Each’s item 1 is to coerce the item into an item instead of a list. I can’t tell exactly the condition of its happening but it happens. Perhaps the DT experts will be able to explain it better.

However, if we use
repeat with n from 1 to count of this_selection, the AppleScript will always coerce item n into an item. That’s why I always use repeat with n from … whenever I’m manipulating arrays with reference objects.

I was referring to the following two lines

set current_name to the name of this_item
set docPath to path of item 1 of this_item

Even in AppleScript, I doubt that this_item changes from a single object to a list of objects from one incantation to the next :wink:

Try selecting only 1 item in selection and see what you get from the each in repeat statement? :thinking:

If you use Repeat with each, each will return as a list of one item.

If you use Repeat with n from , b will return the reference object.

I’m not an expert, just discussing what I have found… :grinning:

One last time: We’re in a loop here, and this_item is the current element. It is either a list or an object. It can’t change what it is inside the same loop. Unless AppleScript is even weirder than I think.

Oh, and the loop is repeat with this_item in this_selection anyway, so your first case.

See my changed post with two examples.

I am not trying to prove myself correct. This is a lesson learnt from many trial and errors that might be beneficial to others. In fact, a few years ago a forum member also mentioned in this forum about this after many rather frustrating puzzles in using repeat with each to manipulating array with objects.

Sometimes a loop won’t work when using each, but using each’s item 1 will. But as a non-pro user, I find using repeat with n from … is the safest way to go for.

After having had a closer look, I understand that you’re comparing apples to oranges here :wink:

You have one loop that iterates over the list (repeat with item in list), whereas the other one does not. It just iterates over the numbers from 1 to count list. That is fundamentally different. I’m using “item” and “list” here to make the concepts clearer (hopefully).

repeat with item from list

iterates over the list, returning each of its elements in turn. So item is always exactly this: an item.

In

repeat with n from i to count a

you do not access the list at all. You just get at the number of its elements (count). Then, inside the loop, you have to access the list with a's item n. Which of course gives you an item.

In conclusion: Just because both loops use repeat, they do not work the same way. One of AppleScript weirdnesses. There’s more on repeat here. Apparently, Apple thought keywords were expensive, when it conceived of its scripting language. Whereas one has “while”, “repeat”, “for”, “foreach” and so on in other languages, AppleScript only knows “repeat”. Which obviously leads to confusion.

Compare with the same thing in JavaScript:

for (i = 0; i < list.length; i++) {
  console.log(list[i]);  /* item i of list */
}

vs.

list.forEach(item => { console.log(item))}; /* forEach returns each item in turn */

As a layman, I can only share what I learnt from previous practices. But thanks for the explanation. :+1:

@chrillek,

Thanks for pointing out the redundant path of item 1 of this_item. It was probably a hold-over from another script that I used as the foundation.

I changed it to be:

 		set docPath to the path of this_item

and it is working fine.

Using JavaScript is certainly a great recommendation. However, for my use-case, I am just bulk-processing the JSON files (at the file-level), and not parsing them in the script. Hence AppleScript does the job equally well.

Thanks again.