package diff;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Properties;
import java.util.Set;
import org.semanticweb.owlapi.model.OWLAnnotationAssertionAxiom;
import org.semanticweb.owlapi.model.OWLAxiom;
import org.semanticweb.owlapi.model.OWLClass;
import org.semanticweb.owlapi.model.OWLClassExpression;
import org.semanticweb.owlapi.model.OWLDataPropertyDomainAxiom;
import org.semanticweb.owlapi.model.OWLDataPropertyRangeAxiom;
import org.semanticweb.owlapi.model.OWLObjectIntersectionOf;
import org.semanticweb.owlapi.model.OWLObjectPropertyDomainAxiom;
import org.semanticweb.owlapi.model.OWLObjectPropertyRangeAxiom;
import org.semanticweb.owlapi.model.OWLObjectUnionOf;
import org.semanticweb.owlapi.model.OWLPropertyExpression;
import org.semanticweb.owlapi.model.OWLSubClassOfAxiom;
import org.semanticweb.owlapi.model.OWLSubPropertyAxiom;
import uk.ac.manchester.cs.owl.owlapi.OWLDataPropertyImpl;
import uk.ac.manchester.cs.owl.owlapi.OWLObjectPropertyImpl;
import widoco.Constants;
/**
* class to render diff objects in HTML. Separated from the main class
* to calculate
* @author dgarijo
*/
public class OntologyDifferencesRenderer {
/**
* convenience method to print information on diff to console
*
* @param c
*/
public static void differenceSummaryToString(CompareOntologies c) {
System.out.println();
System.out.println("@Ontology Change Summary");
System.out.println("@First ontology IRI: " + c.getOldVersion());
System.out.println("@Second ontology IRI: " + c.getNewVersion());
System.out.println("@Number of classes changed: " + c.getModifiedClasses().size());
System.out.println("@Number of classes added: " + c.getNewClasses().size());
System.out.println("@Number of classes deleted: " + c.getDeletedClasses().size());
System.out.println("@Number of properties changed: " + c.getModifiedProperties().size());
System.out.println("@Number of properties added: " + c.getNewProperties().size());
System.out.println("@Number of properties deleted: " + c.getDeletedProperties().size());
System.out.println("@Number of data properties changed: " + c.getModifiedDataProperties().size());
System.out.println("@Number of data properties added: " + c.getNewDataProperties().size());
System.out.println("@Number of data properties deleted: " + c.getDeletedDataProperties().size());
ArrayList<OWLAxiomInfo> modifiedClasses = c.getModifiedClasses();
if (!modifiedClasses.isEmpty()) {
System.out.println("\n@Modified classes");
System.out.println(setToString(modifiedClasses, "Class changed", true));
System.out.println();
}
ArrayList<OWLAxiomInfo> newClasses = c.getNewClasses();
if (!newClasses.isEmpty()) {
System.out.println("@New Classes");
System.out.println(setToString(newClasses, "Class added", true));
System.out.println();
}
ArrayList<OWLAxiomInfo> deletedClasses = c.getDeletedClasses();
if (!deletedClasses.isEmpty()) {
System.out.println("@Deleted Classes");
System.out.println(setToString(deletedClasses, "Deleted class", false));
System.out.println();
}
ArrayList<OWLAxiomInfo> modifiedProperties = c.getModifiedProperties();
if (!modifiedProperties.isEmpty()) {
System.out.println("\n@Modified properties");
System.out.println(setToString(modifiedProperties, "Property changed", true));
System.out.println();
}
ArrayList<OWLAxiomInfo> newProperties = c.getNewProperties();
if (!newProperties.isEmpty()) {
System.out.println("@New Properties");
System.out.println(setToString(newProperties, "Property added", true));
System.out.println();
}
ArrayList<OWLAxiomInfo> deletedProperties = c.getDeletedProperties();
if (!deletedProperties.isEmpty()) {
System.out.println("@Deleted Properties");
System.out.println(setToString(deletedProperties, "Property deleted", false));
System.out.println();
}
ArrayList<OWLAxiomInfo> modifiedDataProperties = c.getModifiedDataProperties();
if (!modifiedDataProperties.isEmpty()) {
System.out.println("\n@Modified Data properties");
System.out.println(setToString(modifiedDataProperties, "Data property changed", true));
System.out.println();
}
ArrayList<OWLAxiomInfo> newDataProperties = c.getNewDataProperties();
if (!newDataProperties.isEmpty()) {
System.out.println("@New Data Properties");
System.out.println(setToString(newDataProperties, "Data property added", true));
System.out.println();
}
ArrayList<OWLAxiomInfo> deletedDataProperties = c.getDeletedDataProperties();
if (!deletedDataProperties.isEmpty()) {
System.out.println("@Deleted Data Properties");
System.out.println(setToString(deletedDataProperties, "Data property deleted", false));
System.out.println();
}
}
/**
* Method to serialize a set as a string
* @param set
* @param initialMessage
* @param printDetails true if the goal is to print more details about the changes, e.g., modification of a term
* @return
*/
private static String setToString(ArrayList<OWLAxiomInfo>set, String initialMessage, boolean printDetails){
String v = "";
Iterator<OWLAxiomInfo> i = set.iterator();
while (i.hasNext()) {
OWLAxiomInfo classAxiomSet = i.next();
//if the output is write URIs print them
v+="---\n"+initialMessage+" ";
v+=classAxiomSet.getIRIAsString()+"\n";
if(printDetails){
if(classAxiomSet.getNewAxioms()!=null){
for(Object f:classAxiomSet.getNewAxioms()){
v+="+"+f.toString()+"\n";
}
}
if(classAxiomSet.getDeletedAxioms()!=null){
for(Object f:classAxiomSet.getDeletedAxioms()){
v+="-"+f.toString()+"\n";
}
}
}
}
return v;
}
/**
* Method to serialize a set as html. This method is designed to be called by added classes and properties.
* @param set
* @param initialMessage
* @param printDetails true if the goal is to print more details about the changes, e.g., modification of a term
* @return
*/
private static String axiomInfoSetToHTML(ArrayList<OWLAxiomInfo>set, String ns, boolean showAdditions, boolean showDeletions, Properties lang){
String v = "";
Iterator<OWLAxiomInfo> i = set.iterator();
while (i.hasNext()) {
OWLAxiomInfo axiomSet = i.next();
//we print the whole url of the new property and link to the document reference.
v+="<li><a href=\"#"+axiomSet.getIRIAsString().replace(ns, "")+"\">"+axiomSet.getIRIAsString()+"</a>\n";
if(showAdditions &&
axiomSet.getNewAxioms()!=null && !axiomSet.getNewAxioms().isEmpty()){
v+="<ul>\n";
v+=axiomSetToHTML(axiomSet.getNewAxioms(), true, lang);
v+="</ul>\n";
}
if(showDeletions &&
axiomSet.getDeletedAxioms()!=null && !axiomSet.getDeletedAxioms().isEmpty()){
v+="<ul>\n";
v+=axiomSetToHTML(axiomSet.getDeletedAxioms(), false, lang);
v+="</ul>\n";
}
v+="</li>\n";
}
return v;
}
private static String axiomSetToHTML(Set<Object> set, boolean isAddition, Properties lang){
String v = "";
String message;
if(isAddition){
message=lang.getProperty(Constants.LANG_ADDED)+": ";
}else{
message=lang.getProperty(Constants.LANG_DELETED)+": ";
}
for(Object f:set){
try{
v+="<li>";
if(f instanceof OWLSubClassOfAxiom){
v+=message+lang.getProperty(Constants.LANG_SUBCLASS_OF) +" "+ ((OWLSubClassOfAxiom)f).getSuperClass().asOWLClass().getIRI();
}else if(f instanceof OWLSubPropertyAxiom){
OWLPropertyExpression prop = ((OWLSubPropertyAxiom)f).getSuperProperty();
if(prop instanceof OWLObjectPropertyImpl){
v+=message+lang.getProperty(Constants.LANG_SUBPROP_OF) +" "+ ((OWLObjectPropertyImpl)prop).getIRI();
}else if(prop instanceof OWLDataPropertyImpl){
v+=message+lang.getProperty(Constants.LANG_SUBPROP_OF) +" "+ ((OWLDataPropertyImpl)prop).getIRI();
}
}else if(f instanceof OWLObjectPropertyDomainAxiom){
v+=message+Constants.LANG_DOMAIN+" "+expressionToHTML(((OWLObjectPropertyDomainAxiom)f).getDomain(), lang);
}else if(f instanceof OWLDataPropertyDomainAxiom){
v+=message+lang.getProperty(Constants.LANG_DOMAIN)+" "+expressionToHTML(((OWLDataPropertyDomainAxiom)f).getDomain(), lang);
}else if(f instanceof OWLObjectPropertyRangeAxiom){
v+=message+lang.getProperty(Constants.LANG_RANGE)+" "+expressionToHTML(((OWLObjectPropertyRangeAxiom)f).getRange(), lang);
}else if(f instanceof OWLDataPropertyRangeAxiom){
v+=message+lang.getProperty(Constants.LANG_RANGE)+" "+((OWLDataPropertyRangeAxiom)f).getRange().asOWLDatatype().getIRI();
}else if(f instanceof OWLAnnotationAssertionAxiom){
v+= message+((OWLAnnotationAssertionAxiom)f).getProperty().toString() +" "+ ((OWLAnnotationAssertionAxiom)f).getValue().toString();
}else{
//other less typical axioms
v+=message+((OWLAxiom)f).getAxiomType().getName()+" "+f.toString().replace("<", "<").replace(">", ">");
}
/**
* To add if we want to refine
* OWLDisjointClassesAxiom, OWLDisjointDataPropertiesAxiom, OWLDisjointObjectPropertiesAxiom,
* OWLEquivalentClassesAxiom, OWLEquivalentDataPropertiesAxiom, OWLEquivalentObjectPropertiesAxiom,
* OWLFunctionalDataPropertyAxiom, OWLFunctionalObjectPropertyAxiom,
*/
v+="</li>\n";
}catch (Exception e){
System.out.println("Error while transforming "+f.toString() +" "+e.getMessage());
}
}
return v;
}
/**
* Method to translate expressions to html. It is recursive as an expression
* could be the union of intersections or viceversa.
* @param expr
* @param lang
* @return
*/
private static String expressionToHTML(OWLClassExpression expr, Properties lang){
String v ="";
if(expr instanceof OWLClass){
v+=expr.asOWLClass().getIRI();
}else{
if(expr instanceof OWLObjectUnionOf || expr instanceof OWLObjectIntersectionOf){
if(expr instanceof OWLObjectUnionOf){
v+=lang.getProperty(Constants.LANG_UNION)+" (";
for(OWLClassExpression e:expr.asDisjunctSet()){
v+= expressionToHTML(e, lang)+", ";
}
}else{
v+=lang.getProperty(Constants.LANG_INTERSECTION)+" (";
for(OWLClassExpression e:expr.asConjunctSet()){
v+= expressionToHTML(e, lang)+", ";
}
}
if(v.length()>2){
v = v.substring(0, v.length()-2);//remove last comma
}
v+=")";
}
}
return v;
}
/**
* Method that renders the current differences as HTML.
* @param c the comparison object with all the differences to render
* @param ontologyNamepsace namespace of the ontology to link back
* @param language language file with the labels to be used in the report
* @return
*/
public static String differencesToHTML(CompareOntologies c, String ontologyNamepsace, Properties language){
String changelog="";
int changesInClasses = c.getDeletedClasses().size()+c.getModifiedClasses().size()+c.getNewClasses().size(),
changesInProps = c.getDeletedProperties().size()+c.getModifiedProperties().size()+c.getNewProperties().size(),
changesInDataProps = c.getDeletedDataProperties().size()+c.getModifiedProperties().size()+c.getNewDataProperties().size();
if(changesInClasses>0){
changelog+="<h3 id=\"changeClass\" class=\"list\">"+language.getProperty(Constants.LANG_CLASSES)+"</h3>\n";//this will be on the lang file later
if(!c.getModifiedClasses().isEmpty()){
changelog+="<p><u>"+language.getProperty(Constants.LANG_MODIFIED_CLASS)+"</u></p>\n";
changelog+="<ul>";
changelog += axiomInfoSetToHTML(c.getModifiedClasses(), ontologyNamepsace, true, true, language);
changelog+="</ul>";
}
if(!c.getNewClasses().isEmpty()){
changelog+="<p><u>"+language.getProperty(Constants.LANG_ADDED_CLASS)+"</u></p>\n";
changelog+="<ul>";
changelog += axiomInfoSetToHTML(c.getNewClasses(), ontologyNamepsace, true, false, language);
changelog+="</ul>";
}
if(!c.getDeletedClasses().isEmpty()){
changelog+="<p><u>"+language.getProperty(Constants.LANG_DELETED_CLASS)+"</u></p>\n";
changelog+="<ul>";
changelog += axiomInfoSetToHTML(c.getDeletedClasses(), ontologyNamepsace, false, false, language);
changelog+="</ul>";
}
}
if(changesInProps>0){
changelog+="<h3 id=\"changeProp\" class=\"list\">"+language.getProperty(Constants.LANG_OBJ_PROP)+"</h3>\n";
if(!c.getModifiedProperties().isEmpty()){
changelog+="<p><u>"+language.getProperty(Constants.LANG_MODIFIED_PROP)+"</u></p>\n";
changelog+="<ul>";
changelog += axiomInfoSetToHTML(c.getModifiedProperties(), ontologyNamepsace, true, true, language);
changelog+="</ul>";
}
if(!c.getNewProperties().isEmpty()){
changelog+="<p><u>"+language.getProperty(Constants.LANG_ADDED_PROP)+"</u></p>\n";
changelog+="<ul>";
changelog += axiomInfoSetToHTML(c.getNewProperties(), ontologyNamepsace, true, false, language);
changelog+="</ul>";
}
if(!c.getDeletedProperties().isEmpty()){
changelog+="<p><u>"+language.getProperty(Constants.LANG_DELETED_PROP)+"</u></p>\n";
changelog+="<ul>";
changelog += axiomInfoSetToHTML(c.getDeletedProperties(), ontologyNamepsace, false, false, language);
changelog+="</ul>";
}
}
if(changesInDataProps>0){
changelog+="<h3 id=\"changeDataProp\" class=\"list\">"+language.getProperty(Constants.LANG_DATA_PROP)+"</h3>\n";
if(!c.getModifiedDataProperties().isEmpty()){
changelog+="<p><u>"+language.getProperty(Constants.LANG_MODIFIED_DATA_PROP)+"</u></p>\n";
changelog+="<ul>";
changelog += axiomInfoSetToHTML(c.getModifiedDataProperties(), ontologyNamepsace, true, true, language);
changelog+="</ul>";
}
if(!c.getNewDataProperties().isEmpty()){
changelog+="<p><u>"+language.getProperty(Constants.LANG_ADDED_DATA_PROP)+"</u></p>\n";
changelog+="<ul>";
changelog += axiomInfoSetToHTML(c.getNewDataProperties(), ontologyNamepsace, true, false, language);
changelog+="</ul>";
}
if(!c.getDeletedDataProperties().isEmpty()){
changelog+="<p><u>"+language.getProperty(Constants.LANG_DELETED_DATA_PROP)+"</u></p>\n";
changelog+="<ul>";
changelog += axiomInfoSetToHTML(c.getDeletedDataProperties(), ontologyNamepsace, false, false, language);
changelog+="</ul>";
}
}
return changelog;
}
}