001: /*
002: * LICENSE INFORMATION
003: * Copyright (c) 2003 - 2007 Leo Sauermann and Deutsches Forschungszentrum fuer Kuenstliche Intelligenz DFKI GmbH.
004: * All rights reserved.
005: * Copyright 2005-2007 by FZI (http://www.fzi.de).
006: * Licensed under a BSD license (http://www.opensource.org/licenses/bsd-license.php)
007: * <OWNER> = Max Völkel
008: * <ORGANIZATION> = FZI Forschungszentrum Informatik Karlsruhe, Karlsruhe, Germany
009: * <YEAR> = 2007
010: *
011: * Project information at http://semweb4j.org/rdf2go
012: */
013:
014: package org.ontoware.rdf2go.util;
015:
016: import java.io.StringReader;
017: import java.io.StringWriter;
018: import java.security.MessageDigest;
019: import java.security.NoSuchAlgorithmException;
020: import java.text.DateFormat;
021: import java.text.ParseException;
022: import java.text.SimpleDateFormat;
023: import java.util.Date;
024:
025: import org.ontoware.aifbcommons.collection.ClosableIterator;
026: import org.ontoware.rdf2go.RDF2Go;
027: import org.ontoware.rdf2go.exception.ModelRuntimeException;
028: import org.ontoware.rdf2go.model.Model;
029: import org.ontoware.rdf2go.model.ModelSet;
030: import org.ontoware.rdf2go.model.Statement;
031: import org.ontoware.rdf2go.model.Syntax;
032: import org.ontoware.rdf2go.model.node.Literal;
033: import org.ontoware.rdf2go.model.node.Node;
034: import org.ontoware.rdf2go.model.node.NodeOrVariable;
035: import org.ontoware.rdf2go.model.node.Resource;
036: import org.ontoware.rdf2go.model.node.ResourceOrVariable;
037: import org.ontoware.rdf2go.model.node.URI;
038: import org.ontoware.rdf2go.model.node.UriOrVariable;
039: import org.ontoware.rdf2go.model.node.Variable;
040: import org.ontoware.rdf2go.vocabulary.RDFS;
041: import org.slf4j.Logger;
042: import org.slf4j.LoggerFactory;
043:
044: /**
045: * RDFTool, a helper utility to cope with RDF in general.
046: *
047: * The accessor methods are also handled by the RDFReactor runtime.
048: *
049: * <p>
050: * This tool has been part of gnowsis.org.
051: * </p>
052: *
053: * @author Leo Sauermann (leo@gnowsis.com), 2003-2007
054: * @author Max Völkel
055: */
056: public class RDFTool {
057:
058: @SuppressWarnings("unused")
059: private static Logger log = LoggerFactory.getLogger(RDFTool.class);
060:
061: /**
062: * datetime format.
063: */
064: private static DateFormat dateTimeFormat = null;
065:
066: /**
067: * format to express dates in ISO 8601
068: */
069: private static DateFormat dateFormat = null;
070:
071: /**
072: * @param m
073: * the model to copy
074: * @return a copy of the model in a memory model
075: */
076: public static Model copyModel(Model m) {
077: Model res = RDF2Go.getModelFactory().createModel();
078: res.open();
079: res.addAll(m.iterator());
080: return res;
081: }
082:
083: /**
084: * format the given date in a good date format: ISO 8601, using only the
085: * date and not the T seperator example: 2003-01-22 Timezone is ignored.
086: *
087: * @param date
088: * @return a formatted string.
089: * @deprecated use {@link #date2String(Date)}
090: */
091: public static String dateTime2DateString(Date date) {
092: return getDateTimeFormat().format(date);
093: }
094:
095: /**
096: * format the given date in a good dateTime format: ISO 8601, using the T
097: * seperator and the - and : seperators accordingly. example:
098: * 2003-01-22T17:00:00
099: *
100: * @param date
101: * @return a formatted string.
102: */
103: public static String dateTime2String(Date date) {
104: return getDateTimeFormat().format(date);
105: }
106:
107: /**
108: * format the given date in a good date format: ISO 8601, using only the
109: * date and not the T seperator example: 2003-01-22 Timezone is ignored.
110: *
111: * @param date
112: * @return a formatted string.
113: */
114: public static String date2String(Date date) {
115: return getDateFormat().format(date);
116: }
117:
118: /**
119: * find the first statement that fits the passed triple pattern and return
120: * it.
121: *
122: * @param model
123: * the model to search on
124: * @param subject
125: * subject
126: * @param predicate
127: * predicate
128: * @param object
129: * object
130: * @return a statement (the first found) or null, if nothing matched
131: * @throws RuntimeException
132: * if the model throws an exception
133: */
134: public static Statement findStatement(Model model,
135: ResourceOrVariable subject, UriOrVariable predicate,
136: NodeOrVariable object) {
137: ClosableIterator<? extends Statement> i = model.findStatements(
138: subject, predicate, object);
139: if (i.hasNext()) {
140: Statement s = i.next();
141: i.close();
142: return s;
143: }
144: // else
145: return null;
146: }
147:
148: /**
149: * format to express dates in ISO 8601. Timezone is ignored.
150: *
151: * @return the DateFormat to format dates (without time) according to
152: * ISO8601.
153: */
154: public static DateFormat getDateFormat() {
155: if (dateFormat == null) {
156: dateFormat = new SimpleDateFormat("yyyy-MM-dd");
157: }
158: return dateFormat;
159: }
160:
161: /**
162: * get a DateFormat to format dates according to ISO 8601. This ignored
163: * timezones.
164: *
165: * @return a dateformat.
166: */
167: public static DateFormat getDateTimeFormat() {
168: if (dateTimeFormat == null) {
169: dateTimeFormat = new SimpleDateFormat(
170: "yyyy-MM-dd'T'HH:mm:ss");
171: }
172: return dateTimeFormat;
173: }
174:
175: /**
176: * Get the Displaylabel of a Node. For resources, the "rdfs:label" property
177: * is returned, if there is none, the url is shortened to a localname. If it
178: * is a Literal, return the Lexical Form. If it is null, returns null
179: * Results may vary.
180: *
181: * @param o
182: * the node to check
183: * @param source
184: * the model to ask
185: * @return a string representation of the node or null.
186: */
187: public static String getGoodLabel(Node o, Model source) {
188: if (o == null)
189: return null;
190: if (o instanceof Resource) {
191: // resource
192: Node rdfslabel = RDFTool.getSingleValue(source,
193: (Resource) o, RDFS.label);
194: if (rdfslabel != null) {
195: if (rdfslabel instanceof Literal)
196: return ((Literal) rdfslabel).getValue();
197: // else
198: return rdfslabel.toString();
199: }
200: // else
201: return RDFTool.getShortName(o.toString());
202: } else if (o instanceof Literal)
203: return ((Literal) o).getValue();
204: else
205: // else ? well, just string it
206: return o.toString();
207: }
208:
209: /**
210: * Get the label of a Node. If it is a resource, return the local name (the
211: * last part of the URI). If it is a Literal, return the Lexical Form (the
212: * value). If it is <code>null</code>, returns <code>null</code>.
213: *
214: * @param o
215: * the node to check
216: * @return a string representation of the node or <code>null</code>.
217: */
218: public static String getLabel(Node o) {
219: if (o == null)
220: return null;
221: if (o instanceof Resource) {
222: // resource
223: return getShortName(o.toString());
224: } else if (o instanceof Literal)
225: // Literal
226: return ((Literal) o).getValue();
227: // else ? well, just string it
228: return o.toString();
229: }
230:
231: /**
232: * The passed uri identifies something on the web, probably a namespace. To
233: * shorten this, parse the url for something like a localname. Returns the
234: * last string after a '#' or a '/'.
235: *
236: * @param uri
237: * a URI
238: * @return a short name for it, for display.
239: */
240: public static String getShortName(String uri) {
241: if (uri.indexOf('#') > 0)
242: uri = uri.substring(uri.lastIndexOf('#') + 1);
243: else if (uri.indexOf('/') > 0)
244: uri = uri.substring(uri.lastIndexOf('/') + 1);
245: return uri;
246: }
247:
248: /**
249: * get the property pred of the resource res. If there is none, return null.
250: * If there are mutliple, return any.
251: *
252: * @param m
253: * the model to read from
254: * @param res
255: * the resource
256: * @param pred
257: * the predicate to read
258: * @return the value or null
259: */
260: public static Node getSingleValue(Model m, Resource res, URI pred) {
261: ClosableIterator<? extends Statement> i = m.findStatements(res,
262: pred, Variable.ANY);
263: try {
264: if (i.hasNext()) {
265: return i.next().getObject();
266: }
267: //else
268: return null;
269: } finally {
270: i.close();
271: }
272: }
273:
274: public static Node getSingleValue(ModelSet m, Resource res, URI pred) {
275: ClosableIterator<? extends Statement> i = m.findStatements(
276: Variable.ANY, res, pred, Variable.ANY);
277: try {
278: if (i.hasNext()) {
279: return i.next().getObject();
280: }
281: //else
282: return null;
283: } finally {
284: i.close();
285: }
286: }
287:
288: /**
289: * read the values of a predicate of a resource. If a value exists, return a
290: * string representation of it. When multiple triples with this
291: * subject/predicate exist, choose one at random.
292: *
293: * @param m
294: * the model to read from
295: * @param res
296: * the resource
297: * @param pred
298: * the predicate to read
299: * @return a string representation of the value, or null. Literals are
300: * returned using their Value (not toString()).
301: */
302: public static String getSingleValueString(Model m, Resource res,
303: URI pred) {
304: Node n = getSingleValue(m, res, pred);
305: if (n == null)
306: return null;
307:
308: if (n instanceof Literal)
309: // Literal
310: return ((Literal) n).getValue();
311: return n.toString();
312: }
313:
314: /**
315: * read the values of a predicate of a resource. If a value exists, return a
316: * string representation of it. When multiple triples with this
317: * subject/predicate exist, choose one at random.
318: *
319: * @param modelset
320: * the model to read from
321: * @param res
322: * the resource
323: * @param pred
324: * the predicate to read
325: * @return a string representation of the value, or null. Literals are
326: * returned using their Value (not toString()).
327: */
328: public static String getSingleValueString(ModelSet modelset,
329: Resource res, URI pred) {
330: Node n = getSingleValue(modelset, res, pred);
331: if (n == null)
332: return null;
333:
334: if (n instanceof Literal)
335: // Literal
336: return ((Literal) n).getValue();
337: return n.toString();
338: }
339:
340: /**
341: * guess the RDF syntax of a filename inspired by
342: * com.hp.hpl.jena.graph.impl.FileGraph#guessLang with the addition of
343: * toLowerCase
344: *
345: * @param filenname
346: * the filename, we will look at the suffix after "."
347: * @return the guessed RDF syntax, fallback is RDF/XML
348: */
349: public static Syntax guessSyntax(String filenname) {
350: String suffix = filenname
351: .substring(filenname.lastIndexOf('.') + 1);
352: if (suffix != null) {
353: suffix = suffix.toLowerCase();
354:
355: if (suffix.equals("n3"))
356: return Syntax.Turtle;
357: else if (suffix.equals("nt"))
358: return Syntax.Ntriples;
359: else if (suffix.equals("trig")) {
360: return Syntax.Trig;
361: } else if (suffix.equals("trix"))
362: return Syntax.Trix;
363: }
364: return Syntax.RdfXml;
365: }
366:
367: /**
368: * convert a model to a string RDF/XML for serialization
369: *
370: * @param model
371: * the model to convert
372: * @return
373: */
374: public static String modelToString(Model model) {
375: return modelToString(model, Syntax.RdfXml);
376: }
377:
378: public static String modelToString(ModelSet modelset) {
379: return modelToString(modelset, Syntax.RdfXml);
380: }
381:
382: /**
383: * convert a model to a string for serialization
384: *
385: * @param model
386: * the model to convert
387: * @param syntax
388: * the syntax to use
389: * @return a string of this model, according to the passed syntax
390: */
391: public static String modelToString(Model model, Syntax syntax) {
392: StringWriter buffer = new StringWriter();
393: try {
394: model.writeTo(buffer, syntax);
395: } catch (Exception e) {
396: throw new ModelRuntimeException(e);
397: }
398: return buffer.toString();
399: }
400:
401: /**
402: * convert a modelset to a string for serialization
403: *
404: * @param modelset
405: * the model to convert
406: * @param syntax
407: * the syntax to use
408: * @return a string of this model, according to the passed syntax
409: */
410: public static String modelToString(ModelSet modelset, Syntax syntax) {
411: StringWriter buffer = new StringWriter();
412: try {
413: modelset.writeTo(buffer, syntax);
414: } catch (Exception e) {
415: throw new ModelRuntimeException(e);
416: }
417: return buffer.toString();
418: }
419:
420: /**
421: * set the property pred of the resource res. If it exists, change it. If it
422: * not exists, create it. If the passed value is null, delete the statement
423: *
424: * @param m
425: * the model to manipulate
426: * @param res
427: * the rsource
428: * @param pred
429: * the predicate to set
430: * @param value
431: * a value or null
432: */
433: public static void setSingleValue(Model m, Resource res, URI pred,
434: Node value) {
435: m.removeStatements(res, pred, Variable.ANY);
436: if (value != null) {
437: m.addStatement(res, pred, value);
438: }
439: }
440:
441: /**
442: * set the property pred of the resource res. If it exists, change it. If it
443: * not exists, create it. If value is null, delete the triple.
444: *
445: * @param m
446: * the model to manipulate
447: * @param res
448: * the rsource
449: * @param pred
450: * the predicate to set
451: * @param value
452: * a string or null
453: */
454: public static void setSingleValue(Model m, Resource res, URI pred,
455: String value) {
456: m.removeStatements(res, pred, Variable.ANY);
457: if (value != null) {
458: m.addStatement(res, pred, value);
459: }
460: }
461:
462: /**
463: * compute the sha1sum of a string (useful for handling FOAF data).
464: *
465: * @param data
466: * the string to parse
467: * @return the sha1sum as string.
468: */
469: public static String sha1sum(String data) {
470: MessageDigest md = null;
471: try {
472: md = MessageDigest.getInstance("SHA");
473: } catch (NoSuchAlgorithmException e) {
474: throw new RuntimeException(e);
475: }
476:
477: byte[] digest = md.digest(data.getBytes());
478:
479: StringBuffer res = new StringBuffer();
480: for (int i = 0; i < digest.length; i++) {
481: int digByte = digest[i] & 0xFF;
482: if (digByte < 0x10)
483: res.append('0');
484: res.append(Integer.toHexString(digByte));
485: }
486:
487: return res.toString();
488: }
489:
490: /**
491: * try to get a date out of a string. If this works, return it, otherwise
492: * return null. Btw: the namespace of dateTime is
493: * http://www.w3.org/2001/XMLSchema#dateTime Timezone is ignored.
494: *
495: * @param isodate
496: * the XSD date as string.
497: * @return a parsed date or null, if this breaks
498: * @throws ParseException
499: */
500: public static Date string2Date(String isodate)
501: throws ParseException {
502: return getDateFormat().parse(isodate);
503: }
504:
505: /**
506: * format the given date in a good date format: ISO 8601, using only the
507: * date and not the T seperator example: 2003-01-22 This ignores timezones.
508: *
509: * @param date
510: * the date-string to parse
511: * @return a formatted string.
512: */
513: public static Date string2DateTime(String date)
514: throws ParseException {
515: return getDateTimeFormat().parse(date);
516: }
517:
518: /**
519: * convenience function to create a memModel from an RDF/XML-ABBREV stream
520: *
521: * @param rdfxml
522: * the serialized form of the model
523: * @return a Model
524: */
525: public static Model stringToModel(String rdfxml) {
526: return stringToModel(rdfxml, Syntax.RdfXml);
527: }
528:
529: /**
530: * convenience function to create a memModel from a string
531: *
532: * @param string
533: * the string with the serialized model
534: * @param syntax
535: * the syntax to use
536: * @return the model that was serialised.
537: */
538: public static Model stringToModel(String string, Syntax syntax) {
539: Model m = RDF2Go.getModelFactory().createModel();
540: m.open();
541: StringReader s = new StringReader(string);
542: try {
543: m.readFrom(s, syntax);
544: return m;
545: } catch (Exception e) {
546: throw new ModelRuntimeException(e);
547: } finally {
548: s.close();
549: }
550: }
551: }
|