Last active
August 9, 2021 07:45
-
-
Save tpluscode/5d9c6983004c1c9ec91f to your computer and use it in GitHub Desktop.
OWL => C# T4 template
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | |
<ItemGroup> | |
<!-- This way the FOAF.tt will generate a Foaf class with fields for prefix, base URI and all vocabulary members --> | |
<Compile Include="Ontologies\FOAF.cs"> | |
<AutoGen>True</AutoGen> | |
<DesignTime>True</DesignTime> | |
<DependentUpon>FOAF.tt</DependentUpon> | |
</Compile> | |
</ItemGroup> | |
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<# // Create exact file grouped with your OWL/XML file. See example below of csproj structure #> | |
<#@ assembly name="System.Core" #> | |
<#@ assembly name="System.Xml" #> | |
<#@ import namespace="System.Xml" #> | |
<#@ include file="Vocabulary.tt" #><# | |
CreateVocabulary(); | |
#> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<#@ template debug="false" hostspecific="true" language="C#" #> | |
<#@ assembly name="System.Core" #> | |
<#@ assembly name="System.Xml" #> | |
<#@ assembly name="EnvDTE" #> | |
<#@ import namespace="System.Collections.Generic" #> | |
<#@ import namespace="System.Linq" #> | |
<#@ import namespace="System.Text.RegularExpressions" #> | |
<#@ import namespace="System.Xml" #> | |
<#@ import namespace="Microsoft.VisualStudio.TextTemplating" #> | |
<#@ output extension=".cs" #><#+ | |
public void CreateVocabulary() | |
{ | |
string prefix; | |
string ns; | |
string uri; | |
string className; | |
XmlNamespaceManager namespaceManager; | |
bool isRDFMode; | |
XmlDocument ontology=Initialize(out prefix,out uri,out ns,out className,out namespaceManager,out isRDFMode); | |
#> | |
// <auto-generated /> | |
using System; | |
namespace <#=ns #> | |
{ | |
/// <summary><#=GetTitle(ontology.DocumentElement,namespaceManager,isRDFMode) #> (<#=uri #>).</summary> | |
public static partial class <#=className #> | |
{ | |
/// <summary> | |
/// <#=className.ToLower() #> | |
/// </summary> | |
public const string Prefix="<#=className.ToLower() #>"; | |
/// <summary> | |
/// <#=uri #> | |
/// </summary> | |
public const string BaseUri="<#=uri #>"; | |
<#+ | |
IEnumerable<XmlNode> classes=GetNodes(ontology.DocumentElement,namespaceManager,"rdfs:Class",isRDFMode).Union( | |
GetNodes(ontology.DocumentElement,namespaceManager,"owl:Class",isRDFMode)); | |
foreach (XmlNode classNode in classes) | |
{#> | |
/// <summary> | |
/// <#=GetDescription(classNode, namespaceManager) #> | |
/// </summary> | |
public const string <#=GetTermName(classNode,namespaceManager) #> = BaseUri + "<#=GetTermName(classNode,namespaceManager) #>"; | |
<#+ } | |
IEnumerable<XmlNode> properties=GetNodes(ontology.DocumentElement,namespaceManager,"rdf:Property",isRDFMode).Union( | |
GetNodes(ontology.DocumentElement,namespaceManager,"owl:DatatypeProperty",isRDFMode)).Union( | |
GetNodes(ontology.DocumentElement,namespaceManager,"owl:ObjectProperty",isRDFMode)).Union( | |
GetNodes(ontology.DocumentElement,namespaceManager,"owl:AnnotationProperty",isRDFMode)).Union( | |
GetNodes(ontology.DocumentElement,namespaceManager,"hydra:Link",isRDFMode)); | |
foreach (XmlNode propertyNode in properties) | |
{#> | |
/// <summary> | |
/// <#=GetDescription(propertyNode, namespaceManager) #> | |
/// </summary> | |
public const string <#=GetTermName(propertyNode,namespaceManager) #> = BaseUri + "<#=GetTermName(propertyNode,namespaceManager).Replace("@",System.String.Empty) #>"; | |
<#+ } | |
string rdf=namespaceManager.LookupNamespace("rdf"); | |
foreach (XmlNode classNode in classes) | |
{ | |
string typeName=StandardizeTerm((classNode.Attributes["about",rdf]!=null?classNode.Attributes["about",rdf]:classNode.Attributes["ID",rdf]).Value,namespaceManager); | |
if ((typeName!="rdfs:Class")&&(typeName!="rdf:Property")&&(typeName!="owl:Class")&&((!typeName.StartsWith("owl:"))&&(!typeName.EndsWith("Property")))) | |
{ | |
IEnumerable<XmlNode> namedInstances=GetNodes(ontology.DocumentElement,namespaceManager,typeName,isRDFMode); | |
foreach (XmlNode namedInstanceNode in namedInstances) | |
{#> | |
/// <summary> | |
/// <#=GetDescription(namedInstanceNode, namespaceManager) #> | |
/// </summary> | |
public const string <#=GetTermName(namedInstanceNode,namespaceManager) #> = BaseUri + "<#=GetTermName(namedInstanceNode,namespaceManager).Replace("@",System.String.Empty) #>"; | |
<#+ } | |
} | |
} | |
#> | |
} | |
}<#+ | |
} | |
private XmlDocument Initialize(out string prefix,out string uri,out string ns,out string className,out XmlNamespaceManager namespaceManager,out bool isRDFMode) | |
{ | |
prefix=System.String.Empty; | |
uri=System.String.Empty; | |
ns=System.String.Empty; | |
className=System.String.Empty; | |
namespaceManager=null; | |
isRDFMode=false; | |
string fileName; | |
string rdfFile=System.IO.Path.ChangeExtension(this.Host.TemplateFile, "rdf"); | |
string owlFile=System.IO.Path.ChangeExtension(this.Host.TemplateFile, "owl"); | |
if(System.IO.File.Exists(rdfFile)) | |
{ | |
fileName = rdfFile; | |
} | |
else if(System.IO.File.Exists(owlFile)) | |
{ | |
fileName = owlFile; | |
} | |
else | |
{ | |
throw new Exception(string.Format("Cannot find ontology file. Tried {0} and {1}", owlFile, rdfFile)); | |
} | |
XmlDocument result=new XmlDocument(); | |
result.Load(fileName); | |
prefix=System.IO.Path.GetFileNameWithoutExtension(this.Host.TemplateFile); | |
className=(prefix.Count(item => Char.IsUpper(item))==prefix.Length?prefix.Substring(0,1).ToUpper()+prefix.Substring(1).ToLower():prefix); | |
prefix=prefix.ToLower(); | |
IDictionary<string,string> namespaces=result.DocumentElement.CreateNavigator().GetNamespacesInScope(XmlNamespaceScope.All); | |
uri=namespaces[prefix]; | |
var nsHint = System.Runtime.Remoting.Messaging.CallContext.LogicalGetData("NamespaceHint"); | |
ns = (nsHint ?? "Vocab").ToString(); | |
isRDFMode=(System.IO.Path.GetExtension(fileName).Substring(1).ToLower()=="rdf"); | |
namespaceManager=new XmlNamespaceManager(result.NameTable); | |
namespaceManager.AddNamespace("rdf","http://www.w3.org/1999/02/22-rdf-syntax-ns#"); | |
namespaceManager.AddNamespace("rdfs","http://www.w3.org/2000/01/rdf-schema#"); | |
namespaceManager.AddNamespace("owl","http://www.w3.org/2002/07/owl#"); | |
namespaceManager.AddNamespace("dc","http://purl.org/dc/elements/1.1/"); | |
namespaceManager.AddNamespace("dcterms","http://purl.org/dc/terms/"); | |
namespaceManager.AddNamespace("skos","http://www.w3.org/2004/02/skos/core#"); | |
namespaceManager.AddNamespace("hydra","http://www.w3.org/ns/hydra/core#"); | |
foreach (KeyValuePair<string,string> @namespace in namespaces) | |
{ | |
if (System.String.IsNullOrEmpty(namespaceManager.LookupPrefix(@namespace.Value))) | |
{ | |
namespaceManager.AddNamespace(@namespace.Key,@namespace.Value); | |
} | |
} | |
namespaceManager.AddNamespace("base",namespaceManager.LookupNamespace(prefix)); | |
return result; | |
} | |
private string GetTermName(XmlNode node,XmlNamespaceManager namespaceManager) | |
{ | |
string result=null; | |
string rdf=namespaceManager.LookupNamespace("rdf"); | |
XmlAttribute attribute=node.Attributes["about",rdf]; | |
if (attribute==null) | |
{ | |
result=namespaceManager.LookupNamespace("base")+node.Attributes["ID",rdf].Value; | |
} | |
else | |
{ | |
result=attribute.Value; | |
} | |
if (result.IndexOf('#')!=-1) | |
{ | |
result=result.Substring(result.IndexOf('#')+1); | |
} | |
else if(result.Contains(":")) | |
{ | |
result=new Uri(result).Segments.Last(); | |
} | |
string[] keywords=new string[] { "object","class","readonly","abstract","private","default","as","using","event" }; | |
if (keywords.Contains(result)) | |
{ | |
result="@"+result; | |
} | |
return result; | |
} | |
private string GetDescription(XmlNode node,XmlNamespaceManager namespaceManager) | |
{ | |
string result = null; | |
XmlNode title=node.SelectSingleNode("*[(self::rdfs:comment) or (self::skos:definition)]",namespaceManager); | |
if (title!=null) | |
{ | |
result=title.InnerText; | |
} | |
else | |
{ | |
XmlAttribute attribute=node.Attributes["comment",namespaceManager.LookupNamespace("rdfs")]??(node.Attributes["definition",namespaceManager.LookupNamespace("skos")]); | |
if (attribute!=null) | |
{ | |
result=attribute.Value; | |
} | |
} | |
result = result ?? GetTermName(node, namespaceManager); | |
if(result != null) | |
{ | |
result = result.Replace(Environment.NewLine, " ").Replace("\n", " "); | |
} | |
return result; | |
} | |
private string GetTitle(XmlNode documentElement,XmlNamespaceManager namespaceManager,bool isRDFMode) | |
{ | |
XmlNode ontology=documentElement.SelectSingleNode((isRDFMode?"rdf:Description[rdf:type[@rdf:resource=\"http://www.w3.org/2002/07/owl#Ontology\"]]":"owl:Ontology"),namespaceManager); | |
string result=GetTermName(ontology,namespaceManager); | |
XmlNode title=ontology.SelectSingleNode("*[(self::rdfs:label) or (self::dc:title) or (self::dcterms:title)]",namespaceManager); | |
if (title!=null) | |
{ | |
result=title.InnerText; | |
} | |
else | |
{ | |
XmlAttribute attribute=ontology.Attributes["label",namespaceManager.LookupNamespace("rdfs")]??(ontology.Attributes["title",namespaceManager.LookupNamespace("dc")]??documentElement.Attributes["title",namespaceManager.LookupNamespace("dcterms")]); | |
if (attribute!=null) | |
{ | |
result=attribute.Value; | |
} | |
} | |
return result; | |
} | |
private IEnumerable<XmlNode> GetNodes(XmlNode node,XmlNamespaceManager namespaceManager,string name,bool isRDFMode) | |
{ | |
name=StandardizeTerm(name,namespaceManager); | |
XmlNodeList result=null; | |
if (isRDFMode) | |
{ | |
result=node.SelectNodes("rdf:Description[@rdf:about and rdf:type[@rdf:resource=\""+namespaceManager.LookupNamespace(name.Split(':')[0])+name.Split(':')[1]+"\"]]",namespaceManager); | |
} | |
else | |
{ | |
result=node.SelectNodes(name,namespaceManager); | |
} | |
string rdf = namespaceManager.LookupNamespace("rdf"); | |
string ns = namespaceManager.LookupNamespace("base"); | |
return from item in result.Cast<XmlNode>() | |
where HasAbout(item, rdf, ns) || HasID(item, rdf) | |
select item; | |
} | |
private static bool HasAbout(XmlNode item, string rdf, string ns) | |
{ | |
var about = item.Attributes["about", rdf]; | |
var isRelativeUri = about.Value.Contains(":") == false; | |
return about.Value.StartsWith(ns) || isRelativeUri; | |
} | |
private static bool HasID(XmlNode item, string rdf) | |
{ | |
return item.Attributes["ID", rdf] != null; | |
} | |
private string StandardizeTerm(string term,XmlNamespaceManager namespaceManager) | |
{ | |
if ((!Regex.IsMatch(term,"[^:]+://"))&&(!Regex.IsMatch(term,"[^:]+:[a-zA-Z]"))) | |
{ | |
term=namespaceManager.LookupNamespace("base")+term; | |
} | |
namespaceManager.Cast<string>().Where(item => item.Length>0).Select(item => term=term.Replace(namespaceManager.LookupNamespace(item),item+":")).ToList(); | |
return term; | |
} | |
#> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I never really attempted to make the script reusable. It is part of the build and the Rdf.Vocabularies package is only a way to distribute what was generated
TL;DR; of what's happening:
You should have no issues just reusing those scripts in your project. Or you could submit a PR to the package if yours is a shared vocabulary.