Extension:Cargo/SMW migration guide

This page tries to show how to migrate templates in a wiki from using Semantic MediaWiki to using Cargo. It is not intended to convince anyone that such a migration should be done, simply to illustrate how it can be done.

For a more high-level overview of how Cargo differs from SMW, see Cargo and Semantic MediaWiki.

The original template
Let's take as an example a relatively simple infobox-style template of the kind seen in many Semantic MediaWiki-based wikis. This one is called "Country" and it stores basic (and somewhat random) information about a country. Here are the contents of its page, located at "Template:Country":

This is the "Country" template.

This template displays a table with two columns and three rows. The first column simply holds headers, while the second column holds a value in its first row, a comma-separated list of values in its second row and an aggregating query in its third row.

From property pages to #cargo_declare
To store data, the Semantic MediaWiki approach is to divide data storage among two types of pages: the template page and property pages. The property pages set the type and potentially other details of the data storage, while the template stores the data. In Cargo, on the other hand, these two actions are both done in the template page, using the functions #cargo_declare and #cargo_store, respectively.

So in order to figure out what the #cargo_declare call should look like, we need to know all the SMW properties that this template currently makes use of, and what is contained in the page for each of those properties.

In this case, the template stores data with two properties, "Has date founded" and "Has official language". Going to the pages for those properties, let's say that we see the following at "Property:Has_date_founded":

This is a property of type Has type::Date.

...while "Property:Has_official_language" contains this text:

This is a property of type Has type::Page.

These are very simple declarations, that just set the type. So we know that we need our #cargo_declare function to declare two fields of type "Date" and "Page" respectively. (There is not exactly a one-to-one mapping between SMW and Cargo types, although it's close. The big differences are the addition of "Datetime" and "Wikitext" types within Cargo, and the split of SMW's "Number" type into separate "Integer" and "Float" types in Cargo.)

What should the fields be called? Here the properties are called "Has date founded" and "Has official language", fitting the usual convention of making property names be verb phrases; but the properties could also have been called any number of things, including just "Date founded" and "Official language". For Cargo, the standard convention is to just go with a simple field name, so let's call them "Date_founded" and "Official_languages". The latter is pluralized because it can hold a list, while both names have underscores instead of spaces because Cargo does not allow spaces in field names.

Cargo makes use of tables, so that every piece of data is stored as a field within a table, not as a standalone property like SMW. So we will need to pick a name for the table. The simplest approach here is to go with the name of the category, i.e. "Countries".

Now we know the name of the table we want, and the names and types of all the fields - in this case, a field called "Date_founded" of type "Date" and a field called "Official_languages", which holds a comma-separated list of values of type "Text". So the resulting #cargo_declare call would be:

From property tags to #cargo_store
Now on to the storage. In Cargo, all the data is stored in one #cargo_store call; as opposed to SMW, where storage is usually done inline. (SMW's #set can in fact store all the data in one place, but this is rarely done.) In this template, there are two properties that were being stored. Given that we already know the table name ("Countries"), this call is straightforward to put together. It should look like:

No special handling is needed for fields that hold lists because this is already taken care of in #cargo_declare.

From #ask to #cargo_query
Not all SMW-based templates contain a call to #ask, but some do - usually in order to display an aggregated list of pages that have some property pointing to the current page. (This "list" can be a simple list, or can have a more involved display, like a map, timeline, etc.) The #ask query in this example template looks like:

We need to translate this to a #cargo_query call - on the assumption that the setting of the cities data has also been migrated to Cargo, or will be soon in the future. Just as with the above, the "Is in country" property needs to be migrated elsewhere into a Cargo table and field. Let's say that the property has been migrated (perhaps in a template called "City") into a table and field called "Cities" and "Country", respectively. In that case, the corresponding #cargo_query call would be:

Aside from the different syntax, note several key differences between the two query languages:
 * In #ask queries, specifying the category is optional. In #cargo_query, the table (which is usually the equivalent of the category) is mandatory.
 * In #cargo_query, unlike #ask, text values within queries need to be enclosed within quotation marks.
 * You can't see it in this example, but querying on fields that can hold a list of values is different. In #ask queries, all properties point to a single value, so it doesn't matter whether a template field holds one value or a list of values. In #cargo_query, on the other hand, it does matter - and fields that hold a list of values need to be queried using either "HOLDS" or "HOLDS LIKE". (The equivalent operators for fields that can only hold a single value are "=", as we see here, and "LIKE".)

For those used to writing SMW queries, these differences will probably take a little time to get used to.

The #ask and #cargo_query calls in this example are both simple queries, that simply display a list of page names based on a simple "filter". They have no specified format, no list of fields to display ("printouts", in SMW's parlance), and no other complicating factors. However, they are the kind of simple aggregating queries that often show up in templates. If your wiki has more complex SMW queries that need translating - and most likely it does - please consult the page "Querying data" for the full syntax of #cargo_query.

Putting it all together
If you migrate a template from Semantic MediaWiki to Cargo, you can choose to keep the existing SMW property tags within that template, or remove them - unless you are removing SMW entirely from your wiki, in which case you will of course need to remove the tags. In this case, let's remove the SMW tags. We'll keep the table-based display as it was before, add in #cargo_declare and #cargo_store in the appropriate places, and replace #ask with #cargo_query. The complete template now looks like:

This is the "City" template.

Forms
There is a good chance that you also have forms defined, using the Semantic Forms extension, for editing pages that call these templates. Assuming your forms are defined in a straightforward manner, there is a reasonable chance that you will not need to modify these forms at all; as of version 3.1, SF makes use of Cargo data and metadata. If any issues do come up, please consult the Semantic Forms documentation.

There is one way in which the presence of Semantic Forms could affect the template itself, not just the form for it. The "City" template defines one or more links to pages representing languages. It could be that these language pages all use a form for editing their structured data. If a "city" page links to a nonexistent "language" page, you might want the resulting red link to link to the form for creating that language page. This is usually done by setting a "default form" for the property. So the text at the page "Property:Has_official_language" might look like:

This is a property of type Has type::Page. It uses the form Has default form::Language.

Since we are no longer using SMW properties, we have to instead define this relationship using the parser function #formredlink, new in Semantic Forms 3.0. It takes the place of a regular link, and links to the form for creating a page when appropriate, and shows a regular link to the page otherwise. So the relevant line of the "City" template would change from this:



...to this: