001    /**
002     * Copyright (C) 2007-2011, Jens Lehmann
003     *
004     * This file is part of DL-Learner.
005     *
006     * DL-Learner is free software; you can redistribute it and/or modify
007     * it under the terms of the GNU General Public License as published by
008     * the Free Software Foundation; either version 3 of the License, or
009     * (at your option) any later version.
010     *
011     * DL-Learner is distributed in the hope that it will be useful,
012     * but WITHOUT ANY WARRANTY; without even the implied warranty of
013     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
014     * GNU General Public License for more details.
015     *
016     * You should have received a copy of the GNU General Public License
017     * along with this program.  If not, see <http://www.gnu.org/licenses/>.
018     */
019    
020    package org.dllearner.kb.sparql;
021    import java.util.Iterator;
022    import java.util.Set;
023    
024    import org.apache.log4j.Logger;
025    import org.dllearner.algorithms.gp.ADC;
026    import org.dllearner.core.ComponentManager;
027    import org.dllearner.core.AbstractReasonerComponent;
028    import org.dllearner.core.owl.Constant;
029    import org.dllearner.core.owl.DatatypeExactCardinalityRestriction;
030    import org.dllearner.core.owl.DatatypeMaxCardinalityRestriction;
031    import org.dllearner.core.owl.DatatypeMinCardinalityRestriction;
032    import org.dllearner.core.owl.DatatypeSomeRestriction;
033    import org.dllearner.core.owl.DatatypeValueRestriction;
034    import org.dllearner.core.owl.Description;
035    import org.dllearner.core.owl.DescriptionVisitor;
036    import org.dllearner.core.owl.Entity;
037    import org.dllearner.core.owl.Individual;
038    import org.dllearner.core.owl.Intersection;
039    import org.dllearner.core.owl.NamedClass;
040    import org.dllearner.core.owl.Negation;
041    import org.dllearner.core.owl.Nothing;
042    import org.dllearner.core.owl.ObjectAllRestriction;
043    import org.dllearner.core.owl.ObjectExactCardinalityRestriction;
044    import org.dllearner.core.owl.ObjectMaxCardinalityRestriction;
045    import org.dllearner.core.owl.ObjectMinCardinalityRestriction;
046    import org.dllearner.core.owl.ObjectOneOf;
047    import org.dllearner.core.owl.ObjectProperty;
048    import org.dllearner.core.owl.ObjectSomeRestriction;
049    import org.dllearner.core.owl.ObjectValueRestriction;
050    import org.dllearner.core.owl.Thing;
051    import org.dllearner.core.owl.Union;
052    import org.dllearner.parser.KBParser;
053    import org.dllearner.parser.ParseException;
054    
055    /**
056     * Converter from DL-Learner descriptions to a corresponding natural
057     * language description.
058     * 
059     * @author Sebastian Knappe
060     * 
061     *
062     */
063    public class NaturalLanguageDescriptionConvertVisitor implements DescriptionVisitor{
064            
065            private static Logger logger = Logger.getLogger(ComponentManager.class);
066    
067            private String query="";
068            
069            private AbstractReasonerComponent service;
070            
071            public NaturalLanguageDescriptionConvertVisitor(AbstractReasonerComponent service)
072            {
073                    //stack.push("subject");
074                    this.service=service;
075            }
076            
077            private String getDescription()
078            {       // for old function see below
079                    // it was using the object attribute in a strange way
080                    // QUALITY: what if this function is called several times?? should be private maybe?
081                    String tmpQuery=""+query;
082                    
083                    query = tmpQuery;
084                    return query;
085            }
086            
087            public static String getNaturalLanguageDescription(Description description, AbstractReasonerComponent service)
088            {
089                    NaturalLanguageDescriptionConvertVisitor visitor=new NaturalLanguageDescriptionConvertVisitor(service);
090                    description.accept(visitor);
091                    String ret = visitor.getDescription();
092                    return ret;
093            }
094            
095            public static String getNaturalLanguageDescription(String descriptionKBSyntax, AbstractReasonerComponent service) throws ParseException
096            {       
097                    Description d = KBParser.parseConcept(descriptionKBSyntax);
098                    NaturalLanguageDescriptionConvertVisitor visitor=new NaturalLanguageDescriptionConvertVisitor(service);
099                    d.accept(visitor);
100                    String ret = visitor.getDescription();
101                    return ret;
102            }
103            
104            private String getLabelFromReasoner(Entity ent)
105            {
106                    String label;
107    //              try{
108                            Set<Constant> set=service.getLabel(ent);
109                            if (set.size()>0){
110                                    Iterator<Constant> iter=set.iterator();
111                                    label=iter.next().getLiteral();
112                            }
113                            else label="";
114    //              }
115    //              catch (ReasoningMethodUnsupportedException e)
116    //              {
117    //                      label="";
118    //              }
119                    
120                    return label;
121            }
122            
123            /**
124             * Used for testing the Sparql Query converter.
125             * 
126             * @param args
127             */
128            public static void main(String[] args) {
129                    try {
130                            /*SortedSet<String> s = new TreeSet<String>();
131                            HashMap<String,String> result = new HashMap<String,String>();
132                            String conj="(\"http://dbpedia.org/class/yago/Person100007846\" AND \"http://dbpedia.org/class/yago/Head110162991\")";
133                            s.add("EXISTS \"http://dbpedia.org/property/disambiguates\".TOP");
134                            s.add("EXISTS \"http://dbpedia.org/property/successor\".\"http://dbpedia.org/class/yago/Person100007846\"");
135                            s.add("EXISTS \"http://dbpedia.org/property/successor\"."+conj);
136                            s.add("ALL \"http://dbpedia.org/property/disambiguates\".TOP");
137                            s.add("ALL \"http://dbpedia.org/property/successor\".\"http://dbpedia.org/class/yago/Person100007846\"");
138                            s.add("\"http://dbpedia.org/class/yago/Person100007846\"");
139                            s.add(conj);
140                            s.add("(\"http://dbpedia.org/class/yago/Person100007846\" OR \"http://dbpedia.org/class/yago/Head110162991\")");
141                            s.add("NOT \"http://dbpedia.org/class/yago/Person100007846\"");
142                            s.add("(\"http://dbpedia.org/class/yago/HeadOfState110164747\" AND (\"http://dbpedia.org/class/yago/Negotiator110351874\" AND \"http://dbpedia.org/class/yago/Representative110522035\"))");
143                            for (String kbsyntax : s) {
144                                    result.put(kbsyntax,NaturalLanguageDescriptionConvertVisitor.getNaturalLanguageDescription(kbsyntax,"DBPEDIA"));
145                            }
146                            System.out.println("************************");
147                            for (String string : result.keySet()) {
148                                    System.out.println("KBSyntayString: "+string);
149                                    System.out.println("Query:\n"+result.get(string));
150                                    System.out.println("************************");
151                            }
152                            System.out.println("Finished");*/
153                            //String conj="EXISTS \"http://xmlns.com/foaf/0.1/page\".<= 0 \"http://www.w3.org/2004/02/skos/core#subject\".TOP";
154                            //String conj="(\"Male\" AND (\"hasDog\" = 18))";
155    //                      ObjectValueRestriction rest=new ObjectValueRestriction(new ObjectProperty("hasAge"),new Individual("18"));
156                            //System.out.println(NaturalLanguageDescriptionConvertVisitor.getNaturalLanguageDescription(rest));
157                    } catch (/*Parse*/Exception e) {
158                            // TODO Auto-generated catch block
159                            e.printStackTrace();
160                    }
161            }
162            
163            /* (non-Javadoc)
164             * @see org.dllearner.core.owl.DescriptionVisitor#visit(org.dllearner.core.owl.Negation)
165             */
166            public void visit(Negation description) {
167                    logger.trace("Negation");
168                    query+="not ";
169                    description.getChild(0).accept(this);
170            }
171    
172            /* (non-Javadoc)
173             * @see org.dllearner.core.owl.DescriptionVisitor#visit(org.dllearner.core.owl.ObjectAllRestriction)
174             */
175            public void visit(ObjectAllRestriction description) {
176                    logger.trace("ObjectAllRestriction");
177                    String label=getLabelFromReasoner((ObjectProperty)description.getRole());
178                    if (label.length()>0) query+="all "+label+" are ";
179                    else query+="all "+description.getRole().toString().substring(description.getRole().toString().lastIndexOf("/")+1)+" are ";
180                    description.getChild(0).accept(this);
181                    logger.trace(description.getRole().toString());
182                    logger.trace(description.getChild(0).toString());
183            }
184    
185            /* (non-Javadoc)
186             * @see org.dllearner.core.owl.DescriptionVisitor#visit(org.dllearner.core.owl.ObjectSomeRestriction)
187             */
188            public void visit(ObjectSomeRestriction description) {
189                    logger.trace("ObjectSomeRestriction");
190                    String label=getLabelFromReasoner((ObjectProperty)description.getRole());
191                    if (label.length()>0) query+="has "+label+" which is ";
192                    else query+="has "+description.getRole().toString().substring(description.getRole().toString().lastIndexOf("/")+1)+" which is ";
193                    description.getChild(0).accept(this);
194                    logger.trace(description.getRole().toString());
195                    logger.trace(description.getChild(0).toString());
196            }
197    
198            /* (non-Javadoc)
199             * @see org.dllearner.core.owl.DescriptionVisitor#visit(org.dllearner.core.owl.Nothing)
200             */
201            public void visit(Nothing description) {
202                    logger.trace("Nothing");
203                    if (query.endsWith("which is ")) query=query.substring(0, query.length()-10);
204                    if (query.endsWith("are ")) query=query.substring(0, query.length()-5);
205                    if (query.endsWith("and ")) query=query.substring(0, query.length()-5);
206                    if (query.endsWith("or ")) query=query.substring(0, query.length()-4);
207                    //query+="nothing";
208            }
209    
210            /* (non-Javadoc)
211             * @see org.dllearner.core.owl.DescriptionVisitor#visit(org.dllearner.core.owl.Thing)
212             */
213            public void visit(Thing description) {
214                    logger.trace("Thing");
215                    if (query.endsWith("which is ")) query=query.substring(0, query.length()-10);
216                    if (query.endsWith("are ")) query=query.substring(0, query.length()-5);
217                    if (query.endsWith("and ")) query=query.substring(0, query.length()-5);
218                    if (query.endsWith("or ")) query=query.substring(0, query.length()-4);
219                    //query+="anything";
220            }
221    
222            /* (non-Javadoc)
223             * @see org.dllearner.core.owl.DescriptionVisitor#visit(org.dllearner.core.owl.Intersection)
224             */
225            public void visit(Intersection description) {
226                    // HACK see replace hacks in other functions
227                    logger.trace("Intersection");
228                    description.getChild(0).accept(this);
229                    query+=" and ";
230                    description.getChild(1).accept(this);
231            }
232    
233            /* (non-Javadoc)
234             * @see org.dllearner.core.owl.DescriptionVisitor#visit(org.dllearner.core.owl.Union)
235             */
236            public void visit(Union description) {
237                    // HACK see replace hacks in other functions
238                    logger.trace("Union");
239                    description.getChild(0).accept(this);
240                    query+=" or ";
241                    description.getChild(1).accept(this);
242            }
243    
244            /* (non-Javadoc)
245             * @see org.dllearner.core.owl.DescriptionVisitor#visit(org.dllearner.core.owl.ObjectMinCardinalityRestriction)
246             */
247            public void visit(ObjectMinCardinalityRestriction description) {
248                    logger.trace("ObjectMinCardinalityRestriction");
249                    if (query.endsWith("which is ")) query=query.substring(0, query.length()-3)+"has ";
250                    query+="at least "+description.getCardinality()+" "+description.getRole().toString()+" which is ";
251                    description.getChild(0).accept(this);
252            }
253    
254            /* (non-Javadoc)
255             * @see org.dllearner.core.owl.DescriptionVisitor#visit(org.dllearner.core.owl.ObjectExactCardinalityRestriction)
256             */
257            public void visit(ObjectExactCardinalityRestriction description) {
258                    logger.trace("ObjectExactCardinalityRestriction");
259                    if (query.endsWith("which is ")) query=query.substring(0, query.length()-3)+"has ";
260                    query+="exactly "+description.getCardinality()+" "+description.getRole().toString()+" which is ";
261                    description.getChild(0).accept(this);
262            }
263    
264            /* (non-Javadoc)
265             * @see org.dllearner.core.owl.DescriptionVisitor#visit(org.dllearner.core.owl.ObjectMaxCardinalityRestriction)
266             */
267            public void visit(ObjectMaxCardinalityRestriction description) {
268                    logger.trace("ObjectMaxCardinalityRestriction");
269                    if (query.endsWith("which is ")) query=query.substring(0, query.length()-3)+"has ";
270                    query+="at most "+description.getCardinality()+" "+description.getRole().toString()+" which is ";
271                    description.getChild(0).accept(this);           
272            }
273    
274            /* (non-Javadoc)
275             * @see org.dllearner.core.owl.DescriptionVisitor#visit(org.dllearner.core.owl.ObjectValueRestriction)
276             */
277            public void visit(ObjectValueRestriction description) {
278                    ObjectProperty op = (ObjectProperty) description.getRestrictedPropertyExpression();
279                    Individual ind = description.getIndividual();
280                    String label=getLabelFromReasoner(ind);
281                    String indLabel;
282                    if (label.length()>0)
283                            indLabel =label;
284                    else 
285                            indLabel =ind.getName();
286                    label=getLabelFromReasoner(op);
287                    String propLabel;
288                    if (label.length()>0)
289                            propLabel =label;
290                    else 
291                            propLabel =op.getName();                
292                    query += propLabel + " is " + indLabel;
293            }
294    
295            /* (non-Javadoc)
296             * @see org.dllearner.core.owl.DescriptionVisitor#visit(org.dllearner.core.owl.DatatypeValueRestriction)
297             */
298            public void visit(DatatypeValueRestriction description) {
299                    logger.trace("DatatypeValueRestriction");
300                    //if (query.endsWith("which is ")) query=query.substring(0, query.length()-3)+"has ";
301                    query+=description.getRestrictedPropertyExpression().toString()+" has the value "+description.getValue();
302            }
303    
304            /* (non-Javadoc)
305             * @see org.dllearner.core.owl.DescriptionVisitor#visit(org.dllearner.core.owl.NamedClass)
306             */
307            public void visit(NamedClass description) {
308                    
309                    logger.trace("NamedClass");
310                    if (description.getName().equals("http://dbpedia.org/class/yago/Entity100001740")) {
311                            if (query.endsWith("which is ")) query=query.substring(0, query.length()-10);
312                            if (query.endsWith("are ")) query=query.substring(0, query.length()-5);
313                            if (query.endsWith("and ")) query=query.substring(0, query.length()-5);
314                            if (query.endsWith("or ")) query=query.substring(0, query.length()-4);
315                    }
316                    //SortedSet<String> label=tasks.queryAsSet("SELECT ?label WHERE {<"+description.getName()+"> <http://www.w3.org/2000/01/rdf-schema#label> ?label}", "label");
317                    String l=getLabelFromReasoner(description);
318                    String l2=description.getName().substring(description.getName().lastIndexOf("/")+1, description.getName().length()).replace('_', ' ');
319                    if ((l.length()==0)||(l.length()+5<l2.length()&&!l2.matches(".*[0-9]"))) l=l2;
320                    
321                    //replacements
322                    l=l.replaceAll("Cities", "City");
323                    l=l.replaceAll("Players", "Player");
324                    
325                    l=l.replaceAll("([^-\040])([A-Z])([^A-Z])", "$1 $2$3");
326                                    
327                    if (l.toLowerCase().startsWith("a")||l.toLowerCase().startsWith("e")||l.toLowerCase().startsWith("i")||l.toLowerCase().startsWith("o")||l.toLowerCase().startsWith("u")) query+="an "+l;
328                    else query+="a "+l;
329            }
330            
331            
332    
333            /* (non-Javadoc)
334             * @see org.dllearner.core.owl.DescriptionVisitor#visit(org.dllearner.algorithms.gp.ADC)
335             */
336            public void visit(ADC description) {
337                    logger.trace("ADC");
338            }
339    
340            /* (non-Javadoc)
341             * @see org.dllearner.core.owl.DescriptionVisitor#visit(org.dllearner.core.owl.DatatypeMinCardinalityRestriction)
342             */
343            public void visit(DatatypeMinCardinalityRestriction description) {
344                    logger.trace("DatatypeMinCardinalityRestriction");
345            }
346    
347            /* (non-Javadoc)
348             * @see org.dllearner.core.owl.DescriptionVisitor#visit(org.dllearner.core.owl.DatatypeExactCardinalityRestriction)
349             */
350            public void visit(DatatypeExactCardinalityRestriction description) {
351                    logger.trace("DatatypeExactCardinalityRestriction");
352            }
353    
354            /* (non-Javadoc)
355             * @see org.dllearner.core.owl.DescriptionVisitor#visit(org.dllearner.core.owl.DatatypeMaxCardinalityRestriction)
356             */
357            public void visit(DatatypeMaxCardinalityRestriction description) {
358                    logger.trace("DatatypeMaxCardinalityRestriction");
359            }
360    
361            /* (non-Javadoc)
362             * @see org.dllearner.core.owl.DescriptionVisitor#visit(org.dllearner.core.owl.DatatypeSomeRestriction)
363             */
364            public void visit(DatatypeSomeRestriction description) {
365                    logger.trace("DatatypeSomeRestriction");
366            }
367    
368            /* (non-Javadoc)
369             * @see org.dllearner.core.owl.DescriptionVisitor#visit(org.dllearner.core.owl.ObjectOneOf)
370             */
371            @Override
372            public void visit(ObjectOneOf description) {
373                    logger.trace("ObjectOneOf");
374            }
375    }