I’m trying to get news from a Medium publication that doesn’t have a json feed. This means I can’t iterate over the data coming back from the request with a for of loop because I’m not getting an object returned from the request.
In your sample script getting data back from MacStories and putting it into a table with UITable is something I want to do however I’m not sure how to do it with the data returned being XML. Any ideas?
There seems to be a specific library to help get json from medium that could help: https://github.com/frandiox/medium-json-feed/blob/master/README.md
But if you can get xml then you can also look for xml to json converters - there are a bunch online so hopefully one will fit in with what you need
Scriptable provides an XMLParser. Since your data is XML, you should be able to use that to parse it into a JavaScript object. I do that in the below script which fetches the pollen count from a Danish weather service.
Due to the nature of XML, there’s some manual work to be done here compared to JavaScripts JSON.parse() but when you get the hang of it, it’s not that bad.
For those that know iOS/macOS development, the API of XMLParser is reminiscent of NSXMLParser.
// Shows the pollen count for today.
const url = "http://www.dmi.dk/vejr/services/pollen-rss/"
const r = new Request(url)
let resp = await r.loadString()
const targetCityName = "København"
let elementName = ""
let currentValue = null
let items = []
let currentItem = null
const xmlParser = new XMLParser(resp)
xmlParser.didStartElement = name => {
currentValue = ""
if (name == "item") {
currentItem = {}
}
}
let str = "this is my string"
xmlParser.didEndElement = name => {
const hasItem = currentItem != null
if (hasItem && name == "title") {
currentItem["title"] = currentValue
}
if (hasItem && name == "description") {
currentItem["description"] = currentValue
}
if (name == "item") {
items.push(currentItem)
currentItem = {}
}
}
xmlParser.foundCharacters = str => {
currentValue += str
}
xmlParser.didEndDocument = () => {
const cph = items.filter(i => {
return i.title == "København"
})[0]
const lines = cph.description
.trim()
.split("\n")
.map(l => l.trim().replace(";", ""))
.filter(l => l.length > 0)
let values = lines.join("\n")
let rows = lines.map(mapRow)
let table = new UITable()
for (row of rows) {
table.addRow(row)
}
let focusedType = "Græs"
let regex = new RegExp(focusedType + ": ([0-9]+|-)")
let match = values.match(regex)
let textToSpeak = null
if (match) {
let pollenCount = match[1]
if (pollenCount == "-") {
textToSpeak = "There are no grass pollen"
} else {
textToSpeak = "The pollen count for grass is " + pollenCount
}
} else {
textToSpeak = "Pollen count for grass is unavailable"
}
QuickLook.present(table)
if (config.runsWithSiri) {
Speech.speak(textToSpeak)
}
}
xmlParser.parse()
function mapRow(value) {
let comps = value.split(":")
let row = new UITableRow()
row.addText(mapName(comps[0].trim()))
row.addText(mapValue(comps[1].trim()))
return row
}
function mapName(name) {
if (name == "Birk") {
return "Birch"
} else if (name == "Bynke") {
return "Mugwort"
} else if (name == "El") {
return "Alder"
} else if (name == "Elm") {
return "Elm"
} else if (name == "Græs") {
return "Grass"
} else if (name == "Hassel") {
return "Hazel"
} else {
return name
}
}
function mapValue(value) {
if (value == "Høj") {
return "High"
} else if (value == "Middel") {
return "Moderate"
} else if (value == "Lav") {
return "Low"
} else {
return value
}
}