To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.

Statistics Download as Zip
| Branch: | Revision:

root / onto / tm / doc / specgen.py @ 0:1e44d666ced1

History | View | Annotate | Download (23.1 KB)

1
#!/usr/bin/python
2
# -*- coding: utf8 -*-
3
#
4
# SpecGen v5, ontology specification generator tool
5
# <http://forge.morfeo-project.org/wiki_en/index.php/SpecGen>
6
# 
7
# Copyright (c) 2003-2008 Christopher Schmidt <crschmidt@crschmidt.net>
8
# Copyright (c) 2005-2008 Uldis Bojars <uldis.bojars@deri.org>
9
# Copyright (c) 2007-2008 Sergio Fernández <sergio.fernandez@fundacionctic.org>
10
#
11
# Previous versions of SpecGen:
12
#     v1,2,3 by Christopher Schmidt <http://crschmidt.net/semweb/redland>
13
#     v4 by Uldis Bojars <http://sioc-project.org/specgen>
14
# 
15
# This software is licensed under the terms of the MIT License.
16
# 
17
# Permission is hereby granted, free of charge, to any person obtaining a copy
18
# of this software and associated documentation files (the "Software"), to deal
19
# in the Software without restriction, including without limitation the rights
20
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
21
# copies of the Software, and to permit persons to whom the Software is
22
# furnished to do so, subject to the following conditions:
23
# 
24
# The above copyright notice and this permission notice shall be included in
25
# all copies or substantial portions of the Software.
26
# 
27
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
28
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
30
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
31
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
32
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
33
# THE SOFTWARE.
34

    
35
__version__ = "5.4.2"
36
__authors__ = "Christopher Schmidt, Uldis Bojars, Sergio Fernández"
37
__license__ = "MIT License <http://www.opensource.org/licenses/mit-license.php>"
38
__contact__ = "specgen-devel@lists.morfeo-project.org"
39
__date__    = "2008-12-02"
40
 
41
import os
42
import sys
43
import time
44
import re
45
import urllib
46

    
47
try:
48
    import RDF
49
except ImportError:
50
    version = sys.version.split(" ")[0]
51
    if version.startswith("2.5"):
52
        sys.path.append("/usr/lib/python2.4/site-packages/")
53
    else:
54
        sys.path.append("/usr/lib/python2.5/site-packages/")
55
    try:
56
        import RDF
57
    except:
58
        sys.exit("Error importing RedLand bindings for Python; check if it is installed correctly")
59

    
60
#global vars
61
classranges = {}
62
classdomains = {}
63
spec_url = None
64
spec_ns = None
65
spec_pre = None
66
ns_list = { "http://www.w3.org/1999/02/22-rdf-syntax-ns#"   : "rdf",
67
            "http://www.w3.org/2000/01/rdf-schema#"         : "rdfs",
68
            "http://www.w3.org/2002/07/owl#"                : "owl",
69
            "http://www.w3.org/2001/XMLSchema#"             : "xsd",
70
            "http://rdfs.org/sioc/ns#"                      : "sioc",
71
            "http://xmlns.com/foaf/0.1/"                    : "foaf", 
72
            "http://purl.org/dc/elements/1.1/"              : "dc",
73
            "http://purl.org/dc/terms/"                     : "dct",
74
            "http://usefulinc.com/ns/doap#"                 : "doap",
75
            "http://www.w3.org/2003/06/sw-vocab-status/ns#" : "status",
76
            "http://purl.org/rss/1.0/modules/content/"      : "content", 
77
            "http://www.w3.org/2003/01/geo/wgs84_pos#"      : "geo",
78
            "http://www.w3.org/2004/02/skos/core#"          : "skos"
79
          }
80

    
81
rdf = RDF.NS('http://www.w3.org/1999/02/22-rdf-syntax-ns#')
82
rdfs = RDF.NS('http://www.w3.org/2000/01/rdf-schema#')
83
owl = RDF.NS('http://www.w3.org/2002/07/owl#')
84
vs = RDF.NS('http://www.w3.org/2003/06/sw-vocab-status/ns#')
85

    
86
termdir = './doc' #TODO
87

    
88

    
89
def niceName(uri):
90
    regexp = re.compile( "^(.*[/#])([^/#]+)$" )
91
    rez = regexp.search( uri )
92
    pref = rez.group(1)
93
    #return ns_list.get(pref, pref) + ":" + rez.group(2)
94
    if ns_list.has_key(pref):
95
        return ns_list.get(pref, pref) + ":" + rez.group(2)
96
    else:
97
        return uri
98

    
99

    
100
def setTermDir(directory):
101
    global termdir
102
    termdir = directory
103

    
104

    
105
def termlink(string):
106
    """FOAF specific: function which replaces <code>foaf:*</code> with a 
107
    link to the term in the document."""
108
    return re.sub(r"<code>" + spec_pre + r":(\w+)</code>", r"""<code><a href="#term_\1">""" + spec_pre + r""":\1</a></code>""", string)    
109

    
110

    
111
def return_name(m, urinode):
112
    "Trims the FOAF namespace out of a term to give a name to the term."
113
    return str(urinode.uri).replace(spec_url, "")
114

    
115

    
116
def get_rdfs(m, urinode):
117
    "Returns label and comment given an RDF.Node with a URI in it"
118
    comment = ''
119
    label = ''
120
    if (type(urinode)==str):
121
        urinode = RDF.Uri(urinode)
122
    l = m.find_statements(RDF.Statement(urinode, rdfs.label, None))
123
    if l.current():
124
        label = l.current().object.literal_value['string']
125
    c = m.find_statements(RDF.Statement(urinode, rdfs.comment, None))
126
    if c.current():
127
        comment = c.current().object.literal_value['string']
128
    return label, comment
129

    
130

    
131
def get_status(m, urinode):
132
    "Returns the status text for a term."
133
    status = ''
134
    s = m.find_statements(RDF.Statement(urinode, vs.term_status, None))
135
    if s.current():
136
        return s.current().object.literal_value['string']
137

    
138

    
139
def htmlDocInfo( t ):
140
    """Opens a file based on the term name (t) and termdir directory (global).
141
       Reads in the file, and returns a linkified version of it."""
142
    doc = ""
143
    try:
144
        f = open("%s/%s.en" % (termdir, t), "r")
145
        doc = f.read()
146
        doc = termlink(doc)
147
    except:
148
        return ""         # "<p>No detailed documentation for this term.</p>"
149
    return doc
150

    
151

    
152
def owlVersionInfo(m):
153
    v = m.find_statements(RDF.Statement(None, owl.versionInfo, None))
154
    if v.current():
155
        return v.current().object.literal_value['string']
156
    else:
157
        return ""
158

    
159

    
160
def rdfsPropertyInfo(term,m):
161
    """Generate HTML for properties: Domain, range, status."""
162
    global classranges
163
    global classdomains
164
    doc = ""
165
    range = ""
166
    domain = ""
167

    
168
    #find subPropertyOf information
169
    o = m.find_statements( RDF.Statement(term, rdfs.subPropertyOf, None) )
170
    if o.current():
171
        rlist = ''
172
        for st in o:
173
            k = getTermLink(str(st.object.uri))
174
            rlist += "<dd>%s</dd>" % k
175
        doc += "<dt>sub-property-of:</dt> %s" % rlist
176

    
177
    #domain stuff
178
    domains = m.find_statements(RDF.Statement(term, rdfs.domain, None))
179
    domainsdoc = ""
180
    for d in domains:
181
        collection = m.find_statements(RDF.Statement(d.object, owl.unionOf, None))
182
        if collection.current():
183
            uris = parseCollection(m, collection)
184
            for uri in uris:
185
                domainsdoc += "<dd>%s</dd>" % getTermLink(uri)
186
                add(classdomains, uri, term.uri)
187
        else:
188
            if not d.object.is_blank():
189
                domainsdoc += "<dd>%s</dd>" % getTermLink(str(d.object.uri))
190
    if (len(domainsdoc)>0):
191
        doc += "<dt>Domain:</dt> %s" % domainsdoc
192

    
193
    #range stuff
194
    ranges = m.find_statements(RDF.Statement(term, rdfs.range, None))
195
    rangesdoc = ""
196
    for r in ranges:
197
        collection = m.find_statements(RDF.Statement(r.object, owl.unionOf, None))
198
        if collection.current():
199
            uris = parseCollection(m, collection)
200
            for uri in uris:
201
                rangesdoc += "<dd>%s</dd>" % getTermLink(uri)
202
                add(classranges, uri, term.uri)
203
        else:
204
            if not r.object.is_blank():
205
                rangesdoc += "<dd>%s</dd>" % getTermLink(str(r.object.uri))
206
    if (len(rangesdoc)>0):
207
        doc += "<dt>Range:</dt> %s" % rangesdoc
208

    
209
    return doc
210

    
211

    
212
def parseCollection(model, collection):
213
    # #propertyA a rdf:Property ;
214
    #   rdfs:domain [
215
    #      a owl:Class ;
216
    #      owl:unionOf [
217
    #        rdf:parseType Collection ;
218
    #        #Foo a owl:Class ;
219
    #        #Bar a owl:Class
220
    #     ]
221
    #   ]
222
    # 
223
    # seeAlso "Collections in RDF"
224

    
225
    uris = []
226

    
227
    rdflist = model.find_statements(RDF.Statement(collection.current().object, None, None))
228
    while rdflist and rdflist.current() and not rdflist.current().object.is_blank():
229
        one = rdflist.current()
230
        if not one.object.is_blank():
231
            uris.append(str(one.object.uri))
232
        rdflist.next()
233
        one = rdflist.current()
234
        if one.predicate == rdf.rest:
235
            rdflist = model.find_statements(RDF.Statement(one.object, None, None))
236
    
237
    return uris
238

    
239

    
240
def getTermLink(uri):
241
    uri = str(uri)
242
    if (uri.startswith(spec_url)):
243
        return '<a href="#term_%s" style="font-family: monospace;">%s</a>' % (uri.replace(spec_url, ""), niceName(uri))
244
    else:
245
        return '<a href="%s" style="font-family: monospace;">%s</a>' % (uri, niceName(uri))
246

    
247

    
248
def rdfsClassInfo(term,m):
249
    """Generate rdfs-type information for Classes: ranges, and domains."""
250
    global classranges
251
    global classdomains
252
    doc = ""
253

    
254
    #patch to control incoming strings (FIXME, why??? drop it!)
255
    try:
256
        term.uri
257
    except:
258
        term = RDF.Node(RDF.Uri(term))
259

    
260
    # Find subClassOf information
261
    o = m.find_statements( RDF.Statement(term, rdfs.subClassOf, None) )
262
    if o.current():
263
        doc += "<dt>sub-class-of:</dt>"
264
        superclasses = []
265
        for st in o:
266
            if not st.object.is_blank():
267
                uri = str(st.object.uri)
268
                if (not uri in superclasses):
269
                    superclasses.append(uri)
270
        for superclass in superclasses:
271
            doc += "<dd>%s</dd>" % getTermLink(superclass)
272

    
273
    # Find out about properties which have rdfs:domain of t
274
    d = classdomains.get(str(term.uri), "")
275
    if d:
276
        dlist = ''
277
        for k in d:
278
            dlist += "<dd>%s</dd>" % getTermLink(k)
279
        doc += "<dt>in-domain-of:</dt>" + dlist
280

    
281
    # Find out about properties which have rdfs:range of t
282
    r = classranges.get(str(term.uri), "")
283
    if r:
284
        rlist = ''
285
        for k in r:
286
            rlist += "<dd>%s</dd>" % getTermLink(k)
287
        doc += "<dt>in-range-of:</dt>" + rlist
288

    
289
    return doc
290

    
291
def rdfsInstanceInfo(term,m):
292
    """Generate rdfs-type information for instances"""
293
    doc = ""
294
    
295
    t = m.find_statements( RDF.Statement(RDF.Node(RDF.Uri(term)), rdf.type, None) )
296
    if t.current():
297
        doc += "<dt>RDF Type:</dt>"
298
    while t.current():
299
        doc += "<dd>%s</dd>" % getTermLink(str(t.current().object.uri))
300
        t.next()
301

    
302
    return doc
303

    
304

    
305
def owlInfo(term,m):
306
    """Returns an extra information that is defined about a term (an RDF.Node()) using OWL."""
307
    res = ''
308

    
309
    # FIXME: refactor this code
310
    
311
    # Inverse properties ( owl:inverseOf )
312
    o = m.find_statements( RDF.Statement(term, owl.inverseOf, None) )
313
    if o.current():
314
        res += "<dt>Inverse:</dt>"
315
        for st in o:
316
            res += "<dd>%s</dd>" % getTermLink(str(st.object.uri))
317
    
318
    # Datatype Property ( owl.DatatypeProperty )
319
    o = m.find_statements( RDF.Statement(term, rdf.type, owl.DatatypeProperty) )
320
    if o.current():
321
        res += "<dt>OWL Type:</dt><dd>DatatypeProperty</dd>\n"
322
        
323
    # Object Property ( owl.ObjectProperty )
324
    o = m.find_statements( RDF.Statement(term, rdf.type, owl.ObjectProperty) )
325
    if o.current():
326
        res += "<dt>OWL Type:</dt><dd>ObjectProperty</dd>\n"
327

    
328
    # Annotation Property ( owl.AnnotationProperty )
329
    o = m.find_statements( RDF.Statement(term, rdf.type, owl.AnnotationProperty) )
330
    if o.current():
331
        res += "<dt>OWL Type:</dt><dd>AnnotationProperty</dd>\n"
332

    
333
    # IFPs ( owl.InverseFunctionalProperty )
334
    o = m.find_statements( RDF.Statement(term, rdf.type, owl.InverseFunctionalProperty) )
335
    if o.current():
336
        res += "<dt>OWL Type:</dt><dd>InverseFunctionalProperty (uniquely identifying property)</dd>\n"
337

    
338
    # Symmertic Property ( owl.SymmetricProperty )
339
    o = m.find_statements( RDF.Statement(term, rdf.type, owl.SymmetricProperty) )
340
    if o.current():
341
        res += "<dt>OWL Type:</dt><dd>SymmetricProperty</dd>\n"
342
        
343
    return res
344

    
345

    
346
def docTerms(category, list, m):
347
    """
348
    A wrapper class for listing all the terms in a specific class (either
349
    Properties, or Classes. Category is 'Property' or 'Class', list is a 
350
    list of term names (strings), return value is a chunk of HTML.
351
    """
352
    doc = ""
353
    nspre = spec_pre
354
    for t in list:
355
        if (t.startswith(spec_url)) and (len(t[len(spec_url):].split("/"))<2):
356
            term = t
357
            t = t.split(spec_url[-1])[-1]
358
            curie = t#"%s:%s" % (nspre, t)
359
        else:
360
            if t.startswith("http://"):
361
                term = t
362
                curie = getShortName(t)
363
                t = getAnchor(t)
364
            else:
365
                term = spec_ns[t]
366
                curie = "%s:%s" % (nspre, t)
367
        
368
        doc += """<div class="specterm" id="term_%s">\n<h3>%s: %s</h3>\n""" % (t, category, curie)
369
        try:
370
            term_uri = term.uri
371
        except:
372
            term_uri = term
373
        doc += """<p style="font-family:monospace; font-size:0.em;">URI: <a href="%s">%s</a></p>""" % (term_uri, term_uri)
374
        label, comment = get_rdfs(m, term)    
375
        status = get_status(m, term)
376
        doc += "<p><em>%s</em> - %s </p>" % (label, comment)
377
        terminfo = ""
378
        if category=='Property':
379
            terminfo += owlInfo(term,m)
380
            terminfo += rdfsPropertyInfo(term,m)
381
        if category=='Class':
