var OwlThing = require("../elements/nodes/implementations/OwlThing"); var RdfsLiteral = require("../elements/nodes/implementations/RdfsLiteral"); var elementTools = require("../util/elementTools")(); var equivalentPropertyMerger = {}; module.exports = function (){ return equivalentPropertyMerger; }; var PREFIX = "GENERATED-MERGED_RANGE-"; var OBJECT_PROPERTY_DEFAULT_RANGE_TYPE = "owl:Thing"; var DATA_PROPERTY_DEFAULT_RANGE_TYPE = "rdfs:Literal"; equivalentPropertyMerger.merge = function ( properties, nodes, propertyMap, nodeMap, graph ){ var totalNodeIdsToHide = d3.set(); var processedPropertyIds = d3.set(); var mergeNodes = []; for ( var i = 0; i < properties.length; i++ ) { var property = properties[i]; var equivalents = property.equivalents().map(createIdToPropertyMapper(propertyMap)); if ( equivalents.length === 0 || processedPropertyIds.has(property.id()) ) { continue; } var propertyWithEquivalents = equivalents.concat(property); var mergeNode = findMergeNode(propertyWithEquivalents, nodeMap); if ( !mergeNode ) { if ( mergeNode !== undefined ) { mergeNode = createDefaultMergeNode(property, graph); mergeNodes.push(mergeNode); } } var nodeIdsToHide = replaceRangesAndCollectNodesToHide(propertyWithEquivalents, mergeNode, properties, processedPropertyIds); for ( var j = 0; j < nodeIdsToHide.length; j++ ) { totalNodeIdsToHide.add(nodeIdsToHide[j]); } } return filterVisibleNodes(nodes.concat(mergeNodes), totalNodeIdsToHide); }; function createIdToPropertyMapper( propertyMap ){ return function ( id ){ return propertyMap[id]; }; } function findMergeNode( propertyWithEquivalents, nodeMap ){ var typeMap = mapPropertiesRangesToType(propertyWithEquivalents, nodeMap); var typeSet = d3.set(typeMap.keys()); // default types are the fallback values and should be ignored for the type determination typeSet.remove(OBJECT_PROPERTY_DEFAULT_RANGE_TYPE); typeSet.remove(DATA_PROPERTY_DEFAULT_RANGE_TYPE); // exactly one type to chose from -> take the node of this type as range if ( typeSet.size() === 1 ) { var type = typeSet.values()[0]; var ranges = typeMap.get(type); if ( ranges.length === 1 ) { return ranges[0]; } } } function mapPropertiesRangesToType( properties, nodeMap ){ var typeMap = d3.map(); properties.forEach(function ( property ){ if ( property === undefined ) //@ WORKAROUND return; var range = nodeMap[property.range()]; var type = range.type(); if ( !typeMap.has(type) ) { typeMap.set(type, []); } typeMap.get(type).push(range); }); return typeMap; } function createDefaultMergeNode( property, graph ){ var range; if ( elementTools.isDatatypeProperty(property) ) { range = new RdfsLiteral(graph); } else { range = new OwlThing(graph); } range.id(PREFIX + property.id()); return range; } function replaceRangesAndCollectNodesToHide( propertyWithEquivalents, mergeNode, properties, processedPropertyIds ){ var nodesToHide = []; propertyWithEquivalents.forEach(function ( property ){ if ( property === undefined || mergeNode === undefined ) // @ WORKAROUND return; var oldRangeId = property.range(); property.range(mergeNode.id()); if ( !isDomainOrRangeOfOtherProperty(oldRangeId, properties) ) { nodesToHide.push(oldRangeId); } processedPropertyIds.add(property.id()); }); return nodesToHide; } function isDomainOrRangeOfOtherProperty( nodeId, properties ){ for ( var i = 0; i < properties.length; i++ ) { var property = properties[i]; if ( property.domain() === nodeId || property.range() === nodeId ) { return true; } } return false; } function filterVisibleNodes( nodes, nodeIdsToHide ){ var filteredNodes = []; nodes.forEach(function ( node ){ if ( !nodeIdsToHide.has(node.id()) ) { filteredNodes.push(node); } }); return filteredNodes; }