Anonymous

Module:MwJson: Difference between revisions

From OSL Demo
import from wiki-dev
(Update package: OSW Core)
(import from wiki-dev)
Line 23: Line 23:
}  
}  
p.slots = { --slot names
p.slots = { --slot names
main='main',
jsondata='jsondata',  
jsondata='jsondata',  
jsonschema='jsonschema',  
jsonschema='jsonschema',  
Line 34: Line 35:
query='query'
query='query'
}
}
p.cache = {}


--loads json from a wiki page
--loads json from a wiki page
Line 40: Line 43:
function p.loadJson(args)
function p.loadJson(args)
local page_title = p.defaultArg(args.title, "JsonSchema:Entity") --for testing
local page_title = p.defaultArg(args.title, "JsonSchema:Entity") --for testing
local slot = p.defaultArg(args.slot, nil)
local slot = p.defaultArg(args.slot, 'main')
local debug = p.defaultArg(args.debug, nil)
local debug = p.defaultArg(args.debug, nil)
local msg = ""
local msg = ""
Line 46: Line 49:
local json = {}
local json = {}
if (slot == nil) then
if p.cache[page_title] ~= nil then
if p.cache[page_title][slot] ~= nil then
if (debug) then msg = msg .. "Fetch slot " .. p.slots.jsondata .. " of page " .. page_title .. " from cache <br>" end
json = p.cache[page_title][slot]
return {json=json, debug_msg=msg}
end
else p.cache[page_title] = {}
end
if (slot == 'main') then
--json = mw.loadJsonData( "JsonSchema:Entity" ) --requires MediaWiki 1.39
--json = mw.loadJsonData( "JsonSchema:Entity" ) --requires MediaWiki 1.39
local page = mw.title.makeTitle(p.splitString(page_title, ':')[1], p.splitString(page_title, ':')[2])
local page = mw.title.makeTitle(p.splitString(page_title, ':')[1], p.splitString(page_title, ':')[2])
Line 52: Line 64:
if (text ~= nil) then json = mw.text.jsonDecode(text) end
if (text ~= nil) then json = mw.text.jsonDecode(text) end
else
else
if (debug) then msg = msg .. "Fetch slot " .. p.slots.jsondata .. " from page " .. title .. "<br>" end
if (debug) then msg = msg .. "Fetch slot " .. p.slots.jsondata .. " of page " .. page_title .. "<br>" end
local text = mw.slots.slotContent( slot , page_title )
local text = mw.slots.slotContent( slot , page_title )
if (text ~= nil) then json = mw.text.jsonDecode(text) end
if (text ~= nil) then json = mw.text.jsonDecode(text) end
end
end
local generated_content = json["$defs"] and json["$defs"]["generated"]
if generated_content then
    -- Check if "$ref": "#/$defs/generated" exists directly in the table
    if json["$ref"] == "#/$defs/generated" then
        json = p.tableMerge(p.copy(generated_content), json)
        json["$ref"] = nil -- Remove the reference after merging
    end
    -- Check if "$ref": "#/$defs/generated" is contained in "allOf"
    if json["allOf"] then
        for _, item in ipairs(json["allOf"]) do
            if item["$ref"] == "#/$defs/generated" then
           
            -- Remove the reference after merging
                for i, v in ipairs(json["allOf"]) do
                    if v["$ref"] == "#/$defs/generated" then
                        table.remove(json["allOf"], i)
                        break
                    end
                end
                json = p.tableMerge(p.copy(generated_content), json)
               
                break
            end
        end
    end
    json["$defs"]["generated"] = nil
end
--[[local defs = p.defaultArgPath(json, {"$defs", "generated"}, nil)
if defs == nil then defs = p.defaultArgPath(json, {"definitions", "generated"}, nil) end
if defs ~= nil then
json = p.tableMerge(p.copy(defs), json)
json["allOf"] = p.tableMerge(json["allOf"], p.copy(defs["allOf"]))
end]]--
--mw.logObject(json)
--mw.logObject(json)
p.cache[page_title][slot] = json


return {json=json, debug_msg=msg}
return {json=json, debug_msg=msg}
end
end