382
            terminfo += rdfsClassInfo(term,m)
383
        if category=='Instance':
384
            terminfo += rdfsInstanceInfo(term,m)
385
        if (len(terminfo)>0): #to prevent empty list (bug #882)
386
            doc += "\n<dl>%s</dl>\n" % terminfo 
387
        doc += htmlDocInfo(t)
388
        doc += "<p style=\"float: right; font-size: small;\">[<a href=\"#sec-glance\">back to top</a>]</p>\n\n"
389
        doc += "\n\n</div>\n\n"
390
    
391
    return doc
392

    
393

    
394
def getShortName(uri):
395
    if ("#" in uri):
396
        return uri.split("#")[-1]
397
    else:
398
        return uri.split("/")[-1]
399

    
400

    
401
def getAnchor(uri):
402
    if (uri.startswith(spec_url)):
403
        return uri[len(spec_url):].replace("/","_")
404
    else:
405
        return getShortName(uri)
406

    
407

    
408
def buildazlist(classlist, proplist, instalist=None):
409
    """
410
    Builds the A-Z list of terms. Args are a list of classes (strings) and 
411
    a list of props (strings)
412
    """
413
    azlist = '<div style="padding: 1em; border: dotted; background-color: #ddd;">'
414

    
415
    if (len(classlist)>0):
416
        azlist += "<p>Classes: "
417
        classlist.sort()
418
        for c in classlist:
419
            if c.startswith(spec_url):
420
                c = c.split(spec_url[-1])[1]
421
            azlist = """%s <a href="#term_%s">%s</a>, """ % (azlist, c, c)
422
        azlist = """%s\n</p>""" % azlist
423

    
424
    if (len(proplist)>0):
425
        azlist += "<p>Properties: "
426
        proplist.sort()
427
        for p in proplist:
428
            if p.startswith(spec_url):
429
                p = p.split(spec_url[-1])[1]
430
            azlist = """%s <a href="#term_%s">%s</a>, """ % (azlist, p, p)
431
        azlist = """%s\n</p>""" % azlist
432

    
433
    if (instalist!=None and len(instalist)>0):
434
        azlist += "<p>Instances: "
435
        for i in instalist:
436
            p = getShortName(i)
437
            anchor = getAnchor(i)
438
            azlist = """%s <a href="#term_%s">%s</a>, """ % (azlist, anchor, p)
439
        azlist = """%s\n</p>""" % azlist
440

    
441
    azlist = """%s\n</div>""" % azlist
442
    return azlist
443

    
444

    
445
def build_simple_list(classlist, proplist, instalist=None):
446
    """
447
    Builds a simple <ul> A-Z list of terms. Args are a list of classes (strings) and 
448
    a list of props (strings)
449
    """
450

    
451
    azlist = """<div style="padding: 5px; border: dotted; background-color: #ddd;">"""
452
    azlist = """%s\n<p>Classes:""" % azlist
453
    azlist += """\n<ul>"""
454

    
455
    classlist.sort()
456
    for c in classlist:
457
        azlist += """\n  <li><a href="#term_%s">%s</a></li>""" % (c.replace(" ", ""), c)
458
    azlist = """%s\n</ul></p>""" % azlist
459

    
460
    azlist = """%s\n<p>Properties:""" % azlist
461
    azlist += """\n<ul>"""
462
    proplist.sort()
463
    for p in proplist:
464
        azlist += """\n  <li><a href="#term_%s">%s</a></li>""" % (p.replace(" ", ""), p)
465
    azlist = """%s\n</ul></p>""" % azlist
466

    
467
    #FIXME: instances
468

    
469
    azlist = """%s\n</div>""" % azlist
470
    return azlist
471

    
472

    
473
def add(where, key, value):
474
    if not where.has_key(key):
475
        where[key] = []
476
    if not value in where[key]:
477
        where[key].append(value)
478

    
479

    
480
def specInformation(m, ns):
481
    """
482
    Read through the spec (provided as a Redland model) and return classlist
483
    and proplist. Global variables classranges and classdomains are also filled
484
    as appropriate.
485
    """
486
    global classranges
487
    global classdomains
488

    
489
    # Find the class information: Ranges, domains, and list of all names.
490
    classtypes = [rdfs.Class, owl.Class]
491
    classlist = []
492
    for onetype in classtypes:
493
        for classStatement in  m.find_statements(RDF.Statement(None, rdf.type, onetype)):
494
            for range in m.find_statements(RDF.Statement(None, rdfs.range, classStatement.subject)):
495
                if not m.contains_statement( RDF.Statement( range.subject, rdf.type, owl.DeprecatedProperty )):
496
                    if not classStatement.subject.is_blank():
497
                        add(classranges, str(classStatement.subject.uri), str(range.subject.uri))
498
            for domain in m.find_statements(RDF.Statement(None, rdfs.domain, classStatement.subject)):
499
                if not m.contains_statement( RDF.Statement( domain.subject, rdf.type, owl.DeprecatedProperty )):
500
                    if not classStatement.subject.is_blank():
501
                        add(classdomains, str(classStatement.subject.uri), str(domain.subject.uri))
502
            if not classStatement.subject.is_blank():
503
                uri = str(classStatement.subject.uri)
504
                name = return_name(m, classStatement.subject)
505
                if name not in classlist and uri.startswith(spec_url):
506
                    classlist.append(return_name(m, classStatement.subject))
507

    
508
    # Create a list of properties in the schema.
509
    proptypes = [rdf.Property, owl.ObjectProperty, owl.DatatypeProperty, owl.AnnotationProperty]
510
    proplist = []
511
    for onetype in proptypes: 
512
        for propertyStatement in m.find_statements(RDF.Statement(None, rdf.type, onetype)):
513
            uri = str(propertyStatement.subject.uri)
514
            name = return_name(m, propertyStatement.subject)
515
            if uri.startswith(ns) and not name in proplist:
516
                proplist.append(name)
517

    
518
    return classlist, proplist
519

    
520
def getInstances(model, classes, properties):
521
    """
522
    Extract all resources instanced in the ontology
523
    (aka "everything that is not a class or a property")
524
    """
525
    instances = []
526
    for one in classes:
527
        for i in model.find_statements(RDF.Statement(None, rdf.type, spec_ns[one])):
528
            uri = str(i.subject.uri)
529
            if not uri in instances:
530
                instances.append(uri)
531
    for i in model.find_statements(RDF.Statement(None, rdfs.isDefinedBy, RDF.Uri(spec_url))):            
532
            uri = str(i.subject.uri)
533
            if (uri.startswith(spec_url)):
534
                uri = uri[len(spec_url):]
535
            if ((not uri in instances) and (not uri in classes)):
536
                instances.append(uri)
537
    return instances
538
   
539
 
540
def specgen(specloc, template, instances=False, mode="spec"):
541
    """The meat and potatoes: Everything starts here."""
542

    
543
    global spec_url
544
    global spec_ns
545
    global ns_list
546
        
547
    m = RDF.Model()
548
    p = RDF.Parser()
549
    try:
550
        p.parse_into_model(m, specloc)
551
    except IOError, e:
552
        print "Error reading from ontology:", str(e)
553
        usage()
554
    except RDF.RedlandError, e:
555
        print "Error parsing the ontology"
556

    
557
    spec_url = getOntologyNS(m)
558
    spec_ns = RDF.NS(spec_url)
559
    ns_list[spec_url] = spec_pre
560

    
561
    classlist, proplist = specInformation(m, spec_url)
562
    classlist = sorted(classlist)
563
    proplist = sorted(proplist)
564

    
565
    instalist = None
566
    if instances:
567
        instalist = getInstances(m, classlist, proplist)
568
        instalist.sort(lambda x, y: cmp(getShortName(x).lower(), getShortName(y).lower()))
569
    
570
    if mode == "spec":
571
        # Build HTML list of terms.
572
        azlist = buildazlist(classlist, proplist, instalist)
573
    elif mode == "list":
