smihael smihael - 5 months ago 22
JSON Question

How to get latest version of certain software using Wikidata?

I use following command to get (latest) version of certain software from Wikidata from the command line using

jq
as JSON parser.

curl -sL "http://www.wikidata.org/w/api.php?action=wbgetentities&ids=$QID&languages=en&format=json" |
jq ".entities.$QID.claims.$PID""[0].mainsnak.datavalue.value"


where
$QID
is the ID of a Wikidata entry, and
$PID
the ID of the property we want to print (in this case software version "P348").

That usually works fine, since usually the first claim (
[0]
) for
P348
is the newest version, but for example for "Q13166" (WordPress), we have several claims about software version. How to get the newest stable one instead of the first claim?

I probably should (in the case we have more than one claim), find the ith claim, where version type "P548" equals to stable version "Q12355314". Or find out the clam that has preferred rank. How to do that with jq? Is there an easier way, such as for example sending an SPARQL query to query.wikidata.org?

Answer

The following collects all the relevant version numbers, and determines the "maximum" value using the filter defined here as "lexmax":

jq --arg QID "$QID" --arg PID "$PID" '
  def lexmax:
    map( split(".")
         | map(if test("^[0-9]*$") then tonumber else . end) )
  | max | map(tostring) | join(".");

  .entities | .[$QID] | .claims | .[$PID]
  | map(.mainsnak.datavalue.value)
  | lexmax'

The result with QID=Q13166 PID=P348 is

"4.5.2"

If you want to use .rank == "preferred" as a selection criterion, you could use the following:

def lexmax:
  map( split(".")
       | map(if test("^[0-9]*$") then tonumber else . end) )
  | max | map(tostring) | join(".");

def when(condition; action):
  if condition? // null then action else . end;

.entities | .[$QID] | .claims | .[ $PID ]
| map( select(when(has("rank"); .rank == "preferred"))
       | .mainsnak.datavalue.value)
| lexmax

Or perhaps you won't need to use lexmax ...