diff options
Diffstat (limited to 'lv2specgen')
| -rw-r--r-- | lv2specgen/DTD/xhtml-datatypes-1.mod.1 | 103 | ||||
| -rw-r--r-- | lv2specgen/DTD/xhtml-metaAttributes-1.mod | 154 | ||||
| -rw-r--r-- | lv2specgen/DTD/xhtml-rdfa-1.dtd | 472 | ||||
| -rw-r--r-- | lv2specgen/DTD/xhtml-rdfa-model-1.mod | 249 | ||||
| -rwxr-xr-x | lv2specgen/lv2docgen.py | 17 | ||||
| -rwxr-xr-x | lv2specgen/lv2specgen.py | 1666 | ||||
| -rw-r--r-- | lv2specgen/template.html | 136 |
7 files changed, 2120 insertions, 677 deletions
diff --git a/lv2specgen/DTD/xhtml-datatypes-1.mod.1 b/lv2specgen/DTD/xhtml-datatypes-1.mod.1 new file mode 100644 index 0000000..dde43e8 --- /dev/null +++ b/lv2specgen/DTD/xhtml-datatypes-1.mod.1 @@ -0,0 +1,103 @@ +<!-- ...................................................................... --> +<!-- XHTML Datatypes Module .............................................. --> +<!-- file: xhtml-datatypes-1.mod + + This is XHTML, a reformulation of HTML as a modular XML application. + Copyright 1998-2005 W3C (MIT, ERCIM, Keio), All Rights Reserved. + Revision: $Id: xhtml-datatypes-1.mod,v 4.1 2001/04/06 19:23:32 altheim Exp $ SMI + + This DTD module is identified by the PUBLIC and SYSTEM identifiers: + + PUBLIC "-//W3C//ENTITIES XHTML Datatypes 1.0//EN" + SYSTEM "http://www.w3.org/MarkUp/DTD/xhtml-datatypes-1.mod" + + Revisions: + (none) + ....................................................................... --> + +<!-- Datatypes + + defines containers for the following datatypes, many of + these imported from other specifications and standards. +--> + +<!-- Length defined for cellpadding/cellspacing --> + +<!-- nn for pixels or nn% for percentage length --> +<!ENTITY % Length.datatype "CDATA" > + +<!-- space-separated list of link types --> +<!ENTITY % LinkTypes.datatype "NMTOKENS" > + +<!-- single or comma-separated list of media descriptors --> +<!ENTITY % MediaDesc.datatype "CDATA" > + +<!-- pixel, percentage, or relative --> +<!ENTITY % MultiLength.datatype "CDATA" > + +<!-- one or more digits (NUMBER) --> +<!ENTITY % Number.datatype "CDATA" > + +<!-- integer representing length in pixels --> +<!ENTITY % Pixels.datatype "CDATA" > + +<!-- script expression --> +<!ENTITY % Script.datatype "CDATA" > + +<!-- textual content --> +<!ENTITY % Text.datatype "CDATA" > + +<!-- Placeholder Compact URI-related types --> +<!ENTITY % CURIE.datatype "CDATA" > +<!ENTITY % CURIEs.datatype "CDATA" > +<!ENTITY % SafeCURIE.datatype "CDATA" > +<!ENTITY % SafeCURIEs.datatype "CDATA" > +<!ENTITY % URIorSafeCURIE.datatype "CDATA" > +<!ENTITY % URIorSafeCURIEs.datatype "CDATA" > + +<!-- Imported Datatypes ................................ --> + +<!-- a single character from [ISO10646] --> +<!ENTITY % Character.datatype "CDATA" > + +<!-- a character encoding, as per [RFC2045] --> +<!ENTITY % Charset.datatype "CDATA" > + +<!-- a space separated list of character encodings, as per [RFC2045] --> +<!ENTITY % Charsets.datatype "CDATA" > + +<!-- Color specification using color name or sRGB (#RRGGBB) values --> +<!ENTITY % Color.datatype "CDATA" > + +<!-- media type, as per [RFC2045] --> +<!ENTITY % ContentType.datatype "CDATA" > + +<!-- comma-separated list of media types, as per [RFC2045] --> +<!ENTITY % ContentTypes.datatype "CDATA" > + +<!-- date and time information. ISO date format --> +<!ENTITY % Datetime.datatype "CDATA" > + +<!-- formal public identifier, as per [ISO8879] --> +<!ENTITY % FPI.datatype "CDATA" > + +<!-- a language code, as per [RFC3066] or its successor --> +<!ENTITY % LanguageCode.datatype "CDATA" > + +<!-- a comma separated list of language code ranges --> +<!ENTITY % LanguageCodes.datatype "CDATA" > + +<!-- a qualified name , as per [XMLNS] or its successor --> +<!ENTITY % QName.datatype "CDATA" > +<!ENTITY % QNames.datatype "CDATA" > + +<!-- a Uniform Resource Identifier, see [URI] --> +<!ENTITY % URI.datatype "CDATA" > + +<!-- a space-separated list of Uniform Resource Identifiers, see [URI] --> +<!ENTITY % URIs.datatype "CDATA" > + +<!-- a relative URI reference consisting of an initial '#' and a fragment ID --> +<!ENTITY % URIREF.datatype "CDATA" > + +<!-- end of xhtml-datatypes-1.mod --> diff --git a/lv2specgen/DTD/xhtml-metaAttributes-1.mod b/lv2specgen/DTD/xhtml-metaAttributes-1.mod new file mode 100644 index 0000000..b434e39 --- /dev/null +++ b/lv2specgen/DTD/xhtml-metaAttributes-1.mod @@ -0,0 +1,154 @@ +<!-- ...................................................................... --> +<!-- XHTML MetaAttributes Module ......................................... --> +<!-- file: xhtml-metaAttributes-1.mod + + This is XHTML-RDFa, modules to annotate XHTML family documents. + Copyright 2007-2008 W3C (MIT, ERCIM, Keio), All Rights Reserved. + Revision: $Id: xhtml-metaAttributes-1.mod,v 1.6 2008/08/01 20:01:00 smccarro Exp $ + + This DTD module is identified by the PUBLIC and SYSTEM identifiers: + + PUBLIC "-//W3C//ENTITIES XHTML MetaAttributes 1.0//EN" + SYSTEM "http://www.w3.org/MarkUp/DTD/xhtml-metaAttributes-1.mod" + + Revisions: + (none) + ....................................................................... --> + +<!ENTITY % XHTML.global.attrs.prefixed "IGNORE" > + +<!-- Placeholder Compact URI-related types --> +<!ENTITY % CURIE.datatype "CDATA" > +<!ENTITY % CURIEs.datatype "CDATA" > +<!ENTITY % SafeCURIE.datatype "CDATA" > +<!ENTITY % SafeCURIEs.datatype "CDATA" > +<!ENTITY % URIorSafeCURIE.datatype "CDATA" > +<!ENTITY % URIorSafeCURIEs.datatype "CDATA" > + +<!-- Common Attributes + + This module declares a collection of meta-information related + attributes. + + %NS.decl.attrib; is declared in the XHTML Qname module. + + This file also includes declarations of "global" versions of the + attributes. The global versions of the attributes are for use on + elements in other namespaces. +--> + +<!ENTITY % about.attrib + "about %URIorSafeCURIE.datatype; #IMPLIED" +> + +<![%XHTML.global.attrs.prefixed;[ +<!ENTITY % XHTML.global.about.attrib + "%XHTML.prefix;:about %URIorSafeCURIE.datatype; #IMPLIED" +> +]]> + +<!ENTITY % typeof.attrib + "typeof %CURIEs.datatype; #IMPLIED" +> + +<![%XHTML.global.attrs.prefixed;[ +<!ENTITY % XHTML.global.typeof.attrib + "%XHTML.prefix;:typeof %CURIEs.datatype; #IMPLIED" +> +]]> + +<!ENTITY % property.attrib + "property %CURIEs.datatype; #IMPLIED" +> + +<![%XHTML.global.attrs.prefixed;[ +<!ENTITY % XHTML.global.property.attrib + "%XHTML.prefix;:property %CURIEs.datatype; #IMPLIED" +> +]]> + +<!ENTITY % resource.attrib + "resource %URIorSafeCURIE.datatype; #IMPLIED" +> + +<![%XHTML.global.attrs.prefixed;[ +<!ENTITY % XHTML.global.resource.attrib + "%XHTML.prefix;:resource %URIorSafeCURIE.datatype; #IMPLIED" +> +]]> + +<!ENTITY % content.attrib + "content CDATA #IMPLIED" +> + +<![%XHTML.global.attrs.prefixed;[ +<!ENTITY % XHTML.global.content.attrib + "%XHTML.prefix;:content CDATA #IMPLIED" +> +]]> + +<!ENTITY % datatype.attrib + "datatype %CURIE.datatype; #IMPLIED" +> + +<![%XHTML.global.attrs.prefixed;[ +<!ENTITY % XHTML.global.datatype.attrib + "%XHTML.prefix;:datatype %CURIE.datatype; #IMPLIED" +> +]]> + +<!ENTITY % rel.attrib + "rel %CURIEs.datatype; #IMPLIED" +> + +<![%XHTML.global.attrs.prefixed;[ +<!ENTITY % XHTML.global.rel.attrib + "%XHTML.prefix;:rel %CURIEs.datatype; #IMPLIED" +> +]]> + +<!ENTITY % rev.attrib + "rev %CURIEs.datatype; #IMPLIED" +> + +<![%XHTML.global.attrs.prefixed;[ +<!ENTITY % XHTML.global.rev.attrib + "%XHTML.prefix;:rev %CURIEs.datatype; #IMPLIED" +> +]]> + +<!ENTITY % Metainformation.extra.attrib "" > + +<!ENTITY % Metainformation.attrib + "%about.attrib; + %content.attrib; + %datatype.attrib; + %typeof.attrib; + %property.attrib; + %rel.attrib; + %resource.attrib; + %rev.attrib; + %Metainformation.extra.attrib;" +> + +<!ENTITY % XHTML.global.metainformation.extra.attrib "" > + +<![%XHTML.global.attrs.prefixed;[ + +<!ENTITY % XHTML.global.metainformation.attrib + "%XHTML.global.about.attrib; + %XHTML.global.content.attrib; + %XHTML.global.datatype.attrib; + %XHTML.global.typeof.attrib; + %XHTML.global.property.attrib; + %XHTML.global.rel.attrib; + %XHTML.global.resource.attrib; + %XHTML.global.rev.attrib; + %XHTML.global.metainformation.extra.attrib;" +> +]]> + +<!ENTITY % XHTML.global.metainformation.attrib "" > + + +<!-- end of xhtml-metaAttributes-1.mod --> diff --git a/lv2specgen/DTD/xhtml-rdfa-1.dtd b/lv2specgen/DTD/xhtml-rdfa-1.dtd new file mode 100644 index 0000000..26ed117 --- /dev/null +++ b/lv2specgen/DTD/xhtml-rdfa-1.dtd @@ -0,0 +1,472 @@ +<!-- ....................................................................... --> +<!-- XHTML 1.1 + RDFa DTD ................................................. --> +<!-- file: xhtml-rdfa-1.dtd +--> + +<!-- XHTML 1.1 + RDFa DTD + + This is an example markup language combining XHTML 1.1 and the RDFa + modules. + + XHTML+RDFa + Copyright 1998-2008 World Wide Web Consortium + (Massachusetts Institute of Technology, European Research Consortium + for Informatics and Mathematics, Keio University). + All Rights Reserved. + + Permission to use, copy, modify and distribute the XHTML DTD and its + accompanying documentation for any purpose and without fee is hereby + granted in perpetuity, provided that the above copyright notice and + this paragraph appear in all copies. The copyright holders make no + representation about the suitability of the DTD for any purpose. + + It is provided "as is" without expressed or implied warranty. + +--> +<!-- This is the driver file for version 1 of the XHTML + RDFa DTD. + + Please use this public identifier to identify it: + + "-//W3C//DTD XHTML+RDFa 1.0//EN" +--> +<!ENTITY % XHTML.version "XHTML+RDFa 1.0" > + +<!-- Use this URI to identify the default namespace: + + "http://www.w3.org/1999/xhtml" + + See the Qualified Names module for information + on the use of namespace prefixes in the DTD. + + Note that XHTML namespace elements are not prefixed by default, + but the XHTML namespace prefix is defined as "xhtml" so that + other markup languages can extend this one and use the XHTML + prefixed global attributes if required. + +--> +<!ENTITY % NS.prefixed "IGNORE" > +<!ENTITY % XHTML.prefix "xhtml" > + +<!-- Be sure to include prefixed global attributes - we don't need + them, but languages that extend XHTML 1.1 might. +--> +<!ENTITY % XHTML.global.attrs.prefixed "INCLUDE" > + +<!-- Reserved for use with the XLink namespace: +--> +<!ENTITY % XLINK.xmlns "" > +<!ENTITY % XLINK.xmlns.attrib "" > + +<!-- For example, if you are using XHTML 1.1 directly, use the public + identifier in the DOCTYPE declaration, with the namespace declaration + on the document element to identify the default namespace: + + <?xml version="1.0"?> + <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML+RDFa 1.0//EN" + "xhtml-rdfa-1.dtd"> + <html xmlns="http://www.w3.org/1999/xhtml" + xml:lang="en"> + ... + </html> + + Revisions: + (none) +--> + +<!-- reserved for future use with document profiles --> +<!ENTITY % XHTML.profile "" > + +<!-- ensure XHTML Notations are disabled --> +<!ENTITY % xhtml-notations.module "IGNORE" > + +<!-- Bidirectional Text features + This feature-test entity is used to declare elements + and attributes used for bidirectional text support. +--> +<!ENTITY % XHTML.bidi "INCLUDE" > + +<!-- ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: --> + +<!-- Pre-Framework Redeclaration placeholder .................... --> +<!-- this serves as a location to insert markup declarations + into the DTD prior to the framework declarations. +--> +<!ENTITY % xhtml-prefw-redecl.module "IGNORE" > +<!ENTITY % xhtml-prefw-redecl.mod "" > +<![%xhtml-prefw-redecl.module;[ +%xhtml-prefw-redecl.mod; +<!-- end of xhtml-prefw-redecl.module -->]]> + +<!-- we need the datatypes now --> +<!ENTITY % xhtml-datatypes.module "INCLUDE" > +<![%xhtml-datatypes.module;[ +<!ENTITY % xhtml-datatypes.mod + PUBLIC "-//W3C//ENTITIES XHTML Datatypes 1.0//EN" + "xhtml-datatypes-1.mod" > +%xhtml-datatypes.mod;]]> + +<!-- bring in the RDFa attributes cause we need them in Common --> +<!ENTITY % xhtml-metaAttributes.module "INCLUDE" > +<![%xhtml-metaAttributes.module;[ +<!ENTITY % xhtml-metaAttributes.mod + PUBLIC "-//W3C//ENTITIES XHTML MetaAttributes 1.0//EN" + "xhtml-metaAttributes-1.mod" > +%xhtml-metaAttributes.mod;]]> + +<!ENTITY % xhtml-events.module "INCLUDE" > + +<!ENTITY % Common.extra.attrib + "href %URI.datatype; #IMPLIED + %Metainformation.attrib;" +> +<!-- adding the lang attribute into the I18N collection --> + +<!ENTITY % lang.attrib + "xml:lang %LanguageCode.datatype; #IMPLIED + lang %LanguageCode.datatype; #IMPLIED" +> + +<!-- Inline Style Module ........................................ --> +<!ENTITY % xhtml-inlstyle.module "INCLUDE" > +<![%xhtml-inlstyle.module;[ +<!ENTITY % xhtml-inlstyle.mod + PUBLIC "-//W3C//ELEMENTS XHTML Inline Style 1.0//EN" + "xhtml-inlstyle-1.mod" > +%xhtml-inlstyle.mod;]]> + +<!-- declare Document Model module instantiated in framework +--> +<!ENTITY % xhtml-model.mod + PUBLIC "-//W3C//ENTITIES XHTML+RDFa Document Model 1.0//EN" + "xhtml-rdfa-model-1.mod" > + +<!-- Modular Framework Module (required) ......................... --> +<!ENTITY % xhtml-framework.module "INCLUDE" > +<![%xhtml-framework.module;[ +<!ENTITY % xhtml-framework.mod + PUBLIC "-//W3C//ENTITIES XHTML Modular Framework 1.0//EN" + "xhtml-framework-1.mod" > +%xhtml-framework.mod;]]> + +<!-- Post-Framework Redeclaration placeholder ................... --> +<!-- this serves as a location to insert markup declarations + into the DTD following the framework declarations. +--> +<!ENTITY % xhtml-postfw-redecl.module "IGNORE" > +<!ENTITY % xhtml-postfw-redecl.mod ""> +<![%xhtml-postfw-redecl.module;[ +%xhtml-postfw-redecl.mod; +<!-- end of xhtml-postfw-redecl.module -->]]> + + + +<!-- Text Module (Required) ..................................... --> +<!ENTITY % xhtml-text.module "INCLUDE" > +<![%xhtml-text.module;[ +<!ENTITY % xhtml-text.mod + PUBLIC "-//W3C//ELEMENTS XHTML Text 1.0//EN" + "xhtml-text-1.mod" > +%xhtml-text.mod;]]> + +<!-- Hypertext Module (required) ................................. --> +<!ENTITY % a.attlist "IGNORE" > +<!ENTITY % xhtml-hypertext.module "INCLUDE" > +<![%xhtml-hypertext.module;[ +<!ENTITY % xhtml-hypertext.mod + PUBLIC "-//W3C//ELEMENTS XHTML Hypertext 1.0//EN" + "xhtml-hypertext-1.mod" > +%xhtml-hypertext.mod;]]> +<!ATTLIST %a.qname; + %Common.attrib; + charset %Charset.datatype; #IMPLIED + type %ContentType.datatype; #IMPLIED + hreflang %LanguageCode.datatype; #IMPLIED + accesskey %Character.datatype; #IMPLIED + tabindex %Number.datatype; #IMPLIED +> + +<!-- Lists Module (required) .................................... --> +<!ENTITY % xhtml-list.module "INCLUDE" > +<![%xhtml-list.module;[ +<!ENTITY % xhtml-list.mod + PUBLIC "-//W3C//ELEMENTS XHTML Lists 1.0//EN" + "xhtml-list-1.mod" > +%xhtml-list.mod;]]> + +<!-- ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: --> + +<!-- Edit Module ................................................ --> +<!ENTITY % xhtml-edit.module "INCLUDE" > +<![%xhtml-edit.module;[ +<!ENTITY % xhtml-edit.mod + PUBLIC "-//W3C//ELEMENTS XHTML Editing Elements 1.0//EN" + "xhtml-edit-1.mod" > +%xhtml-edit.mod;]]> + +<!-- BIDI Override Module ....................................... --> +<!ENTITY % xhtml-bdo.module "%XHTML.bidi;" > +<![%xhtml-bdo.module;[ +<!ENTITY % xhtml-bdo.mod + PUBLIC "-//W3C//ELEMENTS XHTML BIDI Override Element 1.0//EN" + "xhtml-bdo-1.mod" > +%xhtml-bdo.mod;]]> + +<!-- Ruby Module ................................................ --> +<!ENTITY % Ruby.common.attlists "INCLUDE" > +<!ENTITY % Ruby.common.attrib "%Common.attrib;" > +<!ENTITY % xhtml-ruby.module "INCLUDE" > +<![%xhtml-ruby.module;[ +<!ENTITY % xhtml-ruby.mod + PUBLIC "-//W3C//ELEMENTS XHTML Ruby 1.0//EN" + "http://www.w3.org/TR/ruby/xhtml-ruby-1.mod" > +%xhtml-ruby.mod;]]> + +<!-- Presentation Module ........................................ --> +<!ENTITY % xhtml-pres.module "INCLUDE" > +<![%xhtml-pres.module;[ +<!ENTITY % xhtml-pres.mod + PUBLIC "-//W3C//ELEMENTS XHTML Presentation 1.0//EN" + "xhtml-pres-1.mod" > +%xhtml-pres.mod;]]> + +<!ENTITY % link.attlist "IGNORE" > +<!-- Link Element Module ........................................ --> +<!ENTITY % xhtml-link.module "INCLUDE" > +<![%xhtml-link.module;[ +<!ENTITY % xhtml-link.mod + PUBLIC "-//W3C//ELEMENTS XHTML Link Element 1.0//EN" + "xhtml-link-1.mod" > +%xhtml-link.mod;]]> + +<!ATTLIST %link.qname; + %Common.attrib; + charset %Charset.datatype; #IMPLIED + hreflang %LanguageCode.datatype; #IMPLIED + type %ContentType.datatype; #IMPLIED + media %MediaDesc.datatype; #IMPLIED +> + +<!-- Document Metainformation Module ............................ --> +<!ENTITY % meta.attlist "IGNORE" > +<!ENTITY % xhtml-meta.module "INCLUDE" > +<![%xhtml-meta.module;[ +<!ENTITY % xhtml-meta.mod + PUBLIC "-//W3C//ELEMENTS XHTML Metainformation 1.0//EN" + "xhtml-meta-1.mod" > +%xhtml-meta.mod;]]> +<!ATTLIST %meta.qname; + %Common.attrib; + http-equiv NMTOKEN #IMPLIED + name NMTOKEN #IMPLIED + scheme CDATA #IMPLIED +> + +<!-- Base Element Module ........................................ --> +<!ENTITY % xhtml-base.module "INCLUDE" > +<![%xhtml-base.module;[ +<!ENTITY % xhtml-base.mod + PUBLIC "-//W3C//ELEMENTS XHTML Base Element 1.0//EN" + "xhtml-base-1.mod" > +%xhtml-base.mod;]]> + +<!-- Scripting Module ........................................... --> +<!ENTITY % script.attlist "IGNORE" > +<!ENTITY % xhtml-script.module "INCLUDE" > +<![%xhtml-script.module;[ +<!ENTITY % xhtml-script.mod + PUBLIC "-//W3C//ELEMENTS XHTML Scripting 1.0//EN" + "xhtml-script-1.mod" > +%xhtml-script.mod;]]> + +<!ATTLIST %script.qname; + %XHTML.xmlns.attrib; + %id.attrib; + %Metainformation.attrib; + href %URI.datatype; #IMPLIED + xml:space ( preserve ) #FIXED 'preserve' + charset %Charset.datatype; #IMPLIED + type %ContentType.datatype; #REQUIRED + src %URI.datatype; #IMPLIED + defer ( defer ) #IMPLIED +> + +<!-- Style Sheets Module ......................................... --> +<!ENTITY % style.attlist "IGNORE" > +<!ENTITY % xhtml-style.module "INCLUDE" > +<![%xhtml-style.module;[ +<!ENTITY % xhtml-style.mod + PUBLIC "-//W3C//ELEMENTS XHTML Style Sheets 1.0//EN" + "xhtml-style-1.mod" > +%xhtml-style.mod;]]> +<!ATTLIST %style.qname; + %XHTML.xmlns.attrib; + %id.attrib; + %title.attrib; + %I18n.attrib; + %Metainformation.attrib; + href %URI.datatype; #IMPLIED + xml:space ( preserve ) #FIXED 'preserve' + type %ContentType.datatype; #REQUIRED + media %MediaDesc.datatype; #IMPLIED +> + +<!-- Image Module ............................................... --> +<!ENTITY % xhtml-image.module "INCLUDE" > +<![%xhtml-image.module;[ +<!ENTITY % xhtml-image.mod + PUBLIC "-//W3C//ELEMENTS XHTML Images 1.0//EN" + "xhtml-image-1.mod" > +%xhtml-image.mod;]]> + +<!-- Client-side Image Map Module ............................... --> +<!ENTITY % area.attlist "IGNORE" > + +<!ENTITY % xhtml-csismap.module "INCLUDE" > +<![%xhtml-csismap.module;[ +<!ENTITY % xhtml-csismap.mod + PUBLIC "-//W3C//ELEMENTS XHTML Client-side Image Maps 1.0//EN" + "xhtml-csismap-1.mod" > +%xhtml-csismap.mod;]]> + +<!ATTLIST %area.qname; + %Common.attrib; + shape %Shape.datatype; 'rect' + coords %Coords.datatype; #IMPLIED + nohref ( nohref ) #IMPLIED + alt %Text.datatype; #REQUIRED + tabindex %Number.datatype; #IMPLIED + accesskey %Character.datatype; #IMPLIED +> + +<!-- Server-side Image Map Module ............................... --> +<!ENTITY % xhtml-ssismap.module "INCLUDE" > +<![%xhtml-ssismap.module;[ +<!ENTITY % xhtml-ssismap.mod + PUBLIC "-//W3C//ELEMENTS XHTML Server-side Image Maps 1.0//EN" + "xhtml-ssismap-1.mod" > +%xhtml-ssismap.mod;]]> + +<!-- Param Element Module ....................................... --> +<!ENTITY % param.attlist "IGNORE" > +<!ENTITY % xhtml-param.module "INCLUDE" > +<![%xhtml-param.module;[ +<!ENTITY % xhtml-param.mod + PUBLIC "-//W3C//ELEMENTS XHTML Param Element 1.0//EN" + "xhtml-param-1.mod" > +%xhtml-param.mod;]]> + +<!ATTLIST %param.qname; + %XHTML.xmlns.attrib; + %id.attrib; + %Metainformation.attrib; + href %URI.datatype; #IMPLIED + name CDATA #REQUIRED + value CDATA #IMPLIED + valuetype ( data | ref | object ) 'data' + type %ContentType.datatype; #IMPLIED +> +<!-- Embedded Object Module ..................................... --> +<!ENTITY % xhtml-object.module "INCLUDE" > +<![%xhtml-object.module;[ +<!ENTITY % xhtml-object.mod + PUBLIC "-//W3C//ELEMENTS XHTML Embedded Object 1.0//EN" + "xhtml-object-1.mod" > +%xhtml-object.mod;]]> + +<!-- Tables Module ............................................... --> +<!ENTITY % xhtml-table.module "INCLUDE" > +<![%xhtml-table.module;[ +<!ENTITY % xhtml-table.mod + PUBLIC "-//W3C//ELEMENTS XHTML Tables 1.0//EN" + "xhtml-table-1.mod" > +%xhtml-table.mod;]]> + +<!-- Forms Module ............................................... --> +<!ENTITY % xhtml-form.module "INCLUDE" > +<![%xhtml-form.module;[ +<!ENTITY % xhtml-form.mod + PUBLIC "-//W3C//ELEMENTS XHTML Forms 1.0//EN" + "xhtml-form-1.mod" > +%xhtml-form.mod;]]> + +<!-- Target Attribute Module .................................... --> +<!ENTITY % xhtml-target.module "INCLUDE" > +<![%xhtml-target.module;[ +<!ENTITY % xhtml-target.mod + PUBLIC "-//W3C//ELEMENTS XHTML Target 1.0//EN" + "xhtml-target-1.mod" > +%xhtml-target.mod;]]> + +<!-- Legacy Markup ............................................... --> +<!ENTITY % xhtml-legacy.module "IGNORE" > +<![%xhtml-legacy.module;[ +<!ENTITY % xhtml-legacy.mod + PUBLIC "-//W3C//ELEMENTS XHTML Legacy Markup 1.0//EN" + "xhtml-legacy-1.mod" > +%xhtml-legacy.mod;]]> + +<!-- Document Structure Module (required) ....................... --> +<!ENTITY % html.attlist "IGNORE" > +<!ENTITY % head.attlist "IGNORE" > +<!ENTITY % title.attlist "IGNORE" > +<!ENTITY % xhtml-struct.module "INCLUDE" > +<![%xhtml-struct.module;[ +<!ENTITY % xhtml-struct.mod + PUBLIC "-//W3C//ELEMENTS XHTML Document Structure 1.0//EN" + "xhtml-struct-1.mod" > +%xhtml-struct.mod;]]> +<!ENTITY % profile.attrib + "profile %URI.datatype; '%XHTML.profile;'" +> +<!ENTITY % XHTML.version.attrib + "version %FPI.datatype; #FIXED '%XHTML.version;'" +> +<!ATTLIST %html.qname; + %Common.attrib; + %XSI.schemaLocation.attrib; + %XHTML.version.attrib; +> +<!ATTLIST %head.qname; + %Common.attrib; + %profile.attrib; +> +<!ATTLIST %title.qname; + %Common.attrib; +> + +<!-- end of XHTML-RDFa DTD ................................................ --> +<!-- ....................................................................... --> + +<!-- Add xmlns attributes to validate lv2specgen output --> +<!-- This is a pretty dirty hack, but avoids needing to write a bunch of code to + mangle DTDs to appease validation --> + +<!ATTLIST html xmlns:dc CDATA #IMPLIED> +<!ATTLIST html xmlns:dct CDATA #IMPLIED> +<!ATTLIST html xmlns:rdf CDATA #IMPLIED> +<!ATTLIST html xmlns:rdfs CDATA #IMPLIED> + +<!ATTLIST html xmlns:atom CDATA #IMPLIED> +<!ATTLIST html xmlns:bufsz CDATA #IMPLIED> +<!ATTLIST html xmlns:da CDATA #IMPLIED> +<!ATTLIST html xmlns:dman CDATA #IMPLIED> +<!ATTLIST html xmlns:ev CDATA #IMPLIED> +<!ATTLIST html xmlns:ia CDATA #IMPLIED> +<!ATTLIST html xmlns:log CDATA #IMPLIED> +<!ATTLIST html xmlns:lv2 CDATA #IMPLIED> +<!ATTLIST html xmlns:midi CDATA #IMPLIED> +<!ATTLIST html xmlns:morph CDATA #IMPLIED> +<!ATTLIST html xmlns:opts CDATA #IMPLIED> +<!ATTLIST html xmlns:param CDATA #IMPLIED> +<!ATTLIST html xmlns:patch CDATA #IMPLIED> +<!ATTLIST html xmlns:pg CDATA #IMPLIED> +<!ATTLIST html xmlns:pprops CDATA #IMPLIED> +<!ATTLIST html xmlns:pset CDATA #IMPLIED> +<!ATTLIST html xmlns:rsz CDATA #IMPLIED> +<!ATTLIST html xmlns:state CDATA #IMPLIED> +<!ATTLIST html xmlns:time CDATA #IMPLIED> +<!ATTLIST html xmlns:ui CDATA #IMPLIED> +<!ATTLIST html xmlns:umap CDATA #IMPLIED> +<!ATTLIST html xmlns:units CDATA #IMPLIED> +<!ATTLIST html xmlns:urid CDATA #IMPLIED> +<!ATTLIST html xmlns:work CDATA #IMPLIED> diff --git a/lv2specgen/DTD/xhtml-rdfa-model-1.mod b/lv2specgen/DTD/xhtml-rdfa-model-1.mod new file mode 100644 index 0000000..ad010ee --- /dev/null +++ b/lv2specgen/DTD/xhtml-rdfa-model-1.mod @@ -0,0 +1,249 @@ +<!-- ....................................................................... --> +<!-- XHTML+RDFa Document Model Module ..................................... --> +<!-- file: xhtml-rdfa-model-1.mod + + This is XHTML+RDFa. + Copyright 1998-2008 W3C (MIT, ERCIM, Keio), All Rights Reserved. + Revision: $Id: xhtml-rdfa-model-1.mod,v 1.4 2009/06/26 14:05:13 smccarro Exp $ SMI + + This DTD module is identified by the PUBLIC and SYSTEM identifiers: + + PUBLIC "-//W3C//ENTITIES XHTML+RDFa Document Model 1.0//EN" + SYSTEM "http://www.w3.org/MarkUp/DTD/xhtml-rdfa-model-1.mod" + + Revisions: + (none) + ....................................................................... --> + +<!-- XHTML+RDFa Document Model + + This module describes the groupings of elements that make up + common content models for XHTML elements. + + XHTML has three basic content models: + + %Inline.mix; character-level elements + %Block.mix; block-like elements, eg., paragraphs and lists + %Flow.mix; any block or inline elements + + Any parameter entities declared in this module may be used + to create element content models, but the above three are + considered 'global' (insofar as that term applies here). + + The reserved word '#PCDATA' (indicating a text string) is now + included explicitly with each element declaration that is + declared as mixed content, as XML requires that this token + occur first in a content model specification. +--> +<!-- Extending the Model + + While in some cases this module may need to be rewritten to + accommodate changes to the document model, minor extensions + may be accomplished by redeclaring any of the three *.extra; + parameter entities to contain extension element types as follows: + + %Misc.extra; whose parent may be any block or + inline element. + + %Inline.extra; whose parent may be any inline element. + + %Block.extra; whose parent may be any block element. + + If used, these parameter entities must be an OR-separated + list beginning with an OR separator ("|"), eg., "| a | b | c" + + All block and inline *.class parameter entities not part + of the *struct.class classes begin with "| " to allow for + exclusion from mixes. +--> + +<!-- .............. Optional Elements in head .................. --> + +<!ENTITY % HeadOpts.mix + "( %script.qname; | %style.qname; | %meta.qname; + | %link.qname; | %object.qname; )*" +> + +<!-- ................. Miscellaneous Elements .................. --> + +<!-- ins and del are used to denote editing changes +--> +<!ENTITY % Edit.class "| %ins.qname; | %del.qname;" > + +<!-- script and noscript are used to contain scripts + and alternative content +--> +<!ENTITY % Script.class "| %script.qname; | %noscript.qname;" > + +<!ENTITY % Misc.extra "" > + +<!-- These elements are neither block nor inline, and can + essentially be used anywhere in the document body. +--> +<!ENTITY % Misc.class + "%Edit.class; + %Script.class; + %Misc.extra;" +> + +<!-- .................... Inline Elements ...................... --> + +<!ENTITY % InlStruct.class "%br.qname; | %span.qname;" > + +<!ENTITY % InlPhras.class + "| %em.qname; | %strong.qname; | %dfn.qname; | %code.qname; + | %samp.qname; | %kbd.qname; | %var.qname; | %cite.qname; + | %abbr.qname; | %acronym.qname; | %q.qname;" > + +<!ENTITY % InlPres.class + "| %tt.qname; | %i.qname; | %b.qname; | %big.qname; + | %small.qname; | %sub.qname; | %sup.qname;" > + +<!ENTITY % I18n.class "| %bdo.qname;" > + +<!ENTITY % Anchor.class "| %a.qname;" > + +<!ENTITY % InlSpecial.class + "| %img.qname; | %map.qname; + | %object.qname;" > + +<!ENTITY % InlForm.class + "| %input.qname; | %select.qname; | %textarea.qname; + | %label.qname; | %button.qname;" > + +<!ENTITY % Inline.extra "" > + +<!ENTITY % Ruby.class "| %ruby.qname;" > + +<!-- %Inline.class; includes all inline elements, + used as a component in mixes +--> +<!ENTITY % Inline.class + "%InlStruct.class; + %InlPhras.class; + %InlPres.class; + %I18n.class; + %Anchor.class; + %InlSpecial.class; + %InlForm.class; + %Ruby.class; + %Inline.extra;" +> + +<!-- %InlNoRuby.class; includes all inline elements + except ruby, used as a component in mixes +--> +<!ENTITY % InlNoRuby.class + "%InlStruct.class; + %InlPhras.class; + %InlPres.class; + %I18n.class; + %Anchor.class; + %InlSpecial.class; + %InlForm.class; + %Inline.extra;" +> + +<!-- %NoRuby.content; includes all inlines except ruby +--> +<!ENTITY % NoRuby.content + "( #PCDATA + | %InlNoRuby.class; + %Misc.class; )*" +> + +<!-- %InlNoAnchor.class; includes all non-anchor inlines, + used as a component in mixes +--> +<!ENTITY % InlNoAnchor.class + "%InlStruct.class; + %InlPhras.class; + %InlPres.class; + %I18n.class; + %InlSpecial.class; + %InlForm.class; + %Ruby.class; + %Inline.extra;" +> + +<!-- %InlNoAnchor.mix; includes all non-anchor inlines +--> +<!ENTITY % InlNoAnchor.mix + "%InlNoAnchor.class; + %Misc.class;" +> + +<!-- %Inline.mix; includes all inline elements, including %Misc.class; +--> +<!ENTITY % Inline.mix + "%Inline.class; + %Misc.class;" +> + +<!-- ..................... Block Elements ...................... --> + +<!-- In the HTML 4.0 DTD, heading and list elements were included + in the %block; parameter entity. The %Heading.class; and + %List.class; parameter entities must now be included explicitly + on element declarations where desired. +--> + +<!ENTITY % Heading.class + "%h1.qname; | %h2.qname; | %h3.qname; + | %h4.qname; | %h5.qname; | %h6.qname;" > + +<!ENTITY % List.class "%ul.qname; | %ol.qname; | %dl.qname;" > + +<!ENTITY % Table.class "| %table.qname;" > + +<!ENTITY % Form.class "| %form.qname;" > + +<!ENTITY % Fieldset.class "| %fieldset.qname;" > + +<!ENTITY % BlkStruct.class "%p.qname; | %div.qname;" > + +<!ENTITY % BlkPhras.class + "| %pre.qname; | %blockquote.qname; | %address.qname;" > + +<!ENTITY % BlkPres.class "| %hr.qname; " > + +<!ENTITY % BlkSpecial.class + "%Table.class; + %Form.class; + %Fieldset.class;" +> + +<!ENTITY % Block.extra "" > + +<!-- %Block.class; includes all block elements, + used as an component in mixes +--> +<!ENTITY % Block.class + "%BlkStruct.class; + %BlkPhras.class; + %BlkPres.class; + %BlkSpecial.class; + %Block.extra;" +> + +<!-- %Block.mix; includes all block elements plus %Misc.class; +--> +<!ENTITY % Block.mix + "%Heading.class; + | %List.class; + | %Block.class; + %Misc.class;" +> + +<!-- ................ All Content Elements .................. --> + +<!-- %Flow.mix; includes all text content, block and inline +--> +<!ENTITY % Flow.mix + "%Heading.class; + | %List.class; + | %Block.class; + | %Inline.class; + %Misc.class;" +> +<!-- end of xhtml-rdfa-model-1.mod --> diff --git a/lv2specgen/lv2docgen.py b/lv2specgen/lv2docgen.py index 423659e..23a239d 100755 --- a/lv2specgen/lv2docgen.py +++ b/lv2specgen/lv2docgen.py @@ -16,16 +16,16 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +import errno +import os +import sys + __date__ = '2012-03-27' __version__ = '0.0.0' __authors__ = 'David Robillard' __license__ = 'ISC License <http://www.opensource.org/licenses/isc>' __contact__ = 'devel@lists.lv2plug.in' -import errno -import os -import sys - try: import rdflib except ImportError: @@ -47,7 +47,7 @@ def get_doc(model, subject): if comment: return '<p class="content">%s</p>' % comment return '' - + def port_doc(model, port): name = model.value(port, lv2.name, None) comment = model.value(port, rdfs.comment, None) @@ -131,11 +131,8 @@ if __name__ == '__main__': pass else: raise - - print 'Writing <%s> documentation to %s' % (plugin, outpath) + + print('Writing <%s> documentation to %s' % (plugin, outpath)) out = open(outpath, 'w') out.write(html) out.close() - - - diff --git a/lv2specgen/lv2specgen.py b/lv2specgen/lv2specgen.py index efbf053..8cfa1c7 100755 --- a/lv2specgen/lv2specgen.py +++ b/lv2specgen/lv2specgen.py @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- # # lv2specgen, a documentation generator for LV2 specifications. -# Copyright (c) 2009-2012 David Robillard <d@drobilla.net> +# Copyright (c) 2009-2014 David Robillard <d@drobilla.net> # # Based on SpecGen: # <http://forge.morfeo-project.org/wiki_en/index.php/SpecGen> @@ -30,36 +30,41 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -__date__ = "2011-10-26" -__version__ = __date__.replace('-', '.') -__authors__ = """ -Christopher Schmidt, -Uldis Bojars, -Sergio Fernández, -David Robillard""" -__license__ = "MIT License <http://www.opensource.org/licenses/mit>" -__contact__ = "devel@lists.lv2plug.in" - import datetime +import markdown +import markdown.extensions +import optparse import os import re import sys +import time import xml.sax.saxutils import xml.dom import xml.dom.minidom +__date__ = "2011-10-26" +__version__ = __date__.replace("-", ".") +__authors__ = """ +Christopher Schmidt, +Uldis Bojars, +Sergio Fernández, +David Robillard""" +__license__ = "MIT License <http://www.opensource.org/licenses/mit>" +__contact__ = "devel@lists.lv2plug.in" + try: from lxml import etree + have_lxml = True -except: +except Exception: have_lxml = False try: import pygments import pygments.lexers + import pygments.lexers.rdf import pygments.formatters - from pygments.lexer import RegexLexer, include, bygroups - from pygments.token import Text, Comment, Operator, Keyword, Name, String, Literal, Punctuation + have_pygments = True except ImportError: print("Error importing pygments, syntax highlighting disabled") @@ -78,31 +83,32 @@ spec_url = None spec_ns_str = None spec_ns = None spec_pre = None +spec_bundle = None specgendir = None ns_list = { - "http://www.w3.org/1999/02/22-rdf-syntax-ns#" : "rdf", - "http://www.w3.org/2000/01/rdf-schema#" : "rdfs", - "http://www.w3.org/2002/07/owl#" : "owl", - "http://www.w3.org/2001/XMLSchema#" : "xsd", - "http://rdfs.org/sioc/ns#" : "sioc", - "http://xmlns.com/foaf/0.1/" : "foaf", - "http://purl.org/dc/elements/1.1/" : "dc", - "http://purl.org/dc/terms/" : "dct", - "http://purl.org/rss/1.0/modules/content/" : "content", - "http://www.w3.org/2003/01/geo/wgs84_pos#" : "geo", - "http://www.w3.org/2004/02/skos/core#" : "skos", - "http://lv2plug.in/ns/lv2core#" : "lv2", - "http://usefulinc.com/ns/doap#" : "doap", - "http://ontologi.es/doap-changeset#" : "dcs" - } - -rdf = rdflib.Namespace('http://www.w3.org/1999/02/22-rdf-syntax-ns#') -rdfs = rdflib.Namespace('http://www.w3.org/2000/01/rdf-schema#') -owl = rdflib.Namespace('http://www.w3.org/2002/07/owl#') -lv2 = rdflib.Namespace('http://lv2plug.in/ns/lv2core#') -doap = rdflib.Namespace('http://usefulinc.com/ns/doap#') -dcs = rdflib.Namespace('http://ontologi.es/doap-changeset#') -foaf = rdflib.Namespace('http://xmlns.com/foaf/0.1/') + "http://www.w3.org/1999/02/22-rdf-syntax-ns#": "rdf", + "http://www.w3.org/2000/01/rdf-schema#": "rdfs", + "http://www.w3.org/2002/07/owl#": "owl", + "http://www.w3.org/2001/XMLSchema#": "xsd", + "http://rdfs.org/sioc/ns#": "sioc", + "http://xmlns.com/foaf/0.1/": "foaf", + "http://purl.org/dc/elements/1.1/": "dc", + "http://purl.org/dc/terms/": "dct", + "http://purl.org/rss/1.0/modules/content/": "content", + "http://www.w3.org/2003/01/geo/wgs84_pos#": "geo", + "http://www.w3.org/2004/02/skos/core#": "skos", + "http://lv2plug.in/ns/lv2core#": "lv2", + "http://usefulinc.com/ns/doap#": "doap", + "http://ontologi.es/doap-changeset#": "dcs", +} + +rdf = rdflib.Namespace("http://www.w3.org/1999/02/22-rdf-syntax-ns#") +rdfs = rdflib.Namespace("http://www.w3.org/2000/01/rdf-schema#") +owl = rdflib.Namespace("http://www.w3.org/2002/07/owl#") +lv2 = rdflib.Namespace("http://lv2plug.in/ns/lv2core#") +doap = rdflib.Namespace("http://usefulinc.com/ns/doap#") +dcs = rdflib.Namespace("http://ontologi.es/doap-changeset#") +foaf = rdflib.Namespace("http://xmlns.com/foaf/0.1/") def findStatements(model, s, p, o): @@ -110,10 +116,10 @@ def findStatements(model, s, p, o): def findOne(m, s, p, o): - l = findStatements(m, s, p, o) + triples = findStatements(m, s, p, o) try: - return l.next() - except: + return sorted(triples)[0] + except Exception: return None @@ -146,6 +152,12 @@ def isLiteral(n): def niceName(uri): + global spec_bundle + if uri.startswith(spec_ns_str): + return uri[len(spec_ns_str) :] + elif uri == str(rdfs.seeAlso): + return "See also" + regexp = re.compile("^(.*[/#])([^/#]+)$") rez = regexp.search(uri) if not rez: @@ -165,148 +177,131 @@ def termName(m, urinode): def getLabel(m, urinode): - l = findOne(m, urinode, rdfs.label, None) - if l: - return getLiteralString(getObject(l)) + statement = findOne(m, urinode, rdfs.label, None) + if statement: + return getLiteralString(getObject(statement)) else: - return '' - -if have_pygments: - # Based on sw.py by Philip Cooper - class Notation3Lexer(RegexLexer): - """ - Lexer for N3 / Turtle / NT - """ - name = 'N3' - aliases = ['n3', 'turtle'] - filenames = ['*.n3', '*.ttl', '*.nt'] - mimetypes = ['text/rdf+n3','application/x-turtle','application/n3'] - - tokens = { - 'comments': [ - (r'(\s*#.*)', Comment) - ], - 'root': [ - include('comments'), - (r'(\s*@(?:prefix|base|keywords)\s*)(\w*:\s+)?(<[^> ]*>\s*\.\s*)',bygroups(Keyword,Name.Variable,Name.Namespace)), - (r'\s*(<[^>]*\>)', Name.Class, ('triple','predObj')), - (r'(\s*[a-zA-Z_:][a-zA-Z0-9\-_:]*\s)', Name.Class, ('triple','predObj')), - (r'\s*\[\]\s*', Name.Class, ('triple','predObj')), - ], - 'triple' : [ - (r'\s*\.\s*', Text, '#pop') - ], - 'predObj': [ - include('comments'), - (r'\s*a\s*', Name.Keyword, 'object'), - (r'\s*[a-zA-Z_:][a-zA-Z0-9\-_:]*\b\s*', Name.Tag, 'object'), - (r'\s*(<[^>]*\>)', Name.Tag, 'object'), - (r'\s*\]\s*', Text, '#pop'), - (r'(?=\s*\.\s*)', Keyword, '#pop'), - ], - 'objList': [ - include('comments'), - (r'\s*\)', Text, '#pop'), - include('object') - ], - 'object': [ - include('comments'), - (r'\s*\[', Text, 'predObj'), - (r'\s*<[^> ]*>', Name.Tag), - (r'\s*("""(?:.|\n)*?""")(\@[a-z]{2-4}|\^\^<?[a-zA-Z0-9\-\:_#/\.]*>?)?\s*', bygroups(Literal.String,Text)), - (r'\s*".*?[^\\]"(?:\@[a-z]{2-4}|\^\^<?[a-zA-Z0-9\-\:_#/\.]*>?)?\s*', Literal.String), - (r'\s*[0-9]+\.[0-9]*\s*\n?', Literal.Number), - (r'\s*[0-9]+\s*\n?', Literal.Number), - (r'\s*[a-zA-Z0-9\-_\:]+\s*', Name.Tag), - (r'\s*\(', Text, 'objList'), - (r'\s*;\s*\n?', Punctuation, '#pop'), - (r'\s*,\s*\n?', Punctuation), # Added by drobilla so "," is not an error - (r'(?=\s*\])', Text, '#pop'), - (r'(?=\s*\.)', Text, '#pop'), - ], - } - -def linkify(string): + return "" + + +def linkifyCodeIdentifiers(string): + "Add links to code documentation for identifiers like LV2_Type" + if linkmap == {}: return string - "Add links to code documentation for identifiers" if string in linkmap.keys(): # Exact match for complete string return linkmap[string] - rgx = re.compile('([^a-zA-Z0-9_:])(' + \ - '|'.join(map(re.escape, linkmap)) + \ - ')([^a-zA-Z0-9_:])') + rgx = re.compile( + "([^a-zA-Z0-9_:])(" + + "|".join(map(re.escape, linkmap)) + + ")([^a-zA-Z0-9_:])" + ) def translateCodeLink(match): return match.group(1) + linkmap[match.group(2)] + match.group(3) - + return rgx.sub(translateCodeLink, string) -def getComment(m, urinode, classlist, proplist, instalist): - c = findOne(m, urinode, lv2.documentation, None) - if c: - markup = getLiteralString(getObject(c)) - - # Syntax highlight all C code - if have_pygments: - code_rgx = re.compile('<pre class="c-code">(.*?)</pre>', re.DOTALL) - while True: - code = code_rgx.search(markup) - if not code: - break - match_str = xml.sax.saxutils.unescape(code.group(1)) - code_str = pygments.highlight( - match_str, - pygments.lexers.CLexer(), - pygments.formatters.HtmlFormatter()) - markup = code_rgx.sub(code_str, markup, 1) - - # Syntax highlight all Turtle code - if have_pygments: - code_rgx = re.compile('<pre class="turtle-code">(.*?)</pre>', re.DOTALL) - while True: - code = code_rgx.search(markup) - if not code: - break - match_str = xml.sax.saxutils.unescape(code.group(1)) - code_str = pygments.highlight( - match_str, - Notation3Lexer(), - pygments.formatters.HtmlFormatter()) - markup = code_rgx.sub(code_str, markup, 1) - - # Add links to code documentation for identifiers - markup = linkify(markup) - - # Transform prefixed names like eg:something into links if possible - rgx = re.compile('([a-zA-Z0-9_-]+):([a-zA-Z0-9_-]+)') - namespaces = getNamespaces(m) - def translateLink(match): - text = match.group(0) - prefix = match.group(1) - name = match.group(2) - curie = match.group(0) - uri = rdflib.URIRef(spec_ns + name) - if prefix == spec_pre: - if not ((classlist and uri in classlist) or - (instalist and uri in instalist) or - (proplist and uri in proplist)): - print("warning: Link to undefined resource <%s>\n" % text) - return '<a href="#%s">%s</a>' % (name, curie) - elif prefix in namespaces: - return '<a href="%s">%s</a>' % ( - namespaces[match.group(1)] + match.group(2), - match.group(0)) - else: - return text - markup = rgx.sub(translateLink, markup) - - if have_lxml: - try: - # Parse and validate documentation as XHTML Basic 1.1 - doc = """<?xml version="1.0" encoding="UTF-8"?> + +def linkifyVocabIdentifiers(m, string, classlist, proplist, instalist): + "Add links to vocabulary documentation for prefixed names like eg:Thing" + + rgx = re.compile("([a-zA-Z0-9_-]+):([a-zA-Z0-9_-]+)") + namespaces = getNamespaces(m) + + def translateLink(match): + text = match.group(0) + prefix = match.group(1) + name = match.group(2) + uri = rdflib.URIRef(spec_ns + name) + if prefix == spec_pre: + if not ( + (classlist and uri in classlist) + or (instalist and uri in instalist) + or (proplist and uri in proplist) + ): + print("warning: Link to undefined resource <%s>\n" % text) + return '<a href="#%s">%s</a>' % (name, name) + elif prefix in namespaces: + return '<a href="%s">%s</a>' % ( + namespaces[match.group(1)] + match.group(2), + match.group(0), + ) + else: + return text + + return rgx.sub(translateLink, string) + + +def prettifyHtml(m, markup, subject, classlist, proplist, instalist): + # Syntax highlight all C code + if have_pygments: + code_rgx = re.compile('<pre class="c-code">(.*?)</pre>', re.DOTALL) + while True: + code = code_rgx.search(markup) + if not code: + break + match_str = xml.sax.saxutils.unescape(code.group(1)) + code_str = pygments.highlight( + match_str, + pygments.lexers.CLexer(), + pygments.formatters.HtmlFormatter(), + ) + markup = code_rgx.sub(code_str, markup, 1) + + # Syntax highlight all Turtle code + if have_pygments: + code_rgx = re.compile( + '<pre class="turtle-code">(.*?)</pre>', re.DOTALL + ) + while True: + code = code_rgx.search(markup) + if not code: + break + match_str = xml.sax.saxutils.unescape(code.group(1)) + code_str = pygments.highlight( + match_str, + pygments.lexers.rdf.TurtleLexer(), + pygments.formatters.HtmlFormatter(), + ) + markup = code_rgx.sub(code_str, markup, 1) + + # Add links to code documentation for identifiers + markup = linkifyCodeIdentifiers(markup) + + # Add internal links for known prefixed names + markup = linkifyVocabIdentifiers(m, markup, classlist, proplist, instalist) + + # Transform names like #foo into links into this spec if possible + rgx = re.compile("([ \t\n\r\f\v^]+)#([a-zA-Z0-9_-]+)") + + def translateLocalLink(match): + text = match.group(0) + space = match.group(1) + name = match.group(2) + uri = rdflib.URIRef(spec_ns + name) + if ( + (classlist and uri in classlist) + or (instalist and uri in instalist) + or (proplist and uri in proplist) + ): + return '%s<a href="#%s">%s</a>' % (space, name, name) + else: + print("warning: Link to undefined resource <%s>\n" % name) + return text + + markup = rgx.sub(translateLocalLink, markup) + + if not have_lxml: + print("warning: No Python lxml module found, output may be invalid") + else: + try: + # Parse and validate documentation as XHTML Basic 1.1 + doc = ( + """<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "DTD/xhtml-basic11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> @@ -314,43 +309,108 @@ def getComment(m, urinode, classlist, proplist, instalist): <title>Validation Skeleton Document</title> </head> <body> -%s +""" + + markup + + """ </body> -</html> -""" % str(markup.decode()) - - oldcwd = os.getcwd() - os.chdir(specgendir) - parser = etree.XMLParser(dtd_validation=True, no_network=True) - root = etree.fromstring(doc, parser) - os.chdir(oldcwd) - except Exception as e: - print("Invalid lv2:documentation for %s\n%s" % (urinode, e)) +</html>""" + ) + + oldcwd = os.getcwd() + os.chdir(specgendir) + parser = etree.XMLParser(dtd_validation=True, no_network=True) + etree.fromstring(doc.encode("utf-8"), parser) + except Exception as e: + print("Invalid documentation for %s\n%s" % (subject, e)) + line_num = 1 + for line in doc.split("\n"): + print("%3d: %s" % (line_num, line)) + line_num += 1 + finally: + os.chdir(oldcwd) + + return markup + + +def formatDoc(m, urinode, literal, classlist, proplist, instalist): + string = getLiteralString(literal) + + if literal.datatype == lv2.Markdown: + ext = [ + "markdown.extensions.codehilite", + "markdown.extensions.tables", + "markdown.extensions.def_list", + ] + + doc = markdown.markdown(string, extensions=ext) + + # Hack to make tables valid XHTML Basic 1.1 + for tag in ["thead", "tbody"]: + doc = doc.replace("<%s>\n" % tag, "") + doc = doc.replace("</%s>\n" % tag, "") + + return prettifyHtml(m, doc, urinode, classlist, proplist, instalist) + else: + doc = xml.sax.saxutils.escape(string) + doc = linkifyCodeIdentifiers(doc) + doc = linkifyVocabIdentifiers(m, doc, classlist, proplist, instalist) + return "<p>%s</p>" % doc - return markup - c = findOne(m, urinode, rdfs.comment, None) +def getComment(m, subject, classlist, proplist, instalist): + c = findOne(m, subject, rdfs.comment, None) if c: - text = getLiteralString(getObject(c)) - return '<p>%s</p>' % xml.sax.saxutils.escape(text) + comment = getObject(c) + return formatDoc(m, subject, comment, classlist, proplist, instalist) + + return "" + - return '' +def getDetailedDocumentation(m, subject, classlist, proplist, instalist): + markup = "" + + d = findOne(m, subject, lv2.documentation, None) + if d: + doc = getObject(d) + if doc.datatype == lv2.Markdown: + markup += formatDoc( + m, subject, doc, classlist, proplist, instalist + ) + else: + html = getLiteralString(doc) + markup += prettifyHtml( + m, html, subject, classlist, proplist, instalist + ) + + return markup + + +def getFullDocumentation(m, subject, classlist, proplist, instalist): + # Use rdfs:comment for first summary line + markup = getComment(m, subject, classlist, proplist, instalist) + + # Use lv2:documentation for further details + markup += getDetailedDocumentation( + m, subject, classlist, proplist, instalist + ) + + return markup def getProperty(val, first=True): "Return a string representing a property value in a property table" - doc = '' + doc = "" if not first: - doc += '<tr><td></td>' # Empty cell in header column - doc += '<td>%s</td></tr>\n' % val + doc += "<tr><th></th>" # Empty cell in header column + doc += "<td>%s</td></tr>\n" % val return doc def endProperties(first): if first: - return '</tr>' + return "</tr>" else: - return '' + return "" def rdfsPropertyInfo(term, m): @@ -358,54 +418,64 @@ def rdfsPropertyInfo(term, m): global classranges global classdomains doc = "" - range = "" - domain = "" + + label = getLabel(m, term) + if label != "": + doc += "<tr><th>Label</th><td>%s</td></tr>" % label # Find subPropertyOf information - rlist = '' + rlist = "" first = True for st in findStatements(m, term, rdfs.subPropertyOf, None): k = getTermLink(getObject(st), term, rdfs.subPropertyOf) rlist += getProperty(k, first) first = False - if rlist != '': - doc += '<tr><th>Sub-property of</th>' + rlist + if rlist != "": + doc += "<tr><th>Sub-property of</th>" + rlist # Domain stuff domains = findStatements(m, term, rdfs.domain, None) domainsdoc = "" first = True - for d in domains: + for d in sorted(domains): union = findOne(m, getObject(d), owl.unionOf, None) if union: uris = parseCollection(m, getObject(union)) for uri in uris: - domainsdoc += getProperty(getTermLink(uri, term, rdfs.domain), first) + domainsdoc += getProperty( + getTermLink(uri, term, rdfs.domain), first + ) add(classdomains, uri, term) else: if not isBlank(getObject(d)): - domainsdoc += getProperty(getTermLink(getObject(d), term, rdfs.domain), first) + domainsdoc += getProperty( + getTermLink(getObject(d), term, rdfs.domain), first + ) first = False - if (len(domainsdoc) > 0): + if len(domainsdoc) > 0: doc += "<tr><th>Domain</th>%s" % domainsdoc # Range stuff ranges = findStatements(m, term, rdfs.range, None) rangesdoc = "" first = True - for r in ranges: + for r in sorted(ranges): union = findOne(m, getObject(r), owl.unionOf, None) if union: uris = parseCollection(m, getObject(union)) for uri in uris: - rangesdoc += getProperty(getTermLink(uri, term, rdfs.range), first) + rangesdoc += getProperty( + getTermLink(uri, term, rdfs.range), first + ) add(classranges, uri, term) first = False else: if not isBlank(getObject(r)): - rangesdoc += getProperty(getTermLink(getObject(r), term, rdfs.range), first) + rangesdoc += getProperty( + getTermLink(getObject(r), term, rdfs.range), first + ) first = False - if (len(rangesdoc) > 0): + if len(rangesdoc) > 0: doc += "<tr><th>Range</th>%s" % rangesdoc return doc @@ -416,10 +486,10 @@ def parseCollection(model, node): while node: first = findOne(model, node, rdf.first, None) - rest = findOne(model, node, rdf.rest, None) + rest = findOne(model, node, rdf.rest, None) if not first or not rest: - break; - + break + uris.append(getObject(first)) node = getObject(rest) @@ -428,41 +498,36 @@ def parseCollection(model, node): def getTermLink(uri, subject=None, predicate=None): uri = str(uri) - extra = '' - if subject != None and predicate != None: - extra = 'about="%s" rel="%s" resource="%s"' % (str(subject), niceName(str(predicate)), uri) - if (uri.startswith(spec_ns_str)): - return '<a href="#%s" %s>%s</a>' % (uri.replace(spec_ns_str, ""), extra, niceName(uri)) + extra = "" + if subject is not None and predicate is not None: + extra = 'about="%s" rel="%s" resource="%s"' % ( + str(subject), + niceName(str(predicate)), + uri, + ) + if uri.startswith(spec_ns_str): + return '<a href="#%s" %s>%s</a>' % ( + uri.replace(spec_ns_str, ""), + extra, + niceName(uri), + ) else: return '<a href="%s" %s>%s</a>' % (uri, extra, niceName(uri)) -def rdfsClassInfo(term, m): - """Generate rdfs-type information for Classes: ranges, and domains.""" - global classranges - global classdomains - doc = "" - - # Find subClassOf information +def owlRestrictionInfo(term, m): + """Generate OWL restriction information for Classes""" restrictions = [] - superclasses = [] - for st in findStatements(m, term, rdfs.subClassOf, None): - if not isBlank(getObject(st)): - uri = getObject(st) - if not uri in superclasses: - superclasses.append(uri) - else: - meta_type = findOne(m, getObject(st), rdf.type, None) - restrictions.append(getSubject(meta_type)) - - if len(superclasses) > 0: - doc += "\n<tr><th>Sub-class of</th>" - first = True - for superclass in superclasses: - doc += getProperty(getTermLink(superclass), first) - first = False + for s in findStatements(m, term, rdfs.subClassOf, None): + if findOne(m, getObject(s), rdf.type, owl.Restriction): + restrictions.append(getObject(s)) + + if not restrictions: + return "" + + doc = "<dl>" - for r in restrictions: + for r in sorted(restrictions): props = findStatements(m, r, None, None) onProp = None comment = None @@ -471,46 +536,82 @@ def rdfsClassInfo(term, m): onProp = getObject(p) elif getPredicate(p) == rdfs.comment: comment = getObject(p) - if onProp != None: - doc += '<tr><th>Restriction on %s</th><td>' % getTermLink(onProp) + if onProp is not None: + doc += "<dt>Restriction on %s</dt>\n" % getTermLink(onProp) - prop_str = '' - last_pred = None - first = True + prop_str = "" for p in findStatements(m, r, None, None): - if (getPredicate(p) == owl.onProperty + if ( + getPredicate(p) == owl.onProperty or getPredicate(p) == rdfs.comment - or (getPredicate(p) == rdf.type and getObject(p) == owl.Restriction) - or getPredicate(p) == lv2.documentation): - last_pred = None + or ( + getPredicate(p) == rdf.type + and getObject(p) == owl.Restriction + ) + or getPredicate(p) == lv2.documentation + ): continue - if getPredicate(p) != last_pred: - prop_str += '<tr><th>%s</th>\n' % getTermLink(getPredicate(p)) - first = True + prop_str += getTermLink(getPredicate(p)) + if isResource(getObject(p)): - prop_str += getProperty(getTermLink(getObject(p)), first) - first = False + prop_str += " " + getTermLink(getObject(p)) elif isLiteral(getObject(p)): - prop_str += getProperty(getLiteralString(getObject(p)), first) - first = False + prop_str += " " + getLiteralString(getObject(p)) + + if comment is not None: + prop_str += "\n<div>%s</div>\n" % getLiteralString(comment) - last_pred = getPredicate(p) + doc += "<dd>%s</dd>" % prop_str if prop_str else "" - prop_str += endProperties(first) + doc += "</dl>" + return doc - if prop_str != '': - doc += '<table class=\"restriction\">%s</table>\n' % prop_str - if comment != None: - doc += "<span>%s</span>\n" % getLiteralString(comment) - doc += '</td></tr>' + +def rdfsClassInfo(term, m): + """Generate rdfs-type information for Classes: ranges, and domains.""" + global classranges + global classdomains + doc = "" + + label = getLabel(m, term) + if label != "": + doc += "<tr><th>Label</th><td>%s</td></tr>" % label + + # Find superclasses + superclasses = set() + for st in findStatements(m, term, rdfs.subClassOf, None): + if not isBlank(getObject(st)): + uri = getObject(st) + superclasses |= set([uri]) + + if len(superclasses) > 0: + doc += "\n<tr><th>Subclass of</th>" + first = True + for superclass in sorted(superclasses): + doc += getProperty(getTermLink(superclass), first) + first = False + + # Find subclasses + subclasses = set() + for st in findStatements(m, None, rdfs.subClassOf, term): + if not isBlank(getObject(st)): + uri = getSubject(st) + subclasses |= set([uri]) + + if len(subclasses) > 0: + doc += "\n<tr><th>Superclass of</th>" + first = True + for superclass in sorted(subclasses): + doc += getProperty(getTermLink(superclass), first) + first = False # Find out about properties which have rdfs:domain of t d = classdomains.get(str(term), "") if d: - dlist = '' + dlist = "" first = True - for k in d: + for k in sorted(d): dlist += getProperty(getTermLink(k), first) first = False doc += "<tr><th>In domain of</th>%s" % dlist @@ -518,9 +619,9 @@ def rdfsClassInfo(term, m): # Find out about properties which have rdfs:range of t r = classranges.get(str(term), "") if r: - rlist = '' + rlist = "" first = True - for k in r: + for k in sorted(r): rlist += getProperty(getTermLink(k), first) first = False doc += "<tr><th>In range of</th>%s" % rlist @@ -529,30 +630,45 @@ def rdfsClassInfo(term, m): def isSpecial(pred): - """Return True if the predicate is "special" and shouldn't be emitted generically""" - return pred in [rdf.type, rdfs.range, rdfs.domain, rdfs.label, rdfs.comment, rdfs.subClassOf, rdfs.subPropertyOf, lv2.documentation] + """Return True if `pred` shouldn't be documented generically""" + return pred in [ + rdf.type, + rdfs.range, + rdfs.domain, + rdfs.label, + rdfs.comment, + rdfs.subClassOf, + rdfs.subPropertyOf, + lv2.documentation, + owl.withRestrictions, + ] def blankNodeDesc(node, m): properties = findStatements(m, node, None, None) - doc = '' - last_pred = '' - for p in properties: + doc = "" + for p in sorted(properties): if isSpecial(getPredicate(p)): continue - doc += '<tr>' + doc += "<tr>" doc += '<td class="blankterm">%s</td>\n' % getTermLink(getPredicate(p)) if isResource(getObject(p)): doc += '<td class="blankdef">%s</td>\n' % getTermLink(getObject(p)) # getTermLink(str(getObject(p)), node, getPredicate(p)) elif isLiteral(getObject(p)): - doc += '<td class="blankdef">%s</td>\n' % getLiteralString(getObject(p)) + doc += '<td class="blankdef">%s</td>\n' % getLiteralString( + getObject(p) + ) elif isBlank(getObject(p)): - doc += '<td class="blankdef">' + blankNodeDesc(getObject(p), m) + '</td>\n' + doc += ( + '<td class="blankdef">' + + blankNodeDesc(getObject(p), m) + + "</td>\n" + ) else: doc += '<td class="blankdef">?</td>\n' - doc += '</tr>' - if doc != '': + doc += "</tr>" + if doc != "": doc = '<table class="blankdesc">\n%s\n</table>\n' % doc return doc @@ -561,27 +677,25 @@ def extraInfo(term, m): """Generate information about misc. properties of a term""" doc = "" properties = findStatements(m, term, None, None) - last_pred = None first = True - for p in properties: + for p in sorted(properties): if isSpecial(getPredicate(p)): - last_pred = None continue - if getPredicate(p) != last_pred: - doc += '<tr><th>%s</th>\n' % getTermLink(getPredicate(p)) - first = True + doc += "<tr><th>%s</th>\n" % getTermLink(getPredicate(p)) if isResource(getObject(p)): - doc += getProperty(getTermLink(getObject(p), term, getPredicate(p)), first) + doc += getProperty( + getTermLink(getObject(p), term, getPredicate(p)), first + ) elif isLiteral(getObject(p)): - doc += getProperty(linkify(str(getObject(p))), first) + doc += getProperty( + linkifyCodeIdentifiers(str(getObject(p))), first + ) elif isBlank(getObject(p)): doc += getProperty(str(blankNodeDesc(getObject(p), m)), first) else: - doc += getProperty('?', first) - first = False - last_pred = getPredicate(p) + doc += getProperty("?", first) - #doc += endProperties(first) + # doc += endProperties(first) return doc @@ -590,16 +704,20 @@ def rdfsInstanceInfo(term, m): """Generate rdfs-type information for instances""" doc = "" + label = getLabel(m, term) + if label != "": + doc += "<tr><th>Label</th><td>%s</td></tr>" % label + first = True - for match in findStatements(m, term, rdf.type, None): - doc += getProperty(getTermLink(getObject(match), - term, - rdf.type), - first) + types = "" + for match in sorted(findStatements(m, term, rdf.type, None)): + types += getProperty( + getTermLink(getObject(match), term, rdf.type), first + ) first = False - if doc != "": - doc = "<tr><th>Type</th>" + doc + if types != "": + doc += "<tr><th>Type</th>" + types doc += endProperties(first) @@ -608,7 +726,7 @@ def rdfsInstanceInfo(term, m): def owlInfo(term, m): """Returns an extra information that is defined about a term using OWL.""" - res = '' + res = "" # Inverse properties ( owl:inverseOf ) first = True @@ -621,78 +739,81 @@ def owlInfo(term, m): def owlTypeInfo(term, propertyType, name): if findOne(m, term, rdf.type, propertyType): - return "<tr><th>OWL Type</th><td>%s</td></tr>\n" % name + return "<tr><th>Type</th><td>%s</td></tr>\n" % name else: return "" res += owlTypeInfo(term, owl.DatatypeProperty, "Datatype Property") res += owlTypeInfo(term, owl.ObjectProperty, "Object Property") res += owlTypeInfo(term, owl.AnnotationProperty, "Annotation Property") - res += owlTypeInfo(term, owl.InverseFunctionalProperty, "Inverse Functional Property") + res += owlTypeInfo( + term, owl.InverseFunctionalProperty, "Inverse Functional Property" + ) res += owlTypeInfo(term, owl.SymmetricProperty, "Symmetric Property") return res +def isDeprecated(m, subject): + deprecated = findOne(m, subject, owl.deprecated, None) + return deprecated and (str(deprecated[2]).find("true") >= 0) + + def docTerms(category, list, m, classlist, proplist, instalist): """ A wrapper class for listing all the terms in a specific class (either Properties, or Classes. Category is 'Property' or 'Class', list is a - list of term names (strings), return value is a chunk of HTML. + list of term URI strings, return value is a chunk of HTML. """ doc = "" - nspre = spec_pre - for item in list: - t = termName(m, item) - if (t.startswith(spec_ns_str)) and ( - len(t[len(spec_ns_str):].split("/")) < 2): - term = t - t = t.split(spec_ns_str[-1])[1] - curie = "%s:%s" % (nspre, t) - else: - if t.startswith("http://"): - term = t - curie = getShortName(t) - t = getAnchor(t) - else: - term = spec_ns[t] - curie = "%s:%s" % (nspre, t) - - term_uri = term + for term in list: + if not term.startswith(spec_ns_str): + sys.stderr.write("warning: Skipping external term `%s'" % term) + continue - doc += """<div class="specterm" id="%s" about="%s">\n<h3>%s <a href="#%s">%s</a></h3>\n""" % (t, term_uri, category, getAnchor(str(term_uri)), curie) + t = termName(m, term) + curie = term.split(spec_ns_str[-1])[1] + doc += '<div class="specterm" id="%s" about="%s">' % (t, term) + doc += '<h3><a href="#%s">%s</a></h3>' % (getAnchor(term), curie) + doc += '<span class="spectermtype">%s</span>' % category - label = getLabel(m, term) - comment = getComment(m, term, classlist, proplist, instalist) + comment = getFullDocumentation(m, term, classlist, proplist, instalist) + is_deprecated = isDeprecated(m, term) doc += '<div class="spectermbody">' - if label != '' or comment != '': - doc += '<div class="description">' - - if label != '': - doc += "<div property=\"rdfs:label\" class=\"label\">%s</div>" % label - - if comment != '': - doc += "<div property=\"rdfs:comment\">%s</div>" % comment - - if label != '' or comment != '': - doc += "</div>" terminfo = "" - if category == 'Property': - terminfo += owlInfo(term, m) + extrainfo = "" + if category == "Property": terminfo += rdfsPropertyInfo(term, m) - if category == 'Class': + terminfo += owlInfo(term, m) + if category == "Class": terminfo += rdfsClassInfo(term, m) - if category == 'Instance': + extrainfo += owlRestrictionInfo(term, m) + if category == "Instance": terminfo += rdfsInstanceInfo(term, m) terminfo += extraInfo(term, m) - if (len(terminfo) > 0): # to prevent empty list (bug #882) + if len(terminfo) > 0: # to prevent empty list (bug #882) doc += '\n<table class="terminfo">%s</table>\n' % terminfo - doc += '</div>' + doc += '<div class="description">' + + if is_deprecated: + doc += '<div class="warning">Deprecated</div>' + + if comment != "": + doc += ( + '<div class="comment" property="rdfs:comment">%s</div>' + % comment + ) + + doc += extrainfo + + doc += "</div>" + + doc += "</div>" doc += "\n</div>\n\n" return doc @@ -700,7 +821,7 @@ def docTerms(category, list, m, classlist, proplist, instalist): def getShortName(uri): uri = str(uri) - if ("#" in uri): + if "#" in uri: return uri.split("#")[-1] else: return uri.split("/")[-1] @@ -708,29 +829,31 @@ def getShortName(uri): def getAnchor(uri): uri = str(uri) - if (uri.startswith(spec_ns_str)): - return uri[len(spec_ns_str):].replace("/", "_") + if uri.startswith(spec_ns_str): + return uri[len(spec_ns_str) :].replace("/", "_") else: return getShortName(uri) def buildIndex(m, classlist, proplist, instalist=None): - """ - Builds the A-Z list of terms. Args are a list of classes (strings) and - a list of props (strings) - """ + if not (classlist or proplist or instalist): + return "" - if len(classlist) == 0 and len(proplist) == 0 and ( - not instalist or len(instalist) == 0): - return '' + head = "" + body = "" - azlist = '<dl class="index">' + def termLink(m, t): + if str(t).startswith(spec_ns_str): + name = termName(m, t) + return '<a href="#%s">%s</a>' % (name, name) + else: + return '<a href="%s">%s</a>' % (str(t), str(t)) - if (len(classlist) > 0): - azlist += "<dt>Classes</dt><dd><ul>" - classlist.sort() + if len(classlist) > 0: + head += '<th><a href="#ref-classes" />Classes</th>' + body += "<td><ul>" shown = {} - for c in classlist: + for c in sorted(classlist): if c in shown: continue @@ -738,65 +861,66 @@ def buildIndex(m, classlist, proplist, instalist=None): local_subclass = False for p in findStatements(m, c, rdfs.subClassOf, None): parent = str(p[2]) - if parent[0:len(spec_ns_str)] == spec_ns_str: + if parent[0 : len(spec_ns_str)] == spec_ns_str: local_subclass = True if local_subclass: continue shown[c] = True - name = termName(m, c) - if name.startswith(spec_ns_str): - name = name.split(spec_ns_str[-1])[1] - azlist += '<li><a href="#%s">%s</a>' % (name, name) + body += "<li>" + termLink(m, c) + def class_tree(c): - tree = '' + tree = "" shown[c] = True subclasses = [] for s in findStatements(m, None, rdfs.subClassOf, c): subclasses += [getSubject(s)] - subclasses.sort() - for s in subclasses: - s_name = termName(m, s) - tree += '<li><a href="#%s">%s</a>\n' % (s_name, s_name) + for s in sorted(subclasses): + tree += "<li>" + termLink(m, s) tree += class_tree(s) - tree += '</li>' - if tree != '': - tree = '<ul>' + tree + '</ul>' + tree += "</li>" + if tree != "": + tree = "<ul>" + tree + "</ul>" return tree - azlist += class_tree(c) - azlist += '</li>' - azlist += '</ul></dd>\n' - - if (len(proplist) > 0): - azlist += "<dt>Properties</dt><dd>" - proplist.sort() - props = [] - for p in proplist: - name = termName(m, p) - if name.startswith(spec_ns_str): - name = name.split(spec_ns_str[-1])[1] - props += ['<a href="#%s">%s</a>' % (name, name)] - azlist += ', '.join(props) + '</dd>\n' - - if (instalist != None and len(instalist) > 0): - azlist += "<dt>Instances</dt><dd>" - instas = [] - for i in instalist: + + body += class_tree(c) + body += "</li>" + body += "</ul></td>\n" + + if len(proplist) > 0: + head += '<th><a href="#ref-properties" />Properties</th>' + body += "<td><ul>" + for p in sorted(proplist): + body += "<li>%s</li>" % termLink(m, p) + body += "</ul></td>\n" + + if instalist is not None and len(instalist) > 0: + head += '<th><a href="#ref-instances" />Instances</th>' + body += "<td><ul>" + for i in sorted(instalist): p = getShortName(i) anchor = getAnchor(i) - instas += ['<a href="#%s">%s</a>' % (anchor, p)] - azlist += ', '.join(instas) + '</dd>\n' + body += '<li><a href="#%s">%s</a></li>' % (anchor, p) + body += "</ul></td>\n" + + if head and body: + return """<table class="index"> +<thead><tr>%s</tr></thead> +<tbody><tr>%s</tr></tbody></table> +""" % ( + head, + body, + ) - azlist += '\n</dl>' - return azlist + return "" def add(where, key, value): - if not key in where: + if key not in where: where[key] = [] - if not value in where[key]: + if value not in where[key]: where[key].append(value) @@ -814,23 +938,36 @@ def specInformation(m, ns): classlist = [] for onetype in classtypes: for classStatement in findStatements(m, None, rdf.type, onetype): - for range in findStatements(m, None, rdfs.range, getSubject(classStatement)): + for range in findStatements( + m, None, rdfs.range, getSubject(classStatement) + ): if not isBlank(getSubject(classStatement)): - add(classranges, + add( + classranges, str(getSubject(classStatement)), - str(getSubject(range))) - for domain in findStatements(m, None, rdfs.domain, getSubject(classStatement)): + str(getSubject(range)), + ) + for domain in findStatements( + m, None, rdfs.domain, getSubject(classStatement) + ): if not isBlank(getSubject(classStatement)): - add(classdomains, + add( + classdomains, str(getSubject(classStatement)), - str(getSubject(domain))) + str(getSubject(domain)), + ) if not isBlank(getSubject(classStatement)): klass = getSubject(classStatement) if klass not in classlist and str(klass).startswith(ns): classlist.append(klass) # Create a list of properties in the schema. - proptypes = [rdf.Property, owl.ObjectProperty, owl.DatatypeProperty, owl.AnnotationProperty] + proptypes = [ + rdf.Property, + owl.ObjectProperty, + owl.DatatypeProperty, + owl.AnnotationProperty, + ] proplist = [] for onetype in proptypes: for propertyStatement in findStatements(m, None, rdf.type, onetype): @@ -845,7 +982,7 @@ def specProperty(m, subject, predicate): "Return a property of the spec." for c in findStatements(m, subject, predicate, None): return getLiteralString(getObject(c)) - return '' + return "" def specProperties(m, subject, predicate): @@ -858,94 +995,136 @@ def specProperties(m, subject, predicate): def specAuthors(m, subject): "Return an HTML description of the authors of the spec." + + subjects = [subject] + p = findOne(m, subject, lv2.project, None) + if p: + subjects += [getObject(p)] + dev = set() - for i in findStatements(m, subject, doap.developer, None): - for j in findStatements(m, getObject(i), foaf.name, None): - dev.add(getLiteralString(getObject(j))) + for s in subjects: + for i in findStatements(m, s, doap.developer, None): + for j in findStatements(m, getObject(i), foaf.name, None): + dev.add(getLiteralString(getObject(j))) maint = set() - for i in findStatements(m, subject, doap.maintainer, None): - for j in findStatements(m, getObject(i), foaf.name, None): - maint.add(getLiteralString(getObject(j))) + for s in subjects: + for i in findStatements(m, s, doap.maintainer, None): + for j in findStatements(m, getObject(i), foaf.name, None): + maint.add(getLiteralString(getObject(j))) - doc = '' + doc = "" - devdoc = '' + devdoc = "" first = True - for d in dev: + for d in sorted(dev): if not first: - devdoc += ', ' - devdoc += '<span class="author" property="doap:developer">%s</span>' % d + devdoc += ", " + devdoc += ( + '<span class="author" property="doap:developer">%s</span>' % d + ) first = False if len(dev) == 1: - doc += '<tr><th class="metahead">Developer</th><td>%s</td></tr>' % devdoc + doc += ( + '<tr><th class="metahead">Developer</th><td>%s</td></tr>' % devdoc + ) elif len(dev) > 0: - doc += '<tr><th class="metahead">Developers</th><td>%s</td></tr>' % devdoc + doc += ( + '<tr><th class="metahead">Developers</th><td>%s</td></tr>' % devdoc + ) - maintdoc = '' + maintdoc = "" first = True - for m in maint: + for m in sorted(maint): if not first: - maintdoc += ', ' - maintdoc += '<span class="author" property="doap:maintainer">%s</span>' % m + maintdoc += ", " + maintdoc += ( + '<span class="author" property="doap:maintainer">%s</span>' % m + ) first = False if len(maint) == 1: - doc += '<tr><th class="metahead">Maintainer</th><td>%s</td></tr>' % maintdoc + doc += ( + '<tr><th class="metahead">Maintainer</th><td>%s</td></tr>' + % maintdoc + ) elif len(maint) > 0: - doc += '<tr><th class="metahead">Maintainers</th><td>%s</td></tr>' % maintdoc + doc += ( + '<tr><th class="metahead">Maintainers</th><td>%s</td></tr>' + % maintdoc + ) return doc -def specHistory(m, subject): - entries = {} +def releaseChangeset(m, release, prefix=""): + changeset = findOne(m, release, dcs.changeset, None) + if changeset is None: + return "" + + entry = "" + # entry = '<dd><ul>\n' + for i in sorted(findStatements(m, getObject(changeset), dcs.item, None)): + item = getObject(i) + label = findOne(m, item, rdfs.label, None) + if not label: + print("error: dcs:item has no rdfs:label") + continue + + text = getLiteralString(getObject(label)) + if prefix: + text = prefix + ": " + text + + entry += "<li>%s</li>\n" % text + + # entry += '</ul></dd>\n' + return entry + + +def specHistoryEntries(m, subject, entries): for r in findStatements(m, subject, doap.release, None): release = getObject(r) revNode = findOne(m, release, doap.revision, None) if not revNode: - print "error: doap:release has no doap:revision" + print("error: doap:release has no doap:revision") continue rev = getLiteralString(getObject(revNode)) created = findOne(m, release, doap.created, None) - dist = findOne(m, release, doap['file-release'], None) + dist = findOne(m, release, doap["file-release"], None) if dist: entry = '<dt><a href="%s">Version %s</a>' % (getObject(dist), rev) else: - entry = '<dt>Version %s' % rev - #print "warning: doap:release has no doap:file-release" + entry = "<dt>Version %s" % rev + # print("warning: doap:release has no doap:file-release") if created: - entry += ' (%s)</dt>' % getLiteralString(getObject(created)) + entry += " (%s)</dt>\n" % getLiteralString(getObject(created)) else: entry += ' (<span class="warning">EXPERIMENTAL</span>)</dt>' - changeset = findOne(m, release, dcs.changeset, None) - if changeset: - entry += '<dd><ul>' - for i in findStatements(m, getObject(changeset), dcs.item, None): - item = getObject(i) - label = findOne(m, item, rdfs.label, None) - if not label: - print "error: dcs:item has no rdfs:label" - continue + entry += "<dd><ul>\n%s" % releaseChangeset(m, release) - entry += '<li>%s</li>' % getLiteralString(getObject(label)) + if dist is not None: + entries[(getObject(created), getObject(dist))] = entry - entry += '</ul></dd>\n' + return entries - entries[rev] = entry +def specHistoryMarkup(entries): if len(entries) > 0: - history = '<dl>' + history = "<dl>\n" for e in sorted(entries.keys(), reverse=True): - history += entries[e] - history += '</dl>' + history += entries[e] + "</ul></dd>" + history += "</dl>\n" return history else: - return '' + return "" + + +def specHistory(m, subject): + return specHistoryMarkup(specHistoryEntries(m, subject, {})) def specVersion(m, subject): @@ -962,7 +1141,7 @@ def specVersion(m, subject): latest_doap_revision = revision latest_doap_release = getObject(i) date = "" - if latest_doap_release != None: + if latest_doap_release is not None: for i in findStatements(m, latest_doap_release, doap.created, None): date = getLiteralString(getObject(i)) @@ -990,16 +1169,19 @@ def getInstances(model, classes, properties): if inst not in instances and str(inst) != spec_url: instances.append(inst) for i in findStatements(model, None, rdf.type, None): - if ((not isResource(getSubject(i))) + if ( + (not isResource(getSubject(i))) or (getSubject(i) in classes) or (getSubject(i) in instances) - or (getSubject(i) in properties)): + or (getSubject(i) in properties) + ): continue full_uri = str(getSubject(i)) - if (full_uri.startswith(spec_ns_str)): + if full_uri.startswith(spec_ns_str): instances.append(getSubject(i)) return instances + def load_tags(path, docdir): "Build a (symbol => URI) map from a Doxygen tag file." @@ -1009,45 +1191,175 @@ def load_tags(path, docdir): def getChildText(elt, tagname): "Return the content of the first child node with a certain tag name." for e in elt.childNodes: - if e.nodeType == xml.dom.Node.ELEMENT_NODE and e.tagName == tagname: + if ( + e.nodeType == xml.dom.Node.ELEMENT_NODE + and e.tagName == tagname + ): return e.firstChild.nodeValue - return '' - - def linkTo(sym, url): - return '<span><a href="%s/%s">%s</a></span>' % (docdir, url, sym) - - tagdoc = xml.dom.minidom.parse(path) - root = tagdoc.documentElement + return "" + + def linkTo(filename, anchor, sym): + if anchor: + return '<span><a href="%s/%s#%s">%s</a></span>' % ( + docdir, + filename, + anchor, + sym, + ) + else: + return '<span><a href="%s/%s">%s</a></span>' % ( + docdir, + filename, + sym, + ) + + tagdoc = xml.dom.minidom.parse(path) + root = tagdoc.documentElement linkmap = {} for cn in root.childNodes: - if (cn.nodeType == xml.dom.Node.ELEMENT_NODE - and cn.tagName == 'compound' - and cn.getAttribute('kind') != 'page'): + if ( + cn.nodeType == xml.dom.Node.ELEMENT_NODE + and cn.tagName == "compound" + and cn.getAttribute("kind") != "page" + ): + + name = getChildText(cn, "name") + filename = getChildText(cn, "filename") + anchor = getChildText(cn, "anchor") + if not filename.endswith(".html"): + filename += ".html" + + if cn.getAttribute("kind") != "group": + linkmap[name] = linkTo(filename, anchor, name) + + prefix = "" + if cn.getAttribute("kind") == "struct": + prefix = name + "::" + + members = cn.getElementsByTagName("member") + for m in members: + mname = prefix + getChildText(m, "name") + mafile = getChildText(m, "anchorfile") + manchor = getChildText(m, "anchor") + linkmap[mname] = linkTo(mafile, manchor, mname) - name = getChildText(cn, 'name') - filename = getChildText(cn, 'filename') - if not filename.endswith('.html'): - filename += '.html' + return linkmap - linkmap[name] = linkTo(name, filename) - prefix = '' - if cn.getAttribute('kind') != 'file': - prefix = name + '::' +def writeIndex(model, specloc, index_path, root_path, root_uri): + # Get extension URI + ext_node = model.value(None, rdf.type, lv2.Specification) + if not ext_node: + ext_node = model.value(None, rdf.type, owl.Ontology) + if not ext_node: + print("no extension found in %s" % bundle) + sys.exit(1) - members = cn.getElementsByTagName('member') - for m in members: - mname = prefix + getChildText(m, 'name') - mafile = getChildText(m, 'anchorfile') - manchor = getChildText(m, 'anchor') - linkmap[mname] = linkTo( - mname, '%s#%s' % (mafile, manchor)) + ext = str(ext_node) - return linkmap + # Get version + minor = 0 + micro = 0 + try: + minor = int(model.value(ext_node, lv2.minorVersion, None)) + micro = int(model.value(ext_node, lv2.microVersion, None)) + except Exception: + print("warning: %s: failed to find version for %s" % (bundle, ext)) + + # Get date + date = None + for r in model.triples([ext_node, doap.release, None]): + revision = model.value(r[2], doap.revision, None) + if str(revision) == ("%d.%d" % (minor, micro)): + date = model.value(r[2], doap.created, None) + break + + # Verify that this date is the latest + for r in model.triples([ext_node, doap.release, None]): + this_date = model.value(r[2], doap.created, None) + if this_date > date: + print( + "warning: %s revision %d.%d (%s) is not the latest release" + % (ext_node, minor, micro, date) + ) + break + + # Get name and short description + name = model.value(ext_node, doap.name, None) + shortdesc = model.value(ext_node, doap.shortdesc, None) + + # Chop 'LV2' prefix from name for cleaner index + if name.startswith("LV2 "): + name = name[4:] + + # Find relative link target + if root_uri and ext_node.startswith(root_uri): + target = ext_node[len(root_uri) :] + ".html" + else: + target = os.path.relpath(ext_node, root_path) + ".html" + + stem = os.path.splitext(os.path.basename(target))[0] + + # Specification (comment is to act as a sort key) + row = '<tr><!-- %s --><td><a rel="rdfs:seeAlso" href="%s">%s</a></td>' % ( + b, + target, + name, + ) + + # API + row += "<td>" + row += '<a rel="rdfs:seeAlso" href="../doc/html/group__%s.html">%s</a>' % ( + stem, + name, + ) + row += "</td>" + + # Description + if shortdesc: + row += "<td>" + str(shortdesc) + "</td>" + else: + row += "<td></td>" -def specgen(specloc, indir, style_uri, docdir, tags, instances=False, offline=False): + # Version + version_str = "%s.%s" % (minor, micro) + if minor == 0 or (micro % 2 != 0): + row += '<td><span style="color: red">' + version_str + "</span></td>" + else: + row += "<td>" + version_str + "</td>" + + # Status + deprecated = model.value(ext_node, owl.deprecated, None) + if minor == 0: + row += '<td><span class="error">Experimental</span></td>' + elif deprecated and str(deprecated[2]) != "false": + row += '<td><span class="warning">Deprecated</span></td>' + elif micro % 2 == 0: + row += '<td><span class="success">Stable</span></td>' + + row += "</tr>" + + index = open(index_path, "w") + index.write(row) + index.close() + + +def specgen( + specloc, + indir, + style_uri, + docdir, + tags, + opts, + instances=False, + root_link=None, + index_path=None, + root_path=None, + root_uri=None, +): """The meat and potatoes: Everything starts here.""" + global spec_bundle global spec_url global spec_ns_str global spec_ns @@ -1056,6 +1368,7 @@ def specgen(specloc, indir, style_uri, docdir, tags, instances=False, offline=Fa global specgendir global linkmap + spec_bundle = "file://%s/" % os.path.abspath(os.path.dirname(specloc)) specgendir = os.path.abspath(indir) # Template @@ -1063,53 +1376,62 @@ def specgen(specloc, indir, style_uri, docdir, tags, instances=False, offline=Fa template = None f = open(temploc, "r") template = f.read() + f.close() # Load code documentation link map from tags file linkmap = load_tags(tags, docdir) m = rdflib.ConjunctiveGraph() - manifest_path = os.path.join(os.path.dirname(specloc), 'manifest.ttl') + manifest_path = os.path.join(os.path.dirname(specloc), "manifest.ttl") if os.path.exists(manifest_path): - m.parse(manifest_path, format='n3') - m.parse(specloc, format='n3') + m.parse(manifest_path, format="n3") + m.parse(specloc, format="n3") - bundle_path = os.path.split(specloc[specloc.find(':') + 1:])[0] - abs_bundle_path = os.path.abspath(bundle_path) spec_url = getOntologyNS(m) spec = rdflib.URIRef(spec_url) - # Parse all seeAlso files in the bundle - for uri in specProperties(m, spec, rdfs.seeAlso): - if uri[:7] == 'file://': - path = uri[7:] - if (path != os.path.abspath(specloc) - and path.endswith('.ttl')): - m.parse(path, format='n3') + # Load all seeAlso files recursively + seeAlso = set() + done = False + while not done: + done = True + for uri in specProperties(m, spec, rdfs.seeAlso): + if uri[:7] == "file://": + path = uri[7:] + if ( + path != os.path.abspath(specloc) + and path.endswith("ttl") + and path not in seeAlso + ): + seeAlso.add(path) + m.parse(path, format="n3") + done = False spec_ns_str = spec_url - if (spec_ns_str[-1] != "/" and spec_ns_str[-1] != "#"): + if spec_ns_str[-1] != "/" and spec_ns_str[-1] != "#": spec_ns_str += "#" spec_ns = rdflib.Namespace(spec_ns_str) namespaces = getNamespaces(m) - keys = namespaces.keys() - keys.sort() + keys = sorted(namespaces.keys()) prefixes_html = "<span>" for i in keys: uri = namespaces[i] - if uri.startswith('file:'): - continue; + if uri.startswith("file:"): + continue ns_list[str(uri)] = i - if (str(uri) == spec_url + '#' or - str(uri) == spec_url + '/' or - str(uri) == spec_url): + if ( + str(uri) == spec_url + "#" + or str(uri) == spec_url + "/" + or str(uri) == spec_url + ): spec_pre = i prefixes_html += '<a href="%s">%s</a> ' % (uri, i) prefixes_html += "</span>" if spec_pre is None: - print('No namespace prefix for %s defined' % specloc) + print("No namespace prefix for %s defined" % specloc) sys.exit(1) ns_list[spec_ns_str] = spec_pre @@ -1120,94 +1442,134 @@ def specgen(specloc, indir, style_uri, docdir, tags, instances=False, offline=Fa instalist = None if instances: - instalist = getInstances(m, classlist, proplist) - instalist.sort(lambda x, y: cmp(getShortName(x).lower(), getShortName(y).lower())) + instalist = sorted( + getInstances(m, classlist, proplist), + key=lambda x: getShortName(x).lower(), + ) azlist = buildIndex(m, classlist, proplist, instalist) # Generate Term HTML - termlist = docTerms('Property', proplist, m, classlist, proplist, instalist) - termlist = docTerms('Class', classlist, m, classlist, proplist, instalist) + termlist + classlist = docTerms("Class", classlist, m, classlist, proplist, instalist) + proplist = docTerms( + "Property", proplist, m, classlist, proplist, instalist + ) if instances: - termlist += docTerms('Instance', instalist, m, classlist, proplist, instalist) - - template = template.replace('@NAME@', specProperty(m, spec, doap.name)) - template = template.replace('@SUBTITLE@', specProperty(m, spec, doap.shortdesc)) - template = template.replace('@URI@', spec) - template = template.replace('@PREFIX@', spec_pre) - if spec_pre == 'lv2': - template = template.replace('@XMLNS@', '') + instlist = docTerms( + "Instance", instalist, m, classlist, proplist, instalist + ) + + termlist = "" + if classlist: + termlist += '<div class="section">' + termlist += '<h2><a id="ref-classes" />Classes</h2>' + classlist + termlist += "</div>" + + if proplist: + termlist += '<div class="section">' + termlist += '<h2><a id="ref-properties" />Properties</h2>' + proplist + termlist += "</div>" + + if instlist: + termlist += '<div class="section">' + termlist += '<h2><a id="ref-instances" />Instances</h2>' + instlist + termlist += "</div>" + + name = specProperty(m, spec, doap.name) + title = name + if root_link: + name = '<a href="%s">%s</a>' % (root_link, name) + + template = template.replace("@TITLE@", title) + template = template.replace("@NAME@", name) + template = template.replace( + "@SHORT_DESC@", specProperty(m, spec, doap.shortdesc) + ) + template = template.replace("@URI@", spec) + template = template.replace("@PREFIX@", spec_pre) + if spec_pre == "lv2": + template = template.replace("@XMLNS@", "") else: - template = template.replace('@XMLNS@', ' xmlns:%s="%s"' % (spec_pre, spec_ns_str)) + template = template.replace( + "@XMLNS@", ' xmlns:%s="%s"' % (spec_pre, spec_ns_str) + ) filename = os.path.basename(specloc) - basename = filename[0:filename.rfind('.')] - - template = template.replace('@STYLE_URI@', style_uri) - template = template.replace('@PREFIXES@', str(prefixes_html)) - template = template.replace('@BASE@', spec_ns_str) - template = template.replace('@AUTHORS@', specAuthors(m, spec)) - template = template.replace('@INDEX@', azlist) - template = template.replace('@REFERENCE@', termlist) - template = template.replace('@FILENAME@', filename) - template = template.replace('@HEADER@', basename + '.h') - template = template.replace('@MAIL@', 'devel@lists.lv2plug.in') - template = template.replace('@HISTORY@', specHistory(m, spec)) + basename = filename[0 : filename.rfind(".")] + + template = template.replace("@STYLE_URI@", style_uri) + template = template.replace("@PREFIXES@", str(prefixes_html)) + template = template.replace("@BASE@", spec_ns_str) + template = template.replace("@AUTHORS@", specAuthors(m, spec)) + template = template.replace("@INDEX@", azlist) + template = template.replace("@REFERENCE@", termlist) + template = template.replace("@FILENAME@", filename) + template = template.replace("@HEADER@", basename + ".h") + template = template.replace("@HISTORY@", specHistory(m, spec)) + + mail_row = "" + if "list_email" in opts: + mail_row = '<tr><th>Discuss</th><td><a href="mailto:%s">%s</a>' % ( + opts["list_email"], + opts["list_email"], + ) + if "list_page" in opts: + mail_row += ' <a href="%s">(subscribe)</a>' % opts["list_page"] + mail_row += "</td></tr>" + template = template.replace("@MAIL@", mail_row) version = specVersion(m, spec) # (minor, micro, date) date_string = version[2] if date_string == "": date_string = "Undated" - version_string = "%s.%s (%s)" % (version[0], version[1], date_string) - experimental = (version[0] == 0 or version[1] % 2 == 1) + version_string = "%s.%s" % (version[0], version[1]) + experimental = version[0] == 0 or version[1] % 2 == 1 if experimental: version_string += ' <span class="warning">EXPERIMENTAL</span>' - deprecated = findOne(m, rdflib.URIRef(spec_url), owl.deprecated, None) - if deprecated and str(deprecated[2]).find("true") > 0: + if isDeprecated(m, rdflib.URIRef(spec_url)): version_string += ' <span class="warning">DEPRECATED</span>' - template = template.replace('@REVISION@', version_string) + template = template.replace("@VERSION@", version_string) - file_list = '' - see_also_files = specProperties(m, spec, rdfs.seeAlso) - see_also_files.sort() - for f in see_also_files: - uri = str(f) - if uri[:7] == 'file://': - uri = uri[7:] - if uri[:len(abs_bundle_path)] == abs_bundle_path: - uri = uri[len(abs_bundle_path) + 1:] - else: - continue # Skip seeAlso file outside bundle + content_links = "" + if docdir is not None: + content_links = '<li><a href="%s">API</a></li>' % os.path.join( + docdir, "group__%s.html" % basename + ) + template = template.replace("@CONTENT_LINKS@", content_links) - if offline: - entry = uri - else: - entry = '<a href="%s">%s</a>' % (uri, uri) - if uri.endswith('.h') or uri.endswith('.hpp'): - name = os.path.basename(uri) - entry += ' - <a href="%s">Documentation</a> ' % ( - docdir + '/' + name.replace('.', '_8') + '.html') - file_list += '<li>%s</li>' % entry - else: - file_list += '<li>%s</li>' % entry + docs = getDetailedDocumentation( + m, rdflib.URIRef(spec_url), classlist, proplist, instalist + ) + template = template.replace("@DESCRIPTION@", docs) - files = '' - if file_list: - files += '<li>Files<ul>%s</ul></li>' % file_list + now = int(os.environ.get("SOURCE_DATE_EPOCH", time.time())) + build_date = datetime.datetime.utcfromtimestamp(now) + template = template.replace("@DATE@", build_date.strftime("%F")) + template = template.replace("@TIME@", build_date.strftime("%F %H:%M UTC")) - template = template.replace('@FILES@', files) + # Write index row + if index_path is not None: + writeIndex(m, specloc, index_path, root_path, root_uri) - comment = getComment(m, rdflib.URIRef(spec_url), classlist, proplist, instalist) - if comment != '': - template = template.replace('@COMMENT@', comment) - else: - template = template.replace('@COMMENT@', '') - - template = template.replace('@TIME@', datetime.datetime.utcnow().strftime('%F %H:%M UTC')) + # Validate complete output page + try: + oldcwd = os.getcwd() + os.chdir(specgendir) + etree.fromstring( + template.replace( + '"http://www.w3.org/MarkUp/DTD/xhtml-rdfa-1.dtd"', + '"DTD/xhtml-rdfa-1.dtd"', + ).encode("utf-8"), + etree.XMLParser(dtd_validation=True, no_network=True), + ) + except Exception as e: + sys.stderr.write("error: Validation failed for %s: %s" % (specloc, e)) + finally: + os.chdir(oldcwd) return template @@ -1215,7 +1577,7 @@ def specgen(specloc, indir, style_uri, docdir, tags, instances=False, offline=Fa def save(path, text): try: f = open(path, "w") - f.write(text.encode("utf-8")) + f.write(text) f.flush() f.close() except Exception: @@ -1227,7 +1589,7 @@ def getNamespaces(m): """Return a prefix:URI dictionary of all namespaces seen during parsing""" nspaces = {} for prefix, uri in m.namespaces(): - if not re.match('default[0-9]*', prefix) and not prefix == 'xml': + if not re.match("default[0-9]*", prefix) and not prefix == "xml": # Skip silly default namespaces added by rdflib nspaces[prefix] = uri return nspaces @@ -1242,7 +1604,7 @@ def getOntologyNS(m): if not isBlank(getSubject(s)): ns = str(getSubject(s)) - if (ns == None): + if ns is None: sys.exit("Impossible to get ontology's namespace") else: return ns @@ -1250,53 +1612,157 @@ def getOntologyNS(m): def usage(): script = os.path.basename(sys.argv[0]) - print("""Usage: %s ONTOLOGY INDIR STYLE OUTPUT [DOCDIR TAGS] [FLAGS] - - ONTOLOGY : Path to ontology file - INDIR : Input directory containing template.html and style.css - STYLE : Stylesheet URI - OUTPUT : HTML output path - DOCDIR : Doxygen HTML directory - TAGS : Doxygen tags file - - Optional flags: - -i : Document class/property instances (disabled by default) - -p PREFIX : Set ontology namespace prefix from command line - -Example: - %s lv2_foos.ttl template.html style.css lv2_foos.html ../doc -i -p foos -""" % (script, script)) - sys.exit(-1) + return "Usage: %s ONTOLOGY_TTL OUTPUT_HTML [OPTION]..." % script if __name__ == "__main__": """Ontology specification generator tool""" - args = sys.argv[1:] - if (len(args) < 3): - usage() - else: - ontology = "file:" + str(args[0]) - indir = args[1] - style = args[2] - output = args[3] - docdir = None - tags = None - if len(args) > 5: - docdir = args[4] - tags = args[5] - - # Flags - instances = False - if len(args) > 6: - flags = args[6:] - i = 0 - while i < len(flags): - if flags[i] == '-i': - instances = True - elif flags[i] == '-p': - spec_pre = flags[i + 1] - i += 1 - i += 1 - - save(output, specgen(ontology, indir, style, docdir, tags, instances=instances)) + indir = os.path.abspath(os.path.dirname(sys.argv[0])) + if not os.path.exists(os.path.join(indir, "template.html")): + indir = os.path.join(os.path.dirname(indir), "share", "lv2specgen") + + opt = optparse.OptionParser( + usage=usage(), + description="Write HTML documentation for an RDF ontology.", + ) + opt.add_option( + "--list-email", + type="string", + dest="list_email", + help="Mailing list email address", + ) + opt.add_option( + "--list-page", + type="string", + dest="list_page", + help="Mailing list info page address", + ) + opt.add_option( + "--template-dir", + type="string", + dest="template_dir", + default=indir, + help="Template directory", + ) + opt.add_option( + "--style-uri", + type="string", + dest="style_uri", + default="style.css", + help="Stylesheet URI", + ) + opt.add_option( + "--docdir", + type="string", + dest="docdir", + default=None, + help="Doxygen output directory", + ) + opt.add_option( + "--index", + type="string", + dest="index_path", + default=None, + help="Index row output file", + ) + opt.add_option( + "--tags", + type="string", + dest="tags", + default=None, + help="Doxygen tags file", + ) + opt.add_option( + "-r", + "--root-path", + type="string", + dest="root_path", + default="", + help="Root path", + ) + opt.add_option( + "-R", + "--root-uri", + type="string", + dest="root_uri", + default="", + help="Root URI", + ) + opt.add_option( + "-p", + "--prefix", + type="string", + dest="prefix", + help="Specification Turtle prefix", + ) + opt.add_option( + "-i", + "--instances", + action="store_true", + dest="instances", + help="Document instances", + ) + opt.add_option( + "--copy-style", + action="store_true", + dest="copy_style", + help="Copy style from template directory to output directory", + ) + + (options, args) = opt.parse_args() + opts = vars(options) + + if len(args) < 2: + opt.print_help() + sys.exit(-1) + + spec_pre = options.prefix + ontology = "file:" + str(args[0]) + output = args[1] + index_path = options.index_path + docdir = options.docdir + tags = options.tags + + out = "." + spec = args[0] + path = os.path.dirname(spec) + outdir = os.path.abspath(os.path.join(out, path)) + + bundle = str(outdir) + b = os.path.basename(outdir) + + if not os.access(os.path.abspath(spec), os.R_OK): + print("warning: extension %s has no %s.ttl file" % (b, b)) + sys.exit(1) + + # Root link + root_path = opts["root_path"] + root_uri = opts["root_uri"] + root_link = os.path.join(root_path, "index.html") + + # Generate spec documentation + specdoc = specgen( + spec, + indir, + opts["style_uri"], + docdir, + tags, + opts, + instances=True, + root_link=root_link, + index_path=index_path, + root_path=root_path, + root_uri=root_uri, + ) + + # Save to HTML output file + save(output, specdoc) + + if opts["copy_style"]: + import shutil + + shutil.copyfile( + os.path.join(indir, "style.css"), + os.path.join(os.path.dirname(output), "style.css"), + ) diff --git a/lv2specgen/template.html b/lv2specgen/template.html index 691f6fd..ed9d6fb 100644 --- a/lv2specgen/template.html +++ b/lv2specgen/template.html @@ -1,3 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML+RDFa 1.0//EN" "http://www.w3.org/MarkUp/DTD/xhtml-rdfa-1.dtd"> <html about="@URI@" xmlns="http://www.w3.org/1999/xhtml" @@ -9,85 +10,86 @@ @XMLNS@ xml:lang="en"> <head> - <title>@NAME@</title> + <title>@TITLE@</title> <meta http-equiv="content-type" content="text/xhtml+xml; charset=utf-8" /> <meta name="generator" content="lv2specgen" /> <link href="@STYLE_URI@" rel="stylesheet" type="text/css" /> </head> <body> - <!-- HEADER --> - <div id="header"> - <h1 id="title">@NAME@</h1> - <span id="subtitle">@SUBTITLE@</span> - <table id="meta"> - <tr><th>URI</th><td><a href="@URI@">@URI@</a></td></tr> - <tr><th>Version</th><td>@REVISION@</td></tr> - <tr><th>Prefixes</th><td>@PREFIXES@</td></tr> - <tr><th>Discuss</th><td> - <a href="mailto:@MAIL@">@MAIL@</a> - (<a href="http://lists.lv2plug.in/listinfo.cgi/devel-lv2plug.in">subscribe</a>) - </td></tr> - @AUTHORS@ - </table> - </div> + <!-- HEADER --> + <div id="topbar"> + <div id="header"> + <div id="titlebox"> + <h1 id="title">@NAME@</h1> + <div id="shortdesc">@SHORT_DESC@</div> + </div> + <div id="metabox"> + <table id="meta"> + <tr><th>ID</th><td><a href="@URI@">@URI@</a></td></tr> + <tr><th>Version</th><td>@VERSION@</td></tr> + <tr><th>Date</th><td>@DATE@</td></tr> + @MAIL@ + @AUTHORS@ + </table> + </div> + </div> + </div> - <h2 class="sec">Contents</h2> - <div class="content"> - <ul> - <li><a href="#sec-description">Description</a></li> - <li><a href="#sec-index">Index</a></li> - <li><a href="#sec-documentation">Documentation</a></li> - <li><a href="#sec-releases">Releases</a></li> - @FILES@ - </ul> - </div> + <div id="content"> + <div id="contentsbox"> + <!-- Contents: --> + <ul id="contents"> + <!-- <li><a href="#sec-description">Description</a></li> --> + <li><a href="#sec-index">Index</a></li> + <li><a href="#sec-history">History</a></li> + @CONTENT_LINKS@ + </ul> + </div> - <!-- DESCRIPTION --> - <h2 class="sec" id="sec-description">Description</h2> - <div class="content">@COMMENT@</div> + <!-- DESCRIPTION --> + <div class="section">@DESCRIPTION@</div> - <!-- INDEX --> - <h2 class="sec" id="sec-index">Index</h2> - <div class="content"> - @INDEX@ - </div> + <!-- INDEX --> + <h2 id="sec-index">Index</h2> + <div class="section"> + @INDEX@ + </div> - <!-- DOCUMENTATION --> - <h2 class="sec" id="sec-documentation">Documentation</h2> - <div class="content"> - @REFERENCE@ - </div> + <!-- REFERENCE --> + <div class="section"> + @REFERENCE@ + </div> - <!-- RELEASES --> - <h2 class="sec" id="sec-releases">Releases</h2> - <div class="content"> - @HISTORY@ - </div> + <!-- HISTORY --> + <h2 id="sec-history">History</h2> + <div class="section"> + @HISTORY@ + </div> - <!-- FOOTER --> - <div id="footer"> - <div> - This document is available under the - <a about="" rel="license" href="http://creativecommons.org/licenses/by-sa/3.0/"> - Creative Commons Attribution-ShareAlike License - </a> - </div> - <div> - Valid - <a about="" rel="dct:conformsTo" resource="http://www.w3.org/TR/rdfa-syntax" - href="http://validator.w3.org/check?uri=referer"> - XHTML+RDFa - </a> - and - <a about="" rel="dct:conformsTo" resource="http://www.w3.org/TR/CSS2" - href="http://jigsaw.w3.org/css-validator/check/referer"> - CSS - </a> - generated from @FILENAME@ by <a href="http://drobilla.net/software/lv2specgen">lv2specgen</a> - </div> - </div> + <!-- FOOTER --> + <div id="footer"> + <div> + This document is available under the + <a about="" rel="license" href="http://creativecommons.org/licenses/by-sa/3.0/"> + Creative Commons Attribution-ShareAlike License + </a> + </div> + <div> + Valid + <a about="" rel="dct:conformsTo" resource="http://www.w3.org/TR/rdfa-syntax" + href="http://validator.w3.org/check?uri=referer"> + XHTML+RDFa + </a> + and + <a about="" rel="dct:conformsTo" resource="http://www.w3.org/TR/CSS2" + href="http://jigsaw.w3.org/css-validator/check/referer"> + CSS + </a> + generated from @FILENAME@ by lv2specgen + </div> + </div> + </div> </body> </html> - |