Skip to content

Instantly share code, notes, and snippets.

@tpluscode
Last active August 9, 2021 07:45
Show Gist options
  • Save tpluscode/5d9c6983004c1c9ec91f to your computer and use it in GitHub Desktop.
Save tpluscode/5d9c6983004c1c9ec91f to your computer and use it in GitHub Desktop.
OWL => C# T4 template
<?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>
<# // 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();
#>
<#@ 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;
}
#>
@binhtq1987
Copy link

hi,
where is the sample FOAF.rdf or FOAF.owl file?
thanks

@tpluscode
Copy link
Author

hi @binhtq1987. wow, 2016 gist :)

I believe that code from this gist would have been used in Rdf.Vocabularies

Note that the package has since been moved to .NET Standard and T4 is no longer used. You will find csx scripts in the repository which do the sam transformation

@binhtq1987
Copy link

Thanks Tomasz!
what if I have my own ontology file with turtle format (*.ttl), can I use Rdf.Vocabularies to generate the static class for vocabulary?
if I want to generate POCO from Classes and Properties from that ontology, will I right another new csx scripts to do that?

@tpluscode
Copy link
Author

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:

  1. run scripty during build: Rdf.Vocabularies/Rdf.Vocabularies.csproj#L26
  2. Rdf.Vocabularies/Vocabs.csx is a meta script which simply run transformation for every source file
    • can be any format parsed by dotNetRDF
    • note there are some parameters because vocabulary files are not made equals
  3. Rdf.Vocabularies/MakeVocab.csx script iterated the vocabulary terms and generates a C# class

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.

@binhtq1987
Copy link

Thanks so much, Tomasz!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment