Search code examples
mediawikisemantic-mediawiki

Semantic MediaWiki: Is it possible to use subqueries rather than properties for tables?


I'm still trying to make my wiki more "dynamic" in order to get rid of duplicated data. In my previous question I was asking how I could bind multiple pages and retrieve properties through bound pages. Since that question is already resolved for simple cases (however I don't like my solution there much), I would like to make it work for tables. let's consider the same page and property structure I mentioned in my question again, thus the following code

{{#ask: [[Category:Venues]] [[Self name::Heineken Music Hall]]}}
{{#ask: [[Category:Cities]] [[-Ref city.Self name::Heineken Music Hall]]}}
{{#ask: [[Category:Countries]] [[-Ref country.-Ref city.Self name::Heineken Music Hall]]}}

retrieves the venue, city (Amsterdam) and country (Netherlands) using inline queries. However I'm not sure if such an approach is possible for tables. As far as I know, #ask can generate a table generating columns out of direct properties :

{{#ask: [[Category:Live events]]
| ?Self date = Date
| ?Ref venue = Venue
| mainlabel = -
}}

Output:

+-----------------+---------------------+
| Date            | Venue               |
+-----------------+---------------------+
| 3 December 2012 | Heineken Music Hall |
+-----------------+---------------------+

I would also like to add the City and Country columns. The problem is, as I mentioned above, the city and country properties are not put directly into the Venue page so the #ask function might use inline subqueries. But I can't make it work:

{{#ask: [[Category:Live events]]
| ?Self date = Date
| ?Ref venue = Venue
| ?WHAT_EXPRESSION_HERE? = City
| ?EVEN_MORE_COMPLEX_EXPRESSION_HERE? = Country
| mainlabel = -
}}

The first thing I'm thinking about is using templates using the format = template and template = TEMPLATE_NAME. I managed to extract the bound city using this approach by creating the required template and parsing {{{1}}}... parameters, but I cannot seem to extract country (simple to extract: date, venue; complex: city; not able: country). Also using the templates approach seems to be fragile and not very consistent to me.

Is it possible to specify subqueries/expressions rather than properties for tables to extract properties from indirectly bound pages in Semantic MediaWiki (probably never using templates)?


Solution

  • As far as I understand, this is not possible in Semantic MediaWiki directly, however it can be worked around. In short, the template format is required, and here it is:

    {{#ask: [[Category:Live events]]
    | ?Self date = Date
    | ?Ref venue = Venue
    | mainlabel = -
    | format = template
    | template = Row:Live events table
    | named args = yes
    }}
    

    The Template:Row:Live events table template is as follows:

    <includeonly><!--
    -->{{#vardefine: DATE | {{{?Date}}}}}<!--
    -->{{#vardefine: VENUE | {{{?Venue}}}}}<!--
    -->{{#vardefine: CITY | {{SHOW_REF|{{#var: VENUE}}|?Ref city}}}}<!--
    -->{{#vardefine: COUNTRY | {{SHOW_REF|{{#var: CITY}}|?Ref country}}}}<!--
    -->{{#vardefine: CONTINENT | {{SHOW_REF|{{#var: COUNTRY}}|?Ref continent}}}}<!--
    -->{{#var: DATE}}, {{#var: VENUE}}, {{#var: CITY}}, {{#var: COUNTRY}} {{#var: FLAG}}, {{#var: CONTINENT}}<br/><!--
    --></includeonly>
    

    In the template above I use named arguments for easiness. However, I use #vardefine and #var to store and retrieve some data from the current row. These functions are supplied by the Extension:Variables extension. Also I use two auxiliary templates: SHOW SELF and SHOW REF to simplify data extraction. The first template, SHOW SELF, is just a shortcut:

    <includeonly>{{#show: {{FULLPAGENAME}} | {{{1|}}}}}</includeonly>
    

    to extract a property for the current page. The second template called SHOW REF simplifies data extraction for the given page, not the current one:

    <includeonly>{{#show: {{PARSE_SMW_PAGE | {{{1|}}} }} | {{{2|}}}}}</includeonly>
    

    And yes, the PARSE SMW PAGE just strips left and right brackets, and optional leading colon:

    <includeonly>{{#explode:
    {{#sub: {{{1}}} | {{#ifeq: {{#pos: {{{1}}} | [:}} | 1 | 3 | 2 }} | -2 }}
    | {{!}}
    }}</includeonly>
    

    #explode and #pos are supplied from Extension:StringFunctions, #ifeq is supplied from Extension:ParserFunctions and {{!}} is a dummy template for the | character.

    As you can see, I managed to crawl the following page relationships:

    • Venue to city
    • City to country
    • Country to continent

    Hope this helps someone else too.