-- test: mw.logObject(p.walkJsonSchema({jsonschema=p.loadJson({title="Category:Hardware", slot="jsonschema"}).json, debug=true}).jsonschema)
-- test: mw.logObject(p.walkJsonSchema({jsonschema=p.loadJson({title="Category:Hardware", slot="jsonschema"}).json, debug=true}).jsonschema)
Line 70: Line 122:
local mode = p.defaultArg(args.mode, p.mode.header)
local mode = p.defaultArg(args.mode, p.mode.header)
--local merged_jsonschema = p.defaultArg(args.merged_jsonschema, {})
--local merged_jsonschema = p.defaultArg(args.merged_jsonschema, {})
local template = p.defaultArg(args.template, nil)
local templates = p.defaultArg(args.templates, {})
local templates = p.defaultArg(args.templates, {})
local recursive = p.defaultArg(args.recursive, true)
local recursive = p.defaultArg(args.recursive, true)
Line 81: Line 134:
if (mode == p.mode.header) then category_template_slot = p.slots.header_template end
if (mode == p.mode.header) then category_template_slot = p.slots.header_template end
if (categories == nil) then categories = p.getCategories({jsonschema=jsonschema, includeNamespace=true}).categories end
if (categories == nil) then categories = p.getCategories({jsonschema=jsonschema, includeNamespace=true, includeSchemas=true}).categories end
if (type(categories) ~= 'table') then categories = {categories} end
if (type(categories) ~= 'table') then categories = {categories} end
if (debug) then msg = msg .. "Supercategories: " .. mw.dumpObject(categories) .. "\n<br>" end
if (debug) then msg = msg .. "Supercategories: " .. mw.dumpObject(categories) .. "\n<br>" end
Line 88: Line 141:
--mw.logObject("Visit " .. category)
--mw.logObject("Visit " .. category)
if (debug) then msg = msg .. "Fetch slot " .. p.slots.jsonschema .. " from page " .. category .. "\n<br>" end
if (debug) then msg = msg .. "Fetch slot " .. p.slots.jsonschema .. " from page " .. category .. "\n<br>" end
local super_jsonschema_str = mw.slots.slotContent( p.slots.jsonschema , category )
local super_jsonschema = nil
if (super_jsonschema_str ~= nil) then
if p.splitString(category, ':')[1] == "JsonSchema" then super_jsonschema = p.loadJson({title=category, slot=p.slots.main}).json
super_jsonschema = mw.text.jsonDecode( super_jsonschema_str )
else super_jsonschema = p.loadJson({title=category, slot=p.slots.jsonschema}).json end
mw.logObject("INSERT")
mw.logObject(super_jsonschema)
if (super_jsonschema ~= nil) then
if (recursive) then
if (recursive) then
local res = p.walkJsonSchema({jsonschema=super_jsonschema, jsonschemas=jsonschemas, templates=templates, mode=mode, visited=visited, root=false})
local res = p.walkJsonSchema({jsonschema=super_jsonschema, jsonschemas=jsonschemas, templates=templates, mode=mode, visited=visited, root=false})
Line 99: Line 155:
--mw.logObject("Store " .. category)
--mw.logObject("Store " .. category)
table.insert(visited, category)
table.insert(visited, category)
jsonschemas[category] = mw.text.jsonDecode( super_jsonschema_str ) --keep a copy of the schema, super_jsonschema passed by references gets modified
jsonschemas[category] = p.copy( super_jsonschema ) --keep a copy of the schema, super_jsonschema passed by references gets modified
--jsonschema = p.tableMerge(jsonschema, super_jsonschema) --merge superschema is done by the caller
--jsonschema = p.tableMerge(jsonschema, super_jsonschema) --merge superschema is done by the caller
end
end
Line 107: Line 164:
end
end
end
end
if (root and p.tableLength(jsonschema) > 0) then
table.insert(visited, "_") -- dummy category for own schema
jsonschemas["_"] = p.copy(jsonschema)
templates["_"] = template
end
if (root) then
if (root) then
for i, category in ipairs(visited) do
for i, category in ipairs(visited) do
Line 137: Line 199:
local msg = ""
local msg = ""
local res = p.defaultArg(args.jsondata, "")
local res = p.defaultArg(args.jsondata, "")
local root = p.defaultArg(args.root, true) -- first entry into recursion
for k,v in pairs(jsondata) do
for k,v in pairs(jsondata) do
Line 160: Line 223:
end
end
elseif type(v) == 'table' then  
elseif type(v) == 'table' then  
if (v[1] == nil) then --key value array = object/dict
if (p.tableLength(v) > 0 and v[1] == nil) then --key value array = object/dict
local sub_res = p.expandEmbeddedTemplates({frame=frame, jsondata=v, jsonschema=p.defaultArgPath(jsonschema, {"properties", k}, {}), template=eval_template, mode=mode, stringify_arrays=stringify_arrays})
local sub_res = p.expandEmbeddedTemplates({frame=frame, jsondata=v, jsonschema=p.defaultArgPath(jsonschema, {"properties", k}, {}), template=eval_template, mode=mode, stringify_arrays=stringify_arrays, root=false})
msg = msg .. sub_res.debug_msg
msg = msg .. sub_res.debug_msg
jsondata[k] = sub_res.res
jsondata[k] = sub_res.res
Line 181: Line 244:


if type(e) == 'table' then
if type(e) == 'table' then
local sub_res = p.expandEmbeddedTemplates({frame=frame, jsondata=e, jsonschema=p.defaultArgPath(jsonschema, {"properties", k, "items"}, {}), template=eval_template, mode=mode, stringify_arrays=stringify_arrays})
local sub_res = p.expandEmbeddedTemplates({frame=frame, jsondata=e, jsonschema=p.defaultArgPath(jsonschema, {"properties", k, "items"}, {}), template=eval_template, mode=mode, stringify_arrays=stringify_arrays, root=false})
msg = msg .. sub_res.debug_msg
msg = msg .. sub_res.debug_msg
if (type(sub_res.res) == 'table') then  
if (type(sub_res.res) == 'table') then  
Line 193: Line 256:
--evaluate single array item string as json {"self": "<value>", ".": "<value>"} => does not work since jsondata is an object
--evaluate single array item string as json {"self": "<value>", ".": "<value>"} => does not work since jsondata is an object
--e = p.expandEmbeddedTemplates({frame=frame, jsondata={["self"]=e,["."]=e}, jsonschema=p.defaultArgPath(jsonschema, {"properties", k, "items"}, {}), template=eval_template, mode=mode, stringify_arrays=stringify_arrays})
--e = p.expandEmbeddedTemplates({frame=frame, jsondata={["self"]=e,["."]=e}, jsonschema=p.defaultArgPath(jsonschema, {"properties", k, "items"}, {}), template=eval_template, mode=mode, stringify_arrays=stringify_arrays, root=false})