574
        # Build simple <ul> list of terms.
575
        azlist = build_simple_list(classlist, proplist, instalist)
576

    
577
    # Generate Term HTML
578
    termlist = docTerms('Property', proplist, m)
579
    termlist = docTerms('Class', classlist, m) + termlist
580
    if instances:
581
        termlist += docTerms('Instance', instalist, m)
582
    
583
    # Generate RDF from original namespace.
584
    u = urllib.urlopen(specloc)
585
    rdfdata = u.read()
586
    rdfdata = re.sub(r"(<\?xml version.*\?>)", "", rdfdata)
587
    rdfdata = re.sub(r"(<!DOCTYPE[^]]*]>)", "", rdfdata)
588
    #rdfdata.replace("""<?xml version="1.0"?>""", "")
589
    
590
    # print template % (azlist.encode("utf-8"), termlist.encode("utf-8"), rdfdata.encode("ISO-8859-1"))
591
    template = re.sub(r"^#format \w*\n", "", template)
592
    template = re.sub(r"\$VersionInfo\$", owlVersionInfo(m).encode("utf-8"), template) 
593
    
594
    # NOTE: This works with the assumtpion that all "%" in the template are escaped to "%%" and it
595
    #       contains the same number of "%s" as the number of parameters in % ( ...parameters here... )
596
    template = template % (azlist, termlist.encode("utf-8"));    
597
    template += "<!-- specification regenerated by SpecGen5 at " + time.strftime('%X %x %Z') + " -->"
598
    
599
    return template
600

    
601

    
602
def save(path, text):
603
    try:
604
        f = open(path, "w")
605
        f.write(text)
606
        f.flush()
607
        f.close()
608
    except Exception, e:
609
        print "Error writting in file \"" + path + "\": " + str(e)
610

    
611

    
612
def getOntologyNS(m):
613
    ns = None
614
    o = m.find_statements(RDF.Statement(None, rdf.type, owl.Ontology))
615
    if o.current():
616
        s = o.current().subject
617
        if (not s.is_blank()):
618
            ns = str(s.uri)
619
            if (ns[-1]!="/" and ns[-1]!="#"):
620
                ns += "#"
621

    
622
    if (ns == None):
623
        sys.exit("Impossible to get ontology's namespace")
624
    else:
625
        return ns
626

    
627

    
628
def __getScriptPath():
629
    path = sys.argv[0]
630
    if path.startswith("./"):
631
        return path
632
    else:
633
        base = "/".join(path.split("/")[:-1])
634
        for one in os.environ["PATH"].split(":"):
635
            if base == one:
636
                return path.split("/")[-1]
637
        return path
638

    
639

    
640
def usage():
641
    script = __getScriptPath()
642
    print """Usage: 
643
    %s ontology prefix template destination [flags]
644

645
        ontology    : path to ontology file
646
        prefix      : prefix for CURIEs
647
        template    : HTML template path
648
        destination : specification destination (by default)
649

650
        optional flags:
651
                -i   : add instances on the specification (disabled by default)
652

653
examples:
654
    %s example.owl ex template.html example.owl.html -i
655

656
""" % (script, script)
657
    sys.exit(-1)
658

    
659
if __name__ == "__main__":
660
    """Ontology specification generator tool"""
661
    
662
    args = sys.argv[1:]
663
    if (len(args) < 4):
664
        usage()
665
    else:
666
        
667
        #ontology
668
        specloc = "file:" + str(args[0])
669
        spec_pre = args[1]
670

    
671
        #template
672
        temploc = args[2]
673
        template = None
674
        try:
675
            f = open(temploc, "r")
676
            template = f.read()
677
        except Exception, e:
678
            print "Error reading from template \"" + temploc + "\": " + str(e)
679
            usage()
680

    
681
        #destination
682
        dest = args[3]
683
 
684
        #flags
685
        instances = False
686
        if len(args) > 3:
687
            flags = args[3:]
688
            if '-i' in flags:
689
                instances = True
690
        
691
        save(dest, specgen(specloc, template, instances=instances))
692