Lesson Learned: Declaratively expressing relationships is good! It helps applications dynamically understand data. Interoperability is enhanced.
Corollary: Ontologies are languages intended for declaratively expressing relationships. Ontologies are good! They promote interoperability. Use ontologies!
<River id="Yangtze">
<length units="kilometer">6300</length>
</River>
<River id="Yangtze">
<length units="mile">3914</length>
</River>The two lengths are related by this mathematical
relationship (transformation):
kilometer = mile * 1.609344Neither RDFS nor OWL can express
this important relationship.
<Map id="M1">
<location>
<cartesian-coordinate>
<x units="kilometer">100</x>
<y units="kilometer">100</y>
</cartesian-coordinate>
</location>
</Map>
<Map id="M2">
<location>
<polar-coordinate>
<r units="kilometer">141.421</x>
<theta units="radian">0.7341</theta>
</polar-coordinate>
</location>
</Map>The two locations are related by this mathematical
formula:
x = r cos theta
y = r sin thetaAgain, neither RDFS nor OWL can express this
relationship.
<Comet id="Hale-Bopp">
<avg-speed units="miles-per-hour">93951.3</avg-speed>
</Comet>
<Comet id="Hale-Bopp">
<avg-speed units="kilometers-per-second">42.0</avg-speed>
</Comet>The two speeds are related by this mathematical
formula:
miles-per-hour = kilometers-per-sec * 3600 / 1.609344Neither
RDFS nor OWL can express this relationship.
<Toyota id="Tercel-95">
<mileage units="miles-per-gallon">29.0</mileage>
</Toyota>
<Toyota id="Tercel-95">
<mileage units="kilometers-per-liter">12.3</mileage>
</Toyota>The two fuel consumption rates are related by
this mathematical formula:
miles-per-gallon = kilometers-per-liter * 1.609344 / 3.785Neither
RDFS nor OWL can express this relationship.
Lesson Learned: There are many important relationships that cannot be expressed using the current ontology languages RDFS and OWL. Thus, the full potential for interoperability cannot be realized with the current form of RDFS and OWL.
How can relationships involving transformations be expressed? The purpose of this document is to provide a concrete approach to expressing these relationships, and for using these relationships.
Above we looked at the problem of stating the relationship of every possible pair. A better approach is to simply state the relationship to the canonical form. This reduces the complexity greatly (for "n" units, the complexity is n).
Further, even if it were possible to extend the languages to express the mathematical relationships there still remains the problem of executing the transformation. For example, suppose that an ontology declaratively expressed the formula to convert a polar coordinate to cartesian coordinate. And suppose an application received input data in polar coordinates, but needs it in cartesian coordinates. Suppose the ontology provides the conversion formula, and suppose the application dynamically retrieves the formula. The application may not be smart enough to dynamically convert the polar coordinates to cartesian coordinates. (In the general case, the problem for the application is to be able to dynamically convert an arbitrary coordinate system to another by using formulas that are dynamically provided. This is very difficult indeed.)
Lesson Learned: Simply expressing a mathematical formula in an ontology may not be very helpful to applications.
The approach is very simple:
<River rdf:ID="Yangtze">
<length>
<Length>
<value>6300000</value>
<units rdf:resource="#Meter"/>
</Length>
</length>
</River>The canonical form of the Length class is:
<owl:Class rdf:ID="Length">
<owlx:canonicalForm>
<owl:Class>
<owl:unionOf rdf:parseType="Collection">
<owl:Restriction>
<owl:onProperty rdf:resource="#value"/>
<owl:hasValue rdf:resource="http://www.w3.org/2001/XMLSchema#decimal"/>
</owl:Restriction>
<owl:Restriction>
<owl:onProperty rdf:resource="#units"/>
<owl:hasValue rdf:resource="#Length-Unit-of-Measure"/>
</owl:Restriction>
</owl:unionOf>
</owl:Class>
<owlx:IncludeFile>
<rdf:type rdf:resource="XSLT2.0"/>
<owlx:location rdf:resource="Length-Include-File.xsl"/>
</owlx:IncludeFile>
</owlx:canonicalForm>
</owl:Class>This is read as: "The canonical form of the
Length class are instances that have a 'value' property in canonical decimal
form, and a 'units' property in canonical Length-Unit-of-Measure form. An
include file for converting Length classes to canonical form may be found in
Length-Include-File.xsl, and it is implemented using XSLT2.0"
The canonical form of xsd:decimal is defined by the XML Schema specification.
<owl:Class rdf:ID="Length-Unit-of-Measure">
<owlx:canonicalForm rdf:resource="#Meter"/>
</owl:Class>This class does not have an
<IncludeFile> element. A <canonicalForm> element may contain zero or
more <IncludeFile> elements. The Length-Unit-of-Measure class does not
have a <canonicalForm> element, indicating that there is no function
available specifically for converting Length-Unit-of-Measure to canonical form.
This makes sense, since this class is never used - only its subclasses are used.
Meter, Kilometer, Mile, etc are all subclasses of Length-Unit-of-Measure:
<owl:Class rdf:ID="Meter">
<rdfs:subClassOf rdf:resource="#Length-Unit-of-Measure"/>
</owl:Class>
<owl:Class rdf:ID="Kilometer">
<rdfs:subClassOf rdf:resource="#Length-Unit-of-Measure"/>
</owl:Class>
<owl:Class rdf:ID="Mile">
<rdfs:subClassOf rdf:resource="#Length-Unit-of-Measure"/>
</owl:Class>The units property is defined to have any
Length-Unit-of-Measure value:
<owl:ObjectProperty rdf:ID="units">
<rdfs:range rdf:resource="#Length-Unit-of-Measure"/>
</owl:ObjectProperty>Thus, this is a valid instance
document:
<River rdf:ID="Yangtze">
<length>
<Length>
<value>6300</value>
<units rdf:resource="#Kilometer"/>
</Length>
</length>
</River>However, as the ontology shows, Length is not in
canonical form.
<xsl:function name="len:Length" as="element()">
<xsl:param name="length" as="item()"/>
<xsl:choose>
<xsl:when test="$length/len:units/@rdf:resource='http://www.xfront.com/owl/ontologies/Length/#Kilometer'">
<Length xmlns="http://www.xfront.com/owl/ontologies/Length/#">
<value><xsl:value-of select="$length/len:value * 1000"/></value>
<units rdf:resource="http://www.xfront.com/owl/ontologies/Length/#Meter"/>
</Length>
</xsl:when>
<xsl:when test="$length/len:units/@rdf:resource='http://www.xfront.com/owl/ontologies/Length/#Mile'">
<Length xmlns="http://www.xfront.com/owl/ontologies/Length/#">
<value><xsl:value-of select="$length/len:value * 1609.344"/></value>
<units rdf:resource="http://www.xfront.com/owl/ontologies/Length/#Meter"/>
</Length>
</xsl:when>
<xsl:when test="$length/len:units/@rdf:resource='http://www.xfront.com/owl/ontologies/Length/#Furlong'">
<Length xmlns="http://www.xfront.com/owl/ontologies/Length/#">
<value><xsl:value-of select="$length/len:value * 201.168"/></value>
<units rdf:resource="http://www.xfront.com/owl/ontologies/Length/#Meter"/>
</Length>
</xsl:when>
<xsl:otherwise>
<xsl:sequence select="$length"/>
</xsl:otherwise>
</xsl:choose>
</xsl:function>The name of the function is "Length",
which is in the units-of-measure namespace. The input parameter to the function
is a Length node, such as:
<Length>
<value>6300</value>
<units rdf:resource="#Kilometer"/>
</Length>If the value of "units" is Kilometer then the
function converts the data to canonical form by returning an identical XML
fragment, except the content of the <value> element has been multiplied by
1000, and <units> is set to have the value #Meter.
For example, if the function is invoked with the above Length it will return:
<Length>
<value>6300000</value>
<units rdf:resource="#Meter"/>
</Length>If the value of "units" is Mile then the
function converts the input to canonical form by returning an identical XML
fragment, except the content of the <value> element has been multiplied by
1609.344, and <units> is set to have the value #Meter.
A complete version of this function would have code to convert any length unit-of-measure into canonical form.
The above function is written in XSLT 2.0. However, it could also be written in Java, C++, etc. In fact, there could be several implementations, each in a different programming language. For each implementation there will be an <IncludeFile> element in the ontology.
The application processes input data as follows: it checks the data to determine if it is in the "preferred" format. If so, then it processes the data directly. If not, it invokes the include file function. The function returns the data in canonical form, and the application then processes the canonical version.
This strategy enables applications to process any length data, regardless of the units-of-measure that are used!
<xsl:include href="Length-Include-File.xsl"/>
<xsl:template match="len:Length[len:units/@rdf:resource!='http://www.xfront.com/owl/ontologies/Length/#Kilometer']
[len:units/@rdf:resource!='http://www.xfront.com/owl/ontologies/Length/#Meter']">
<xsl:variable name="canonical-Length" select="len:Length(.)"/>
<xsl:apply-templates select="$canonical-Length"/>
</xsl:template>
<xsl:template match="len:Length[len:units/@rdf:resource='http://www.xfront.com/owl/ontologies/Length/#Kilometer']">
<xsl:text>The input data is in the preferred Kilometer format</xsl:text>
</xsl:template>
<xsl:template match="len:Length[len:units/@rdf:resource='http://www.xfront.com/owl/ontologies/Length/#Meter']">
<xsl:text>Either the input data was originally in the canonical format, or it was converted to the canonical format</xsl:text>
</xsl:template>
<owl:Class rdf:ID="Coordinate-System">
<owlx:canonicalForm>
<rdfs:Class rdf:resource="#Cartesian-Coordinate-System"/>
<owlx:IncludeFile>
<rdf:type rdf:resource="XSLT2.0"/>
<owlx:location rdf:resource="CoordinateSystem-Include-File.xsl"/>
</owlx:IncludeFile>
</owlx:canonicalForm>
</owl:Class>"The canonical coordinate system is the
cartesian coordinate system. An XSLT2.0 function for converting non-canonical
forms to canonical form may be found in CoordinateSystem-Include-File.xsl"
Here is the definition of the cartesian coordinate system as well as the polar coordinate system:
<owl:Class rdf:ID="Cartesian-Coordinate-System">
<rdfs:subClassOf rdf:resource="#CoordinateSystem"/>
</owl:Class>
<owl:Class rdf:ID="Polar-Coordinate-System">
<rdfs:subClassOf rdf:resource="#CoordinateSystem"/>
</owl:Class>For the complete ontology see the links at
the bottom of this document.
<xsl:include href="Length-Include-File.xsl"/>
<xsl:function name="cs:CoordinateSystem" as="element()">
<xsl:param name="coordinateSystem" as="item()"/>
<xsl:choose>
<xsl:when test="local-name($coordinateSystem)='Polar-Coordinate-System'">
<Cartesian-Coordinate-System xmlns="http://www.xfront.com/owl/ontologies/CoordinateSystem/#">
<xsl:variable name="canonical-r-length" select="len:Length($coordinateSystem/cs:r/len:Length)"/>
<xsl:variable name="canonical-theta-angle" select="cs:Angle($coordinateSystem/cs:theta/cs:Angle)"/>
<x>
<Length xmlns="http://www.xfront.com/owl/ontologies/Length/#">
<value>
<!-- x = r cos theta -->
<xsl:value-of select="$canonical-r-length/len:value * exslt:cos($canonical-theta-angle/cs:value)"/>
</value>
<units rdf:resource="http://www.xfront.com/owl/ontologies/Length/#Meter"/>
</Length>
</x>
<y>
<Length xmlns="http://www.xfront.com/owl/ontologies/Length/#">
<value>
<!-- y = r sin theta -->
<xsl:value-of select="$canonical-r-length/len:value * exslt:sin($canonical-theta-angle/cs:value)"/>
</value>
<units rdf:resource="http://www.xfront.com/owl/ontologies/Length/#Meter"/>
</Length>
</y>
</Cartesian-Coordinate-System>
</xsl:when>
...
</xsl:choose>
</xsl:function>Note that this include file reuses the
Length include file.
Again, the full version of this may be seen by following the link at the bottom of this document.
<xsl:include href="CoordinateSystem-Include-File.xsl"/>
<xsl:template match="*[local-name(.) != 'Cartesian-Coordinate-System']">
<xsl:text>The input data is not in the canonical coordinate system. Converting ...
<xsl:variable name="canonical-CoordinateSystem" select="cs:CoordinateSystem(.)"/>
<xsl:apply-templates select="$canonical-CoordinateSystem"/>
</xsl:template>
<xsl:template match="cs:Cartesian-Coordinate-System[(cs:x/len:Length/len:units/@rdf:resource != 'http://www.xfront.com/owl/ontologies/Length/#Meter') or
(cs:y/len:Length/len:units/@rdf:resource != 'http://www.xfront.com/owl/ontologies/Length/#Meter')]">
<xsl:text>The input data is in the canonical coordinate system, but the Length of x and/or y is not in canonical form. Converting ...
<xsl:variable name="canonicalForm" select="cs:CoordinateSystem(.)"/>
<xsl:apply-templates select="$canonicalForm"/>
</xsl:template>
<xsl:template match="cs:Cartesian-Coordinate-System[(cs:x/len:Length/len:units/@rdf:resource = 'http://www.xfront.com/owl/ontologies/Length/#Meter') and
(cs:y/len:Length/len:units/@rdf:resource = 'http://www.xfront.com/owl/ontologies/Length/#Meter')]">
<xsl:text>The input data is in the canonical coordinate system, and it is in canonical form.
</xsl:template>