Semantic Scribunto example

From Semantic MediaWiki - Sandbox

On this page you can find a short introduction and some examplary use cases for the SMW Extension SemanticScribunto. This documentation aims to get you aquainted on how to utilize lua in conjunction with SMW and shows its advantages on more complex operations. It does not, however give you an introduction to lua. For this, please visit [1] or [2]. It is furthermore assumed that you have installed SMW, Scribunto and this extension.

Introduction

Scribunto allows the usage of the scripting language Lua inside of Mediawiki. This allows for more complex and better maintainable code in comparison to just using the normal template engine. Scribunto has a build-in method of integrating all available parser functions inside your lua modules. However, in case of a data orientated extension like SMW this falls short, because all you get as return values are parsed strings. Wanting to access semantic data via #ask would make it necessary to parse the string produced by the parser function. Enter Extension:Semantic Scribunto (SSC), which provides a new lua library[3] for retrieving and storing semantic data inside lua modules. This relieves users of the necessity to use frame:callParserFunction and a cumbersome manual result parsing, accelerating all SMW operations in the process. In conjunction with lua's intrically capabilites of manipulating data tables, this allows for some advanced operations in a very elegant way.

Simple examples for data retrieval

Ask

mw.smw.ask
Data retrieval function
Links
Documentation external
Example module Module:Smw
Function signature
(string|table) query see below
Return (table) simple query data

This is one of two functions that allows for access to semantic data. It takes as input query parameters akin to the #ask parser function[4]. As return you get a simple table containing your query result data in a propertyname/headline => semantic data format. See example below for more information. Please also see Get query result for a more detailed equivalent.

Note that mw.smw.ask ignores the headers parameter. Use ?<property>#- instead. Unlinking the mainlabel works like this: ?#-=page|mainlabel=-.


