KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > hp > hpl > jena > n3 > N3toRDF


1 /*
2  * (c) Copyright 2001, 2002, 2003, 2004, 2005 Hewlett-Packard Development Company, LP
3  * [See end of file]
4  */

5
6 package com.hp.hpl.jena.n3;
7
8 import antlr.collections.AST ;
9 import java.util.* ;
10 import com.hp.hpl.jena.rdf.model.* ;
11 import com.hp.hpl.jena.shared.*;
12
13 import com.hp.hpl.jena.vocabulary.*;
14 import org.apache.commons.logging.Log;
15 import org.apache.commons.logging.LogFactory;
16
17 /**
18  * @author Andy Seaborne
19  * @version $Id: N3toRDF.java,v 1.28 2005/02/21 12:04:06 andy_seaborne Exp $
20  */

21 public class N3toRDF implements N3ParserEventHandler
22 {
23     protected static Log logger = LogFactory.getLog( N3toRDF.class );
24     
25     Model model ;
26
27     // Maps URIref or a _:xxx bNode to a Resource
28
Map resourceRef = new HashMap() ;
29     // Maps URIref to Property
30
Map propertyRef = new HashMap() ;
31     
32     // A more liberal prefix mapping map.
33
Map myPrefixMapping = new HashMap() ;
34     
35     boolean allowPropertySymbols = true ;
36     boolean allowKeywordA = true ;
37     
38     // Well known namespaces
39

40     static final String JavaDoc NS_rdf = "http://www.w3.org/1999/02/22-rdf-syntax-ns#" ;
41     static final String JavaDoc NS_rdfs = "http://www.w3.org/2000/01/rdf-schema#" ;
42     
43     static final String JavaDoc NS_W3_log = "http://www.w3.org/2000/10/swap/log#" ;
44     static final String JavaDoc LOG_IMPLIES = NS_W3_log+"implies" ;
45     static final String JavaDoc LOG_MEANS = NS_W3_log+"means" ;
46
47     static final String JavaDoc XMLLiteralURI = "http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral" ;
48
49     private String JavaDoc base = null ;
50     private String JavaDoc basedir = null ;
51     final String JavaDoc anonPrefix = "_" ;
52     
53     N3toRDF() {}
54     
55     public void setBase(String JavaDoc str)
56     {
57         if ( str == null )
58         {
59             base = null ;
60             basedir = null ;
61             return ;
62         }
63         base = str ;
64         if ( base.startsWith("file:"))
65         {
66             int i = base.lastIndexOf('/') ;
67             if ( i >= 0 )
68                 // Include the /
69
basedir = base.substring(0,i+1) ;
70             else
71                 basedir = base ;
72         }
73         else
74             basedir = base ;
75     }
76     
77     public void setModel(Model model)
78     {
79         this.model = model ;
80     }
81     
82     // Need to delay setting the model and base
83
// N3toRDF(Model m, String _base)
84
// {
85
// model = m ; base = _base ;
86
// if ( VERBOSE )
87
// System.out.println("N3toRDF: "+base) ;
88
// }
89

90     
91     public void startDocument() { }
92     public void endDocument() { }
93     
94     // When Jena exceptions are runtime, we will change this
95
public void error(Exception JavaDoc ex, String JavaDoc message) { throw new N3Exception(message) ; }
96     public void error(String JavaDoc message) { error(null, message) ; }
97     
98     public void warning(Exception JavaDoc ex, String JavaDoc message) { logger.warn(message, ex) ; }
99     public void warning(String JavaDoc message) { logger.warn(message) ; }
100     
101     public void deprecated(Exception JavaDoc ex, String JavaDoc message) { throw new N3Exception(message) ; }
102     public void deprecated(String JavaDoc message) { deprecated(null, message) ; }
103     
104     public void startFormula(int line, String JavaDoc context)
105     {
106         error("Line "+line+": N3toRDF: All statements are asserted - no formulae in RDF") ;
107     }
108                     
109     public void endFormula(int line, String JavaDoc context) {}
110     
111     public void directive(int line, AST directive, AST[] args, String JavaDoc context)
112     {
113         if ( directive.getType() == N3Parser.AT_PREFIX )
114         {
115             // @prefix now
116
if ( args[0].getType() != N3Parser.QNAME )
117             {
118                 error("Line "+line+": N3toRDF: Prefix directive does not start with a prefix! "+args[0].getText()+ "["+N3Parser.getTokenNames()[args[0].getType()]+"]") ;
119                 return ;
120             }
121                     
122             String JavaDoc prefix = args[0].getText() ;
123             if ( prefix.endsWith(":") )
124                 prefix = prefix.substring(0,prefix.length()-1) ;
125                 
126             if ( args[1].getType() != N3Parser.URIREF )
127             {
128                 error("Line "+line+": N3toRDF: Prefix directive does not supply a URIref! "+args[1].getText()) ;
129                 return ;
130             }
131             
132             String JavaDoc uriref = args[1].getText() ;
133             uriref = expandURIRef(uriref, line) ;
134             
135             if ( uriref == null )
136                 error("Line "+line+": N3toRDF: Relative URI can't be resolved in in @prefix directive") ;
137                 
138             setPrefixMapping(model, prefix, uriref) ;
139             return ;
140         }
141         
142         warning("Line "+line+": N3toRDF: Directive not recongized and ignored: "+directive.getText()) ;
143         return ;
144     }
145     
146     
147     public void quad(int line, AST subj, AST prop, AST obj, String JavaDoc context)
148     {
149         // Syntax that reverses subject and object is done in the grammar
150

151         if ( context != null )
152             error("Line "+line+": N3toRDF: All statement are asserted - no formulae") ;
153         
154         try
155         {
156             // Converting N3 to RDF:
157
// subject: must be a URIref or a bNode name
158
// property: remove sugaring and then must be a URIref
159
// object: can be a literal or a URIref or a bNode name
160
// context must be zero (no formulae)
161

162             // Lists: The parser creates list elements as sequences of triples:
163
// anon list:first ....
164
// anon list:rest resource
165
// Where "resource" is nil for the last element of the list (generated first).
166

167             // The properties are in a unique namespace to distinguish them
168
// from lists encoded explicitly, not with the () syntax.
169

170             int pType = prop.getType();
171             String JavaDoc propStr = prop.getText();
172             Property pNode = null ;
173             
174             switch (pType)
175             {
176                 case N3Parser.ARROW_R :
177                     if ( ! allowPropertySymbols )
178                         error("Line "+line+": N3toRDF: Propertry symbol '=>' not allowed") ;
179                     propStr = LOG_IMPLIES ;
180                     break;
181                 case N3Parser.ARROW_MEANS :
182                     if ( ! allowPropertySymbols )
183                         error("Line "+line+": N3toRDF: Propertry symbol '<=>' not allowed") ;
184                     propStr = LOG_MEANS ;
185                     break;
186                 case N3Parser.ARROW_L :
187                     if ( ! allowPropertySymbols )
188                         error("Line "+line+": N3toRDF: Propertry symbol '<=' not allowed") ;
189                     // Need to reverse subject and object
190
propStr = LOG_IMPLIES ;
191                     AST tmp = obj; obj = subj; subj = tmp;
192                     break;
193                 case N3Parser.EQUAL :
194                     //propStr = NS_DAML + "equivalentTo";
195
//propStr = damlVocab.equivalentTo().getURI() ;
196
if ( ! allowPropertySymbols )
197                         error("Line "+line+": N3toRDF: Propertry symbol '=' not allowed") ;
198                     pNode = OWL.sameAs ;
199                     break;
200                 case N3Parser.KW_A :
201                     if ( ! allowKeywordA )
202                         error("Line "+line+": N3toRDF: Propertry symbol 'a' not allowed") ;
203                     pNode = RDF.type ;
204                     break ;
205                 case N3Parser.QNAME:
206                     
207                     if ( prop.getText().startsWith("_:") )
208                         error("Line "+line+": N3toRDF: Can't have properties with labelled bNodes in RDF") ;
209                     
210                     String JavaDoc uriref = expandPrefix(model, propStr) ;
211                     if ( uriref == propStr )
212                     {
213                         // Failed to expand ...
214
error("Line "+line+": N3toRDF: Undefined qname namespace: " + propStr);
215                         return ;
216                     }
217                     pNode = model.createProperty(uriref) ;
218                     break ;
219                 case N3Parser.URIREF:
220                     propStr = expandURIRef(propStr, line) ;
221                     break ;
222                 case N3Parser.TK_LIST_FIRST:
223                     pNode = RDF.first ;
224                 break ;
225                 case N3Parser.TK_LIST_REST:
226                     pNode = RDF.rest ;
227                     break ;
228                 // Literals, parser generated bNodes (other bnodes handled as QNAMEs)
229
// and tokens that can't be properties.
230
case N3Parser.ANON:
231                     error("Line "+line+": N3toRDF: Can't have anon. properties in RDF") ;
232                     break ;
233                 default:
234                     error("Line "+line+": N3toRDF: Shouldn't see "+
235                                 N3EventPrinter.formatSlot(prop)+
236                                 " at this point!") ;
237                     break ;
238             }
239
240             // Didn't find an existing one above so make it ...
241
if ( pNode == null )
242                 pNode = model.createProperty(propStr) ;
243             else
244                 propStr = pNode.getURI() ;
245
246             RDFNode sNode = createNode(line, subj);
247             // Must be a resource
248
if ( sNode instanceof Literal )
249                 error("Line "+line+": N3toRDF: Subject can't be a literal: " +subj.getText()) ;
250
251             RDFNode oNode = createNode(line, obj);
252             
253             Statement stmt = model.createStatement((Resource)sNode, pNode, oNode) ;
254             model.add(stmt) ;
255         }
256         catch (JenaException rdfEx)
257         {
258             error("Line "+line+": JenaException: " + rdfEx);
259         }
260     }
261     
262     private Map bNodeMap = new HashMap() ;
263     
264     private RDFNode createNode(int line, AST thing)
265     {
266         //String tokenType = N3AntlrParser._tokenNames[thing.getType()] ;
267
//System.out.println("Token type: "+tokenType) ;
268
String JavaDoc text = thing.getText() ;
269         switch (thing.getType())
270         {
271             case N3Parser.NUMBER :
272                 Resource xsdType = XSD.integer ;
273                 if ( text.indexOf('.') >= 0 )
274                     // The choice of XSD:double is for compatibility with N3/cwm.
275
xsdType = XSD.xdouble ;
276                 if ( text.indexOf('e') >= 0 || text.indexOf('E') >= 0 )
277                     xsdType = XSD.xdouble ;
278                 return model.createTypedLiteral(text, xsdType.getURI());
279                 
280             case N3Parser.LITERAL :
281                 // Literals have three part: value (string), lang tag, datatype
282
// Can't have a lang tag and a data type - if both, just use the datatype
283

284                 AST a1 = thing.getNextSibling() ;
285                 AST a2 = (a1==null?null:a1.getNextSibling()) ;
286                 AST datatype = null ;
287                 AST lang = null ;
288
289                 if ( a2 != null )
290                 {
291                     if ( a2.getType() == N3Parser.DATATYPE )
292                         datatype = a2.getFirstChild() ;
293                     else
294                         lang = a2 ;
295                 }
296                 // First takes precedence over second.
297
if ( a1 != null )
298                 {
299                     if ( a1.getType() == N3Parser.DATATYPE )
300                         datatype = a1.getFirstChild() ;
301                     else
302                         lang = a1 ;
303                 }
304
305                 // Chop leading '@'
306
String JavaDoc langTag = (lang!=null)?lang.getText().substring(1):null ;
307                 
308                 if ( datatype == null )
309                     return model.createLiteral(text, langTag) ;
310                 
311                 // If there is a datatype, it takes predence over lang tag.
312
String JavaDoc typeURI = datatype.getText();
313
314                 if ( datatype.getType() != N3Parser.QNAME &&
315                      datatype.getType() != N3Parser.URIREF )
316                 {
317                     error("Line "+ line+ ": N3toRDF: Must use URIref or QName datatype URI: "
318                             + text+ "^^"+ typeURI+"("+N3Parser.getTokenNames()[datatype.getType()]+")");
319                     return model.createLiteral("Illegal literal: " + text + "^^" + typeURI);
320  
321                 }
322                 
323                 // Can't have bNodes here so the code is slightly different for expansion
324

325                 if ( datatype.getType() == N3Parser.QNAME )
326                 {
327                     if (typeURI.startsWith("_:") || typeURI.startsWith("=:"))
328                     {
329                         error("Line "+ line+ ": N3toRDF: Can't use bNode for datatype URI: "
330                                 + text+ "^^"+ typeURI);
331                         return model.createLiteral("Illegal literal: " + text + "^^" + typeURI);
332                     }
333
334                     String JavaDoc typeURI2 = expandPrefix(model, typeURI) ;
335                     if ( typeURI2 == typeURI )
336                     {
337                         error("Line "+line+": N3toRDF: Undefined qname namespace in datatype: " + typeURI);
338                     }
339                     
340                     typeURI = typeURI2 ;
341                 }
342
343                 typeURI = expandURIRef(typeURI, line);
344                 // 2003-08 - Ignore lang tag when there is an type.
345
return model.createTypedLiteral(text, typeURI) ;
346
347             case N3Parser.QNAME :
348                 // Is it a labelled bNode?
349
// Check if _ has been defined.
350
if ( text.startsWith("_:") && ( model.getNsPrefixURI("_") == null ) )
351                 {
352                     if ( ! bNodeMap.containsKey(text) )
353                         bNodeMap.put(text, model.createResource()) ;
354                     return (Resource)bNodeMap.get(text) ;
355                 }
356             
357                 String JavaDoc uriref = expandPrefix(model, text) ;
358                 if ( uriref == text )
359                 {
360                     error("Line "+line+": N3toRDF: Undefined qname namespace: " + text);
361                     return null ;
362                 }
363                 return model.createResource(expandURIRef(uriref, line)) ;
364
365             // Normal URIref - may be <> or <#>
366
case N3Parser.URIREF :
367                 return model.createResource(expandURIRef(text, line)) ;
368
369             // Lists
370
case N3Parser.TK_LIST_NIL:
371                 return RDF.nil ;
372             case N3Parser.TK_LIST:
373                 return RDF.List ;
374
375             case N3Parser.ANON: // bNodes via [] or [:- ] QNAME starts "=:"
376
if ( ! bNodeMap.containsKey(text) )
377                     bNodeMap.put(text, model.createResource()) ;
378                 return (Resource)bNodeMap.get(text) ;
379
380             case N3Parser.UVAR:
381                 error("Line "+line+": N3toRDF: Can't map variables to RDF: "+text) ;
382                 break ;
383
384             default:
385                 error("Line "+line+": N3toRDF: Can't map to a resource or literal: "+AntlrUtils.ast(thing)) ;
386                 break ;
387         }
388         return null ;
389     }
390
391     // Expand shorthand forms (not QNames) for URIrefs.
392
private String JavaDoc expandURIRef(String JavaDoc text, int line)
393     {
394         // Not a "named" bNode (start with _:)
395
if ( text.equals("") && base == null )
396             error("Line "+line+": N3toRDF: Relative URI but no base for <>") ;
397         
398         if ( text.equals("#") && base == null )
399             error("Line "+line+": N3toRDF: Relative URI but no base for <#>") ;
400         
401         if ( text.equals("") )
402             // The case of <>.
403
return base ;
404         
405         if ( text.equals("#") )
406             // The case of <#>.
407
return base+"#" ;
408         
409         if ( base != null && ! hasURIscheme(text) )
410         {
411             if ( ! base.startsWith("file:"))
412             {
413                 if ( text.startsWith("#"))
414                     return base+text ;
415                 else
416                     return base+"#"+text ;
417             }
418             
419             // File-like things.
420
if ( text.startsWith("#") )
421                 return base + text ;
422             if ( text.startsWith("/") )
423                 return "file:" + text ;
424             else
425                 return basedir + text ;
426         }
427         
428         return text;
429     }
430     
431     private boolean hasURIscheme(String JavaDoc text)
432     {
433         for ( int i = 0 ; i < text.length() ; i++ )
434         {
435             char ch = text.charAt(i) ;
436             if ( ch == ':' )
437                 return true ;
438             if ( ( ch >= 'a' && ch <= 'z' ) ||
439                  ( ch >= 'A' && ch <= 'Z' ) )
440                 continue ;
441             return false ;
442         }
443         return false ;
444     }
445     
446     private void setPrefixMapping(Model m, String JavaDoc prefix, String JavaDoc uriref)
447     {
448         try { model.setNsPrefix(prefix, uriref); }
449         catch (PrefixMapping.IllegalPrefixException ex)
450         {
451             warning("Prefix mapping '" + prefix + "' illegal: used but not recorded in model");
452         }
453         myPrefixMapping.put(prefix, uriref);
454     }
455     
456     private String JavaDoc expandPrefix(Model m, String JavaDoc prefixed)
457     {
458         // Code from shared.impl.PrefixMappingImpl ...
459
// Needed a copy as we store unchecked prefixes for N3.
460
int colon = prefixed.indexOf( ':' );
461         if (colon < 0)
462             return prefixed;
463         else
464         {
465             String JavaDoc prefix = prefixed.substring( 0, colon );
466             String JavaDoc uri = (String JavaDoc) myPrefixMapping.get( prefix );
467             if ( uri == null )
468                 return prefixed ;
469             return uri + prefixed.substring( colon + 1 ) ;
470         }
471         // Not this - model may already have prefixes defined;
472
// we allow "illegal" prefixes (e.g. starts with a number)
473
// for compatibility
474
//return model.expandPrefix(prefix) ;
475
}
476 }
477
478 /*
479  * (c) Copyright 2001, 2002, 2003, 2004, 2005 Hewlett-Packard Development Company, LP
480  * All rights reserved.
481  *
482  * Redistribution and use in source and binary forms, with or without
483  * modification, are permitted provided that the following conditions
484  * are met:
485  * 1. Redistributions of source code must retain the above copyright
486  * notice, this list of conditions and the following disclaimer.
487  * 2. Redistributions in binary form must reproduce the above copyright
488  * notice, this list of conditions and the following disclaimer in the
489  * documentation and/or other materials provided with the distribution.
490  * 3. The name of the author may not be used to endorse or promote products
491  * derived from this software without specific prior written permission.
492  *
493  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
494  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
495  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
496  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
497  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
498  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
499  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
500  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
501  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
502  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
503  */

504
Popular Tags