Jump to content

Pass JSON string as filter argument?


Recommended Posts

I tried to search and find an answer to this question, but couldn't. If it's out there, I apologize. I did actually try before posting. Howerver, I'm wondering about the sophistication possible in the strings passed as arguments in script filters. I've seen a number of workflows that pass multiple pieces of data separated by some custom delimiter, but even then, it's typically no more than 3 items. I'm wondering what the specific limitations there are in script filter arguments? Is there some character count? Would the tab and newlines in a JSON string be mangled? If one wants to send a decently large amount of data through the arg, what's the best method?

 

Obviously, I have the specific question of whether one can pass a JSON string. However, I would also like to know a few more technical details about why yes or no. And generally how the argument functions in script filters.

Link to comment

Alfred only reads XML, so you have to translate the JSON into Alfred readable XML. Most languages have native functions to do this (PHP, Python, Ruby), so it's not a big deal, and the workflow libraries that exist all generate it. So, JSON, yes, only if you change it to XML.

 

You can apply different arguments based on modifier keys. However, if you want to chain with a custom delimiter, then you have to do some intermediary caching and Applescript Alfred itself.

 

You might already have looked, but read through this thread (actually the one pinned to the top of this forum). From that thread, David Ferguson put together a workflow that demonstrates how you can chain arguments. Read through the thread here. One of the first workflows that implemented these methods called them "Drill Down Menus." I'm not sure if those links are still live, but they put together a pretty great method. In that same thread, you can also see an artifact of the first Alfred2 workflow repository that lasted just a couple of weeks.

Link to comment

I realize I didn't address the arguments in script filters part. If you chain a script filter to a script action, then the argument selected will be passed as the {query} variable. Since you can't pass a {query} variable to the script itself, the general method is to store it in a file in the cache, and then grab the contents of the file and delete it. You can represent any bit of this you want as long as the argument works with Alfred. So if you want to have five json responses as arguments, you'll have to name them, say one, two, three, four, and five. Before that, record the associated JSON in the cache directory with, perhaps, the files named after the arguments. Then, when you pass the argument back to the script filter itself, (perhaps check first to see if any files exist in the cache directory, if so, do something different), you can read the JSON contents of the proper file into the script and then delete all those files.

Link to comment

I feel my question wasn't clear. My fault. I simply want to pass a JSON formatted string as the argument for an item in script filter. Let me define my terms tho. In alp, the Python module I use, the dictionary key used when creating items for feedback in a Script Filter that corresponds to the value that will become {query} in the next chained action is "arg". So I'm speaking of the argument that is passed for the chosen item in a Script Filter, which will be the {query} of the (say) chained Run Script action.

 

For example, let's say I have a script filter "query Jones" and it returns 3 items:

 

* Tom Jones

* Mike Jones

* Andy Jones

 

If these are valid/active items, I can click on one of them. Within the workflow, each of these items has an argument which will passed to the Run Script action that is chained to the Script Filter. (I know I'm being redundant and we all know this, but I'm trying to be clear via example this time). Normally, that string argument is simple. Let's say that in this case it is:

 

* Tom Jones = "tom"

* Mike Jones = "mike"

* Andy Jones = "andy"

 

If I select the Andy Jones item, then the value of {query} in the Run Script action will be "andy". This is all straight forward, but what if I want to pass more complex data? What if I want to pass each item's First Name, ID, and Height (3 values)? A simple way to represent complex key-value pairs is JSON, which can be put in string form (I know that I can't pass a Python dict as the item's arg). So, what I would want as the args would be:

 

* Tom Jones = "{\n\t'name': 'tom',\n\t'height': '5.0',\n\t'id': 3\n}"

* Mike Jones = "{\n\t'name': 'mike',\n\t'height': '5.5',\n\t'id': 2\n}"

* Andy Jones = "{\n\t'name': 'andy',\n\t'height': '6.0',\n\t'id': 1\n}"

 

If I pass this string as the arg, in the Run Script, I can decode the JSON string to a Python dict and easily get at the multiple values. Now, my question is, can I do this? Can I pass a string arg that has new lines (\n) and tabs (\t), necessary for JSON, in order to pass multiple values through an argument? If not, then what are the best methods for passing key-value pairs through Alfred's arg?

Edited by smarg19
Link to comment

Theoretically, if you escape everything and then unescape everything, it should go through just fine. I don't know if there is a max char limit for the args, but if there isn't, then if you just encode/escape the argument text so it doesn't muss up the XML, it should work.

 

You can always tinker around with your own encode/decode functions if the native python ones don't work well with the Alfred XML.

 

If this does get to be too much of a pain / road-block, then you could just go with the method of writing temporary files like I mentioned above. I don't think it's too dissimilar from using temporary tables in a database.

Link to comment

Maybe this: http://ayaz.wordpress.com/2007/04/22/reescape-pythons-equivalent-of-phps-addslashes/

Or this: http://blog.client9.com/2008/10/04/escaping-html-in-python.html

Or this: http://stackoverflow.com/questions/4309449/what-is-best-practice-for-escaping-special-characters-from-a-python-string

 

I'm a bit more than a Python beginner, so those may not actually fix any potential errors.

 

I'd recommend making a simple workflow that you can use to generate some XML with json in the arguments (you could even just set those as variables) and then see what you need to do to escape the strings so that Alfred plays nice with it.

Link to comment

I tried a few methods and in the end found that regex subs was easiest. In my testing, alp would HTML encode the JSON string when creating the XML Alfred feedback. When I got that feedback in the next step, however, it would space escaped. (I've found Alfred consistently space escapes {query}). So, on the receiving end, I use:

import alp
import json
import re

inp = alp.args()[0]
# For example
#inp = """{"path":\ "/Users/user/path/to/file.txt",\ "query":\ "this\ is\ my\ sample\ query"}"""
x = re.sub(r"\\\s", " ", inp)
data = json.loads(x)
print data['query']

This works well for me so far.

Link to comment

The space-escaping is most likely a problem with your escape selection in the following script escape options (or—far less likely—a bug in Alfred). If you have to manually unescape the input, it was probably not properly escaped in the first place.

 

As a rule, for Python scripts, you'll want to do the following:

 

UEkiA0i.png

 

I reckon the best (least potential for problems) solution would be to follow Shawn's earlier advice of saving the data in a dict in a temporary JSON cache file and passing the key(s) as args. I do this with my MailTo workflow (only email addresses are passed as args, names are added by the receiving script via cached data).

 

So you'd save the following dict to JSON:

{ "tom": {"name": "Tom Jones", "favourite_song" : "What's New Pussycat?"},
  "dick": {"name": "Dick van Dyke", "favourite_song" : "A Spoonful Of Sugar"}
}

and pass "tom" or "dick" as the arg. In the next script, reload the cache and look up your data via the key (arg).

 

As long as the second script cannot be run except as a result of the first (which will overwrite the cached file), there won't be any problems with stale cached data.

Edited by deanishe
Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...