{{#invoke:smw|ask|[[Category:Comic books]][[Has comic book writer::Neil Gaiman]]|?#-=page|?Has main character=protagonist|?Has comic book artist#-|?Creation date|limit=2|mainlabel=-}}
Extended content
(table)[2]:
	1: (table)[0]:
		Creation date: (string) '14 décembre 2016 08:39:18'
		protagonist: (table)[2]:
			1: (string) 'Dream (comics)'
			2: (string) 'Death (DC Comics)'
		page: (string) 'Sandman - Dream Country'
		Has comic book artist: (table)[5]:
			1: (string) 'Malcolm Jones III'
			2: (string) 'Kelley Jones'
			3: (string) 'Steve Oliff'
			4: (string) 'Charles Vess'
			5: (string) 'Colleen Doran'
	2: (table)[0]:
		Creation date: (string) '14 décembre 2016 08:30:19'
		protagonist: (table)[4]:
			1: (string) 'Dream (comics)'
			2: (string) 'Cain and Abel (comics)'
			3: (string) 'John Constantine'
			4: (string) 'Lucifer (DC Comics)'
		page: (string) 'Sandman - Preludes and Nocturnes'
		Has comic book artist: (table)[3]:
			1: (string) 'Sam Kieth'
			2: (string) 'Mike Dringenberg'
			3: (string) 'Malcolm Jones III'

Get query result

mw.smw.getQueryResult
Data retrieval function
Links
Documentation external
Example module Module:Smw
Function signature
(string|table) query see below
Return (table) query json data

This is one of two functions that allows for access to semantic data. It takes input query parameters akin to the #ask parser function [4]. As return you get a table containing your query result data. The table format is like the json format you get when using the api[5]. Please see ask for a simpler equivalent.


{{#invoke:smw|getQueryResult|[[Category:Comic books]][[Has comic book writer::Neil Gaiman]]|?Has main character=protagonist|?Has comic book artist#-|?Creation date|limit=2}}
mw.smw.getPropertyType example result
(table)[0]:
	serializer: (string) 'SMW\Serializers\QueryResultSerializer'
	meta: (table)[0]:
		offset: (number) 0
		count: (number) 2
		time: (string) '0.002004'
		hash: (string) '6c6d5219e141dceb424639660f576870'
		source: (string) 
	printrequests: (table)[4]:
		1: (table)[0]:
			key: (string) 
			label: (string) 
			format: (boolean) false
			mode: (number) 2
			redi: (string) 
			typeid: (string) '_wpg'
		2: (table)[0]:
			key: (string) 'Has_comic_book_artist'
			label: (string) 'Has comic book artist'
			format: (string) '-'
			mode: (number) 1
			redi: (string) 
			typeid: (string) '_wpg'
		3: (table)[0]:
			key: (string) '_CDAT'
			label: (string) 'Creation date'
			format: (string) 
			mode: (number) 1
			redi: (string) 
			typeid: (string) '_dat'
		4: (table)[0]:
			key: (string) 'Has_main_character'
			label: (string) 'protagonist'
			format: (string) 
			mode: (number) 1
			redi: (string) 
			typeid: (string) '_wpg'
	version: (number) 2
	results: (table)[2]:
		1: (table)[0]:
			exists: (string) '1'
			displaytitle: (string) 
			printouts: (table)[0]:
				protagonist: (table)[2]:
					1: (table)[0]:
						exists: (string) '1'
						displaytitle: (string) 
						namespace: (number) 0
						fulltext: (string) 'Dream (comics)'
						fullurl: (string) 'https://sandbox.semantic-mediawiki.net/wiki/Dream_(comics)'
					2: (table)[0]:
						exists: (string) 
						displaytitle: (string) 
						namespace: (number) 0
						fulltext: (string) 'Death (DC Comics)'
						fullurl: (string) 'https://sandbox.semantic-mediawiki.net/wiki/Death_(DC_Comics)'
				Creation date: (table)[1]:
					1: (table)[0]:
						raw: (string) '1/2016/12/14/8/39/18/0'
						timestamp: (string) '1481704758'
				Has comic book artist: (table)[5]:
					1: (table)[0]:
						exists: (string) 
						displaytitle: (string) 
						namespace: (number) 0
						fulltext: (string) 'Malcolm Jones III'
						fullurl: (string) 'https://sandbox.semantic-mediawiki.net/wiki/Malcolm_Jones_III'
					2: (table)[0]:
						exists: (string) 
						displaytitle: (string) 
						namespace: (number) 0
						fulltext: (string) 'Kelley Jones'
						fullurl: (string) 'https://sandbox.semantic-mediawiki.net/wiki/Kelley_Jones'
					3: (table)[0]:
						exists: (string) 
						displaytitle: (string) 
						namespace: (number) 0
						fulltext: (string) 'Steve Oliff'
						fullurl: (string) 'https://sandbox.semantic-mediawiki.net/wiki/Steve_Oliff'
					4: (table)[0]:
						exists: (string) 
						displaytitle: (string) 
						namespace: (number) 0
						fulltext: (string) 'Charles Vess'
						fullurl: (string) 'https://sandbox.semantic-mediawiki.net/wiki/Charles_Vess'
					5: (table)[0]:
						exists: (string) '1'
						displaytitle: (string) 
						namespace: (number) 0
						fulltext: (string) 'Colleen Doran'
						fullurl: (string) 'https://sandbox.semantic-mediawiki.net/wiki/Colleen_Doran'
			namespace: (number) 0
			fullurl: (string) 'https://sandbox.semantic-mediawiki.net/wiki/Sandman_-_Dream_Country'
			fulltext: (string) 'Sandman - Dream Country'
		2: (table)[0]:
			exists: (string) '1'
			displaytitle: (string) 
			printouts: (table)[0]:
				protagonist: (table)[4]:
					1: (table)[0]:
						exists: (string) '1'
						displaytitle: (string) 
						namespace: (number) 0
						fulltext: (string) 'Dream (comics)'
						fullurl: (string) 'https://sandbox.semantic-mediawiki.net/wiki/Dream_(comics)'
					2: (table)[0]:
						exists: (string) 
						displaytitle: (string) 
						namespace: (number) 0
						fulltext: (string) 'Cain and Abel (comics)'
						fullurl: (string) 'https://sandbox.semantic-mediawiki.net/wiki/Cain_and_Abel_(comics)'
					3: (table)[0]:
						exists: (string) 
						displaytitle: (string) 
						namespace: (number) 0
						fulltext: (string) 'John Constantine'
						fullurl: (string) 'https://sandbox.semantic-mediawiki.net/wiki/John_Constantine'
					4: (table)[0]:
						exists: (string) 
						displaytitle: (string) 
						namespace: (number) 0
						fulltext: (string) 'Lucifer (DC Comics)'
						fullurl: (string) 'https://sandbox.semantic-mediawiki.net/wiki/Lucifer_(DC_Comics)'
				Creation date: (table)[1]:
					1: (table)[0]:
						raw: (string) '1/2016/12/14/8/30/19/0'
						timestamp: (string) '1481704219'
				Has comic book artist: (table)[3]:
					1: (table)[0]:
						exists: (string) 
						displaytitle: (string) 
						namespace: (number) 0
						fulltext: (string) 'Sam Kieth'
						fullurl: (string) 'https://sandbox.semantic-mediawiki.net/wiki/Sam_Kieth'
					2: (table)[0]:
						exists: (string) 
						displaytitle: (string) 
						namespace: (number) 0
						fulltext: (string) 'Mike Dringenberg'
						fullurl: (string) 'https://sandbox.semantic-mediawiki.net/wiki/Mike_Dringenberg'
					3: (table)[0]:
						exists: (string) 
						displaytitle: (string) 
						namespace: (number) 0
						fulltext: (string) 'Malcolm Jones III'
						fullurl: (string) 'https://sandbox.semantic-mediawiki.net/wiki/Malcolm_Jones_III'
			namespace: (number) 0
			fullurl: (string) 'https://sandbox.semantic-mediawiki.net/wiki/Sandman_-_Preludes_and_Nocturnes'
			fulltext: (string) 'Sandman - Preludes and Nocturnes'

Get property type

mw.smw.getPropertyType
Data retrieval function
Links
Documentation external
Example module Module:Smw
Function signature
(string) Property name
Return (string) Type identifier
[[Property:Modification date|Modification date]] is of type {{#invoke:smw|getPropertyType|Modification date}}

Produces:

Modification date is of type _dat.

Simple examples for data storage

Set

mw.smw.set
Data storage function
Links
Documentation external
Example module Module:Smw
Function signature
(string|table) query see below
Return (bool) true or (table) in case of error
#1: {{#invoke:smw|set|has author=User:Oetterer|has keyword=documentation|has keyword=example|has keyword=ssc|has keyword=SemanticScribunto}}
#2: {{#invoke:smw|set|has number=foobar}}
#3: {{#invoke:smw|set|has text=draft;live;work in progress|+sep=;}}

Produces:

1: Your data was stored successfully
2: An error occurred during the storage process. Message reads "foobar" is not a number.
3: An error occurred during the storage process. Message reads "+sep" contains a listed "+" character as part of the property label and has therefore been classified as invalid.

Note that query #1 places the page in the gardening category Category:Pages using duplicate arguments in template calls ( functionality live since MW 1.25). This call also ignores all but one assigment. This occurs due to the fact, that Scribunto receives the arguments in a key=>value pair, leading to latter value assignments overwrite former. Query #3 also does not yield the desired result. Again Scribunto is to blame, since it scrambles the order of table entries having non-numbers as keys. There the +sep argument is read before the has text= assignment. However, using mw.smw.set inside a module (and not filled by frame.args) gives you more control over the argument order and allows both the desired effects of #1 and #3. I.e. these problems here occur, because Module:Smw is designed very rudimentry and only passes arguments to the lua methods. This module is fine as an example, a life implementation would probably look more complex. See for example Module:SSC_base, method class:storeSemanticData().

Subobject

mw.smw.subobject
Data storage function
Links
Documentation external
Example module Module:Smw
Function signature
(string|table) query see below
(string) (optional) subobject id
Return (bool) true or (table) in case of error

Much the same as set, this allows to store semantic data, only as subobject. It mirrors the functionality of the parser function #subobject. For legacy reasons, it allows you to set a subobject id, which is why it expects data in the first argument. If you want your subobject to contain multiple values, use a table.

#1: {{#invoke:smw|subobject|has firstname=Donald|has lastname=Duck}}
#2: {{#invoke:smw|subobject|has firstname=Daisy|has lastname=Duck|subobjectId=LadyDuck}}
1: Your data was stored successfully in a subobject
table#1 {
    metatable = table#2
    ["has firstname"] = "Donald",
    ["has lastname"] = "Duck",
}
2: Your data was stored successfully in a subobject
table#1 {
    metatable = table#2
    ["has firstname"] = "Daisy",
    ["has lastname"] = "Duck",
}

Miscellaneous

Info (tooltip)

mw.smw.info
Data display function
Links
Documentation external
Example module Module:Smw
Function signature
Input (string) Infotext, [(string) image type]
Return (string) true

This makes the smw parser function #info available in lua and allows you to add tooltips to your output stream. See the documentation on the SMW homepage for more information.

#1: {{#invoke:smw|info|This is a tooltip info text}}
#2: {{#invoke:smw|info|But you can also set a warning!|warning}}
1: This is a tooltip info text
2: But you can also set a warning!

Notes on the query definition

As you might have noticed, the functions mw.smw.ask, mw.smw.getQueryResult, mw.smw.set, and mw.smw.subobject all take their query as string or table. There are some things, you should keep in mind.

  • When supplying the query as string, use a pipe | as delimiter
  • When using a table, you can either opt for a number-indexed table or key/value pairs (see examples below) (also a mix of both). Just keep in mind:
    • mw.smw.ask and mw.smw.getQueryResult need the selection part of the query as first parameter
    • Lua does not garantee the order of an array. When you use non-numbers as keys, your argument order most definitely get screwed up. This will prevent you from using +set or template on mw.smw.set or mw.smw.subobject. Opt for number indexed table in this case.
  • Again: note that mw.smw.ask ignores the link parameter. Use ?<property>#- instead. Unlinking the mainlabel works like this: ?#-=page|mainlabel=-.
-- example query definition using a string
-- ask and getQueryResult
local query = '[[Category:Comic books]][[Has comic book writer::Neil Gaiman]]|?#-=page|?Has main character=protagonist|?Has comic book artist#-|?Creation date|limit=2|mainlabel=-'
local result = mw.smw.ask(query)
-- set
local query = 'has author=User:Oetterer|has keyword=documentation|has keyword=example|has keyword=ssc|has keyword=SemanticScribunto'
local result = mw.smw.set(query)
-- subobject
local query = 'has firstname=Daisy|has lastname=Duck'
local result = mw.smw.subobject(query, 'LadyDuck')

-- example definition using a table
-- ask and getQueryResult
local query = { '[[Category:Comic books]][[Has comic book writer::Neil Gaiman]]', '?#-=page', '?Has main character=protagonist', '?Has comic book artist#-', '?Creation date', 'limit=2', 'mainlabel=-' }
local result = mw.smw.getQueryResult(query)
-- set
local query = { 'has author=User:Oetterer', 'has keyword=documentation', 'has keyword=example', 'has keyword=ssc', 'has keyword=SemanticScribunto' }
local result = mw.smw.set(query)
-- since now, we have a number indexed table where lua maintaines order, we can do something like this, as well:
local query = { 'has author=User:Oetterer', 'has keyword=documentation;example;ssc;SemanticScribunto', '+sep=;' }
local result = mw.smw.set(query)
-- subobject
local query = { 'has firstname=Daisy', 'has lastname=Duck' }
local result = mw.smw.subobject(query, 'LadyDuck')

-- example definition using a table with key/value pairs (where applicable
-- ask and getQueryResult
local query = { '[[Category:Comic books]][[Has comic book writer::Neil Gaiman]]', ['?#-']='page', ['?Has main character']='protagonist', '?Has comic book artist#-', '?Creation date', limit=2, mainlabel='-' }
local result = mw.smw.ask(query)
-- set
-- obviously set cannot use key/value pairs, with multiple values for one property. Also, you cannot use +sep as key, because we don't have the fixed order we need! :(
-- this works. but why?
local query = { ['has author']='User:Oetterer', ['has keyword']='documentation', 'has keyword=example', 'has keyword=ssc', 'has keyword=SemanticScribunto' }
local result = mw.smw.set(query)
-- again, much the same applies for #subobject
-- subobject
local query = { ['has firstname']='Daisy'], ['has lastname']='Duck' }
local result = mw.smw.subobject(query, 'LadyDuck')

A more complex example

This tries to give you an impressing on the more elaborate things you can achieve, using lua and Smw. First, let's have a look at the setup.

  1. There is base module[6] defining a lua class, which has basic functions for
    1. getting data from your temlate arguments
    2. some plausibility checking (like for instance the existance of mandatory fields)
    3. data preparation (like converting list fields into tables)
    4. storing semantic data into defined properties
    5. displaying data
      1. in an infobox
      2. as strings, wiki-links or links to forms

On that base we build three example classes Module:Character/class, Module:Comic books/class, and Module:Person/class. The first two are really simple, their main purpose is to show you how easy you can set up new classes and also provide us with some semantic data. The real magic is shown in Module:Person/class.

  1. Each class overrides two functions from SSC Base allowing them to dynamically define defaults and make some adjustments after data storage but before displaying information.
  2. Module:Person/class processes and displays "external" data from another class (Comic Books), using data formats and functions defined there. Note how getPersonVitae() does not need to construct a query, it simply "asks" Class ComicBooks to retrieve everything automatically. It also deferns data display back to that class (in extractCollaborations() and extractWorks()) because it knows best on how to display its own data.
  3. Of cource each of the three entity classes have an entry module (Module:Character, Module:Comic books, and Module:Person) and a class configuration (Module:Character/config, Module:Comic books/config, and Module:Person/config).
  4. Each Class also has a template and a from (you find them in Category:SSC_example_templates and Category:SSC_example_forms.

Please see Neil Gaiman, a product of Module:Person/class.

Expanding the Example

One could easily imagin useful ways on expanding Module:SSC base. For example, as of now, all forms were generated manually. With a litte addition to the config files, we have enough information to create a static method which can generate a form for each class. We then would need to add a second "gate way"-function to the Module:Entity-pages and from them on your Form pages would only contain a few text lines and one #invoke-call. Expanding classes (meaning adding more parameters) would automatically adapt the form, no need for tedious work on that part.

See also

Has keywordUsed to store strings of restricted length in a normalized way. Is a variant of datatype text.
Has telephone numberUsed for international telephone numbers that are to be stored in a standardized format.
Has textUsed to store strings of arbitrary length.
draft;live;work in progress +
Has subobject"Has subobject" is a predefined property representing a container construct and is provided by Semantic MediaWiki.
Cookies help us deliver our services. By using our services, you agree to our use of cookies.