andrewn Posted September 25, 2015 Share Posted September 25, 2015 Hi, The XML I'm outputting from my Javascript Script Filter is causing an error by I can't figure out what the issue is. I have similar code working fine as a Ruby Script Filter. It takes a string input e.g. "this is an example", transforms it to "this-is-an-example" and outputs the XML so it can be copied to the clipboard. I've tried to convert it to use the JS Script Filter but it gives the following error in the workflow debugger and doesn't trigger the action in Alfred: Starting debug for 'filename' [STDERR: alfred.workflow.input.scriptfilter] <?xml version="1.0"?> <items> <item valid="YES" autocomplete="example-input"> <title>example-input</title> <text type="copy">example-input</text> <text type="largetype">example-input</text> </item> </items> Here's the Ruby script that works correctly: Language: /usr/bin/ruby Behaviour: Terminate previous script Queue delay: Immediately after every character types Script: filename = "{query}".downcase.gsub(' ', '-') puts(<<-EOT) <?xml version="1.0"?> <items> <item valid="YES" autocomplete="#{filename}"> <title>#{filename}</title> <text type="copy">#{filename}</text> <text type="large type">#{filename}</text> </item> </items> EOT And this is the JS equivalent that doesn't work: Language: /usr/bin/osascript (JS) Behaviour: Terminate previous script Queue delay: Immediately after every character types Script: var filename = "{query}".toLowerCase().replace(/ /g, '-'); var xml = [ '<?xml version="1.0"?>', '<items>', '<item valid="YES" autocomplete="#{filename}">', '<title>#{filename}</title>', '<text type="copy">#{filename}</text>', '<text type="large type">#{filename}</text>', '</item>', '</items>' ].join('\n').replace(/#\{filename\}/g, filename); console.log(xml); Any ideas what I'm doing wrong? Happy to post any more debugging info if needed. Thanks Link to comment
deanishe Posted September 25, 2015 Share Posted September 25, 2015 (edited) The answer is in the first line of the log output: [STDERR: alfred.workflow.input.scriptfilter] Your JavaScript version is sending the XML to STDERR, not STDOUT. Unfortunately, I can't tell you how to fix it (other than don't use console.log()), as I don't have the first clue about using JavaScript outside of a browser (why would you? It's a terrible language, and Ruby is waaaay better). FWIW, inserting variables into text is a bad way to generate XML: if a character like & or " is in filename (and likely any non-ASCII character, too, due to encoding issues), your XML will be invalid and the workflow won't work. Much better to use a real XML library to generate your XML, and make sure it's UTF-8 encoded. I'd advise you to stick with Ruby and use one of its libraries to generate the XML. Edited September 25, 2015 by deanishe Link to comment
andrewn Posted September 27, 2015 Author Share Posted September 27, 2015 (edited) I'm using this example as a way of trying out the OSAScript JS integration in the latest Alfred release. Thanks to your help, I've figured out that in Apple's JS OSAScript host, console.log outputs to stderr. A convoluted way to output to stdout seems to be: ObjC.import('stdio'); $.printf('this string outputs to stdout'); So, I can get the script working with this: ObjC.import('stdio'); var filename = '{query}'.toLowerCase().replace(/ /g, '-'); var xml = [ '\n<?xml version="1.0"?>', '<items>', '\t<item valid="YES" autocomplete="#{filename}">', '\t\t<title>#{filename}</title>', '\t\t<text type="copy">#{filename}</text>', '\t\t<text type="largetype">#{filename}</text>', '\t</item>', '</items>' ].join('\n').replace(/#\{filename\}/g, filename); $.printf(xml); However, printf returns an int of the number of chars in the string and so Alfred now complains about this: [ERROR: alfred.workflow.input.scriptfilter] XML Parse Error 'The operation couldn’t be completed. (NSXMLParserErrorDomain error 5.)'. Row (null), Col (null): 'Extra content at the end of the document' in XML: <?xml version="1.0"?> <items> <item valid="YES" autocomplete="example-input"> <title>example-input</title> <text type="copy">example-input</text> <text type="largetype">example-input</text> </item> </items>215 Edited September 27, 2015 by andrewn Link to comment
deanishe Posted September 27, 2015 Share Posted September 27, 2015 (edited) I've had a quick play with JavaScript and Script Editor. What you're seeing isn't the return value of $.printf() per se, but the result of the script. So instead of using $.printf(), just write xml;: var filename = '{query}'.toLowerCase().replace(/ /g, '-'); var xml = [ '<?xml version="1.0"?>', '<items>', '\t<item valid="YES" autocomplete="#{filename}">', '\t\t<title>#{filename}</title>', '\t\t<text type="copy">#{filename}</text>', '\t\t<text type="largetype">#{filename}</text>', '\t</item>', '</items>' ].join('\n').replace(/#\{filename\}/g, filename); xml; When run, this outputs: <?xml version="1.0"?> <items> <item valid="YES" autocomplete="{query}"> <title>{query}</title> <text type="copy">{query}</text> <text type="largetype">{query}</text> </item> </items> Note, I've removed the stdio import and the preceding newline in the XML output. A better way (i.e. better coding practice) is to define a run function, which will be called when the script is run: // Called automatically when the script is run. // Its return value will be output to STDOUT. function run(argv) { var filename = '{query}'.toLowerCase().replace(/ /g, '-'); return generateXml(filename); } function generateXml(filename) { var xml = [ '<?xml version="1.0"?>', '<items>', '\t<item valid="YES" autocomplete="#{filename}">', '\t\t<title>#{filename}</title>', '\t\t<text type="copy">#{filename}</text>', '\t\t<text type="largetype">#{filename}</text>', '\t</item>', '</items>' ].join('\n').replace(/#\{filename\}/g, filename); return xml; } Edited September 27, 2015 by deanishe Link to comment
andrewn Posted October 1, 2015 Author Share Posted October 1, 2015 That works great thanks. I didn't realise that osascript returns the last line of the script. Also, thanks for the tip about run() being run! Link to comment
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now