Line 216: Line 279:
if (template == nil) then  
if (template == nil and root == false) then -- don't stringify root json objects
local templates = jsondata[p.keys.template]
local templates = jsondata[p.keys.template]
if (templates == nil) then templates = p.defaultArg(jsonschema[p.keys.template], {}) end
if (templates == nil) then templates = p.defaultArg(jsonschema[p.keys.template], {}) end
Line 228: Line 291:
end
end
if template ~= nil then
if (template ~= nil and root == false) then -- don't stringify root json objects
if (template.type == "wikitext") then
if (template.type == "wikitext") then
for k,v in pairs(jsondata) do
for k,v in pairs(jsondata) do
Line 276: Line 339:
if (not p.nilOrEmpty(jsondata[p.keys.category])) then categories = jsondata[p.keys.category] end -- let json property overwrite function param
if (not p.nilOrEmpty(jsondata[p.keys.category])) then categories = jsondata[p.keys.category] end -- let json property overwrite function param
local schema_res = p.walkJsonSchema({jsonschema=jsonschema, categories=categories, mode=mode, recursive=recursive, debug=debug})
local schema_res = p.walkJsonSchema({jsonschema=jsonschema, template=template, categories=categories, mode=mode, recursive=recursive, debug=debug})
local expand_res = p.expandJsonRef({json=schema_res.jsonschema, debug=debug})
local expand_res = p.expandJsonRef({json=schema_res.jsonschema, debug=debug})
jsonschema = expand_res.json
jsonschema = expand_res.json
--mw.log(mw.text.jsonEncode(jsonschema))
--mw.log(mw.text.jsonEncode(jsonschema))
local display_label = p.defaultArgPath(jsondata, {p.keys.name}, "")
if (display_label == "" or (title.nsText ~= "Category" and title.nsText ~= "Property")) then
display_label = p.defaultArgPath(jsondata, {p.keys.label, 1, p.keys.text}, "") --prefere label for all non-category and non-property pages
end
local jsonld = p.copy(jsondata)
local jsonld = p.copy(jsondata)
Line 291: Line 349:
json_res_store = p.expandEmbeddedTemplates({jsonschema=jsonschema, jsondata=json_data_store, mode='store'})
json_res_store = p.expandEmbeddedTemplates({jsonschema=jsonschema, jsondata=json_data_store, mode='store'})
msg = msg .. json_res_store.debug_msg
msg = msg .. json_res_store.debug_msg
--mw.log("JSONDATA STORE")
mw.log("JSONDATA STORE")
--mw.logObject(json_res_store.res)
mw.logObject(json_res_store.res)
local smw_res = nil
local smw_res = nil
Line 302: Line 360:
-- store metadata where properties were defined / overridden
-- store metadata where properties were defined / overridden
for i, category in ipairs(schema_res.visited) do  
for i, category in ipairs(schema_res.visited) do  
for k, v in pairs(schema_res.jsonschemas[category]['properties']) do
for k, v in pairs(p.defaultArgPath(schema_res.jsonschemas, {category, 'properties'}, {})) do --property section may not exisit
if smw_res.definitions[k] == nil then smw_res.definitions[k] = {} end
if smw_res.definitions[k] == nil then smw_res.definitions[k] = {} end
if smw_res.definitions[k]['defined_in'] == nil then smw_res.definitions[k]['defined_in'] = {} end
if smw_res.definitions[k]['defined_in'] == nil then smw_res.definitions[k]['defined_in'] = {} end
Line 320: Line 378:
end
end
end
end
wikitext = wikitext .. "<div class='jsonld-header' style='display:none' data-jsonld='" .. mw.text.jsonEncode( jsonld ):gsub("'","`") .. "'></div>"
-- wikitext = wikitext .. "<div class='jsonld-header' style='display:none' data-jsonld='" .. mw.text.jsonEncode( jsonld ):gsub("'","`") .. "'></div>"
end
end
Line 362: Line 420:
end
end
--local display_label = ""
--if (jsondata[p.keys.label] ~= nil) then display_label = p.splitString(jsondata[p.keys.label], '@')[1] end
local set_categories_in_wikitext = {}
local set_categories_in_wikitext = {}
p.tableMerge(set_categories_in_wikitext, json_res_store.res[p.keys.subcategory])  --classes/categories, nil for items
p.tableMerge(set_categories_in_wikitext, json_res_store.res[p.keys.subcategory])  --classes/categories, nil for items
Line 369: Line 425:
p.tableMerge(set_categories_in_wikitext, json_res_store.res[p.keys.category]) -- categories from schema type
p.tableMerge(set_categories_in_wikitext, json_res_store.res[p.keys.category]) -- categories from schema type
end
end
-- Todo: Consider moving the category and this block to p.getSemanticProperties with store=true. However, settings categories with @category is only possible for subobjects
-- Todo: Consider moving the category and this block to p.getSemanticProperties with store=true. However, settings categories with @category is only possible for subobjects
if (smw_res ~= nil) then
if (smw_res ~= nil) then
local display_label = p.getDisplayLabel(jsondata, smw_res.properties)
if title.nsText == "Property" then display_label = p.defaultArgPath(jsondata, {p.keys.name}, display_label) end
if (debug) then msg = msg .. "Store page properties" end
if (debug) then msg = msg .. "Store page properties" end
-- category handling
-- category handling
Line 380: Line 441:
-- label and display title handling
-- label and display title handling
smw_res.properties['Display title of'] = display_label --set special property display title
if display_label ~= nil then
smw_res.properties['Display title of lowercase'] = display_label:lower() --store lowercase for case insensitive query
smw_res.properties['Display title of'] = display_label --set special property display title
smw_res.properties['Display title of normalized'] = display_label:lower():gsub('[^%w]+','') --store with all non-alphanumeric chars removed for normalized query
smw_res.properties['Display title of lowercase'] = display_label:lower() --store lowercase for case insensitive query
smw_res.properties['Display title of normalized'] = display_label:lower():gsub('[^%w]+','') --store with all non-alphanumeric chars removed for normalized query
end
p.setNormalizedLabel(smw_res.properties) --build normalized multilang label
p.setNormalizedLabel(smw_res.properties) --build normalized multilang label
mw.ext.displaytitle.set(display_label)
mw.ext.displaytitle.set(display_label)
Line 484: Line 547:
elseif (type(v) == 'boolean') then  
elseif (type(v) == 'boolean') then  
if (v) then v = "&#x2705;" else v = "&#x274C;" end -- green check mark or red cross
if (v) then v = "&#x2705;" else v = "&#x274C;" end -- green check mark or red cross
elseif ((string.len(e) > 100) and (string.find(e, "{{") == nil) and (string.find(e, "</") == nil)) then  
elseif ((string.len(e) > 100) and (string.find(e, "{{") == nil) and (string.find(e, "</") == nil) and (string.find(e, "%[%[") == nil)) then -- no markup, no links
e = string.sub(e, 1, 100) .. "..."; -- limit infobox plain text to max 100 chars
e = string.sub(e, 1, 100) .. "..."; -- limit infobox plain text to max 100 chars
elseif (debug) then
elseif (debug) then
Line 511: Line 574:
elseif (type(v) == 'boolean') then  
elseif (type(v) == 'boolean') then  
if (v) then v = "&#x2705;" else v = "&#x274C;" end -- green check mark or red cross
if (v) then v = "&#x2705;" else v = "&#x274C;" end -- green check mark or red cross
elseif ((string.len(v) > 100) and (string.find(v, "{{") == nil) and (string.find(v, "</") == nil)) then
elseif ((string.len(v) > 100) and (string.find(v, "{{") == nil) and (string.find(v, "</") == nil) and (string.find(v, "%[%[") == nil)) then -- no markup, no links
v = string.sub(v, 1, 100) .. "..."; -- limit infobox plain text to max 100 chars
v = string.sub(v, 1, 100) .. "..."; -- limit infobox plain text to max 100 chars
elseif (debug) then
elseif (debug) then
Line 534: Line 597:
local jsonschema = p.defaultArg(args.jsonschema, {})
local jsonschema = p.defaultArg(args.jsonschema, {})
local includeNamespace = p.defaultArg(args.includeNamespace, false)
local includeNamespace = p.defaultArg(args.includeNamespace, false)
local includeSchemas = p.defaultArg(args.includeSchemas, false)
local categories = {}
local categories = {}
Line 540: Line 604:
--properties['@category'] = {}
--properties['@category'] = {}
for k, entry in pairs(allOf) do
for k, entry in pairs(allOf) do
if type(entry) == 'table' then -- "allOf": [{"$ref": "/wiki/Category:Test?action=raw"}]
local refs = nil
for p, v in pairs(entry) do
if type(entry) == 'table' then refs = entry -- "allOf": [{"$ref": "/wiki/Category:Test?action=raw"}]
if (p == '$ref') then
else refs = {entry} end-- "allOf": {"$ref": "/wiki/Category:Test?action=raw"}
for category in v:gmatch("Category:([^?]+)") do -- e.g. "/wiki/Category:Test?action=raw"
for p, v in pairs(entry) do
if (includeNamespace) then category = "Category:" .. category end
if (p == '$ref') then
    table.insert(categories, category)
