bashsparqljqwikidata-apiwikidata-query-service

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?


Solution

  • 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 ...