for category in v:gmatch("Category:([^?]+)") do -- e.g. "/wiki/Category:Test?action=raw"
if (includeNamespace) then category = "Category:" .. category end
    table.insert(categories, category)
end
if includeSchemas then
for schema in v:gmatch("JsonSchema:([^?]+)") do -- e.g. "/wiki/JsonSchema:Test?action=raw"
if (includeNamespace) then schema = "JsonSchema:" .. schema end
    table.insert(categories, schema)
end
end
end
end
end
end
else -- "allOf": {"$ref": "/wiki/Category:Test?action=raw"}
if (k == '$ref') then
for category in entry:gmatch("Category:([^?]+)") do -- e.g. "/wiki/Category:Test?action=raw"
if (includeNamespace) then category = "Category:" .. category end
table.insert(categories, category)
end
end
end
end
end
end
Line 739: Line 803:
context = p.tableMerge(context, subcontext) -- pull up nested context
context = p.tableMerge(context, subcontext) -- pull up nested context
local values = {}
local values = {}
if (v[1] == nil) then --key value array = object/dict
if (p.tableLength(v) > 0 and v[1] == nil) then --key value array = object/dict => subobject
local subproperties_res = p.getSemanticProperties({jsonschema=schema, jsondata=v, properties=p.copy(subobject_properties), store=true, root=false, debug=debug, context=context, subschema=schema_properties[k], parent_schema_property=property_data[k]})
local subproperties_res = p.getSemanticProperties({jsonschema=schema, jsondata=v, properties=p.copy(subobject_properties), store=true, root=false, debug=debug, context=context, subschema=schema_properties[k], parent_schema_property=property_data[k]})
local id = subproperties_res.id --subobject_id
local id = subproperties_res.id --subobject_id
Line 790: Line 854:
p.tableMerge(properties['@category'], properties[p.keys.category_pseudoproperty]) -- from json-ld context 'Property:Category'
p.tableMerge(properties['@category'], properties[p.keys.category_pseudoproperty]) -- from json-ld context 'Property:Category'
properties[p.keys.category_pseudoproperty] = nil -- delete pseudo property
properties[p.keys.category_pseudoproperty] = nil -- delete pseudo property
if (jsondata[p.keys.name] ~= nil) then properties['Display title of'] = jsondata[p.keys.name]  
elseif (jsondata[p.keys.label] ~= nil and jsondata[p.keys.label][1] ~= nil) then properties['Display title of'] = p.splitString(jsondata[p.keys.label][1], '@')[1]
local display_label = p.getDisplayLabel(jsondata, properties)
else properties['Display title of'] = p.defaultArg(subschema['title'], "") end
if properties['Display title of'] == nil and properties['Display_title_of'] == nil then
if (display_label ~= nil and display_label ~= "") then properties['Display title of'] = display_label
else properties['Display title of'] = p.defaultArg(subschema['title'], "") end -- fall back to property name in schema
end
p.setNormalizedLabel(properties) --build normalized multilang label
p.setNormalizedLabel(properties) --build normalized multilang label
if (p.tableLength(properties) > 0) then
if (p.tableLength(properties) > 0) then
Line 1,032: Line 1,099:
   for k, v in pairs(obj) do res[p.copy(k, s)] = p.copy(v, s) end
   for k, v in pairs(obj) do res[p.copy(k, s)] = p.copy(v, s) end
   return res
   return res
end
-- get normalized label
function p.getDisplayLabel(jsondata, properties)
local display_label = nil
-- check if label properties are mapped
if (properties["HasLabel"] ~= nil and properties["HasLabel"][1] ~= nil) then display_label = p.splitString(properties["HasLabel"][1], '@')[1]
elseif (properties["HasName"] ~= nil) then
if type(properties["HasName"]) == 'table' then display_label = properties["HasName"][1]
else display_label = properties["HasName"] end
-- fall back to unmapped keywords
elseif (jsondata[p.keys.label] ~= nil and jsondata[p.keys.label][1] ~= nil) then display_label = p.splitString(jsondata[p.keys.label][1], '@')[1]
elseif (jsondata[p.keys.name] ~= nil) then display_label = jsondata[p.keys.name]
end
return display_label
end
end


Cookies help us deliver our services. By using our services, you agree to our use of cookies.