Skip to content

Commit

Permalink
Give geographic datatypes their own category + Make custom datatypes …
Browse files Browse the repository at this point in the history
…compatible with their target datatype
  • Loading branch information
Marco De Salvo committed May 28, 2024
1 parent f3e5a49 commit 26266cf
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 31 deletions.
50 changes: 39 additions & 11 deletions RDFSharp.Test/Model/RDFTypedLiteralTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,6 @@ public class RDFTypedLiteralTest
[DataRow("{}", RDFModelEnums.RDFDatatypes.RDF_JSON)]
[DataRow("[{\"value\":25}]", RDFModelEnums.RDFDatatypes.RDF_JSON)]
[DataRow("[]", RDFModelEnums.RDFDatatypes.RDF_JSON)]
[DataRow("POINT(12.496365 41.902782)", RDFModelEnums.RDFDatatypes.GEOSPARQL_WKT)]
[DataRow("<gml:Point xmlns:gml=\"http://www.opengis.net/gml/3.2\"><gml:pos>12.496365 41.902782</gml:pos></gml:Point>", RDFModelEnums.RDFDatatypes.GEOSPARQL_GML)]
[DataRow("http://hello/world#hi", RDFModelEnums.RDFDatatypes.XSD_ANYURI)]
[DataRow("http://hello/world#", RDFModelEnums.RDFDatatypes.XSD_ANYURI)]
[DataRow("http://hello/world/", RDFModelEnums.RDFDatatypes.XSD_ANYURI)]
Expand Down Expand Up @@ -85,6 +83,24 @@ public void ShouldCreateTypedLiteralOfStringCategory(string value, RDFModelEnums

Assert.IsNotNull(tl);
Assert.IsTrue(tl.HasStringDatatype());
Assert.IsFalse(tl.HasGeographicDatatype());
Assert.IsFalse(tl.HasBooleanDatatype());
Assert.IsFalse(tl.HasDatetimeDatatype());
Assert.IsFalse(tl.HasDecimalDatatype());
Assert.IsFalse(tl.HasTimespanDatatype());
Assert.IsTrue(tl.ToString().Equals(string.Concat(value ?? "", "^^", RDFModelUtilities.GetDatatypeFromEnum(datatype))));
}

[DataTestMethod]
[DataRow("POINT(12.496365 41.902782)", RDFModelEnums.RDFDatatypes.GEOSPARQL_WKT)]
[DataRow("<gml:Point xmlns:gml=\"http://www.opengis.net/gml/3.2\"><gml:pos>12.496365 41.902782</gml:pos></gml:Point>", RDFModelEnums.RDFDatatypes.GEOSPARQL_GML)]
public void ShouldCreateTypedLiteralOfGeographicCategory(string value, RDFModelEnums.RDFDatatypes datatype)
{
RDFTypedLiteral tl = new RDFTypedLiteral(value, datatype);

Assert.IsNotNull(tl);
Assert.IsFalse(tl.HasStringDatatype());
Assert.IsTrue(tl.HasGeographicDatatype());
Assert.IsFalse(tl.HasBooleanDatatype());
Assert.IsFalse(tl.HasDatetimeDatatype());
Assert.IsFalse(tl.HasDecimalDatatype());
Expand Down Expand Up @@ -119,6 +135,7 @@ public void ShouldCreateTypedLiteralOfBooleanCategory(string value, RDFModelEnum

Assert.IsNotNull(tl);
Assert.IsFalse(tl.HasStringDatatype());
Assert.IsFalse(tl.HasGeographicDatatype());
Assert.IsTrue(tl.HasBooleanDatatype());
Assert.IsFalse(tl.HasDatetimeDatatype());
Assert.IsFalse(tl.HasDecimalDatatype());
Expand Down Expand Up @@ -210,6 +227,7 @@ public void ShouldCreateTypedLiteralOfDatetimeCategory(string value, RDFModelEnu

Assert.IsNotNull(tl);
Assert.IsFalse(tl.HasStringDatatype());
Assert.IsFalse(tl.HasGeographicDatatype());
Assert.IsFalse(tl.HasBooleanDatatype());
Assert.IsTrue(tl.HasDatetimeDatatype());
Assert.IsFalse(tl.HasDecimalDatatype());
Expand Down Expand Up @@ -293,6 +311,7 @@ public void ShouldCreateTypedLiteralOfDecimalCategory(string value, RDFModelEnum

Assert.IsNotNull(tl);
Assert.IsFalse(tl.HasStringDatatype());
Assert.IsFalse(tl.HasGeographicDatatype());
Assert.IsFalse(tl.HasBooleanDatatype());
Assert.IsFalse(tl.HasDatetimeDatatype());
Assert.IsTrue(tl.HasDecimalDatatype());
Expand All @@ -309,6 +328,7 @@ public void ShouldCreateTypedLiteralOfTimeSpanCategory(string value, RDFModelEnu

Assert.IsNotNull(tl);
Assert.IsFalse(tl.HasStringDatatype());
Assert.IsFalse(tl.HasGeographicDatatype());
Assert.IsFalse(tl.HasBooleanDatatype());
Assert.IsFalse(tl.HasDatetimeDatatype());
Assert.IsFalse(tl.HasDecimalDatatype());
Expand All @@ -324,8 +344,6 @@ public void ShouldCreateTypedLiteralOfTimeSpanCategory(string value, RDFModelEnu
[DataRow("value:", RDFModelEnums.RDFDatatypes.RDF_JSON)]
[DataRow("[{value:}", RDFModelEnums.RDFDatatypes.RDF_JSON)]
[DataRow("{value:}]", RDFModelEnums.RDFDatatypes.RDF_JSON)]
[DataRow("POINT(12.496365)", RDFModelEnums.RDFDatatypes.GEOSPARQL_WKT)]
[DataRow("<gml:Point xmlns:gml=\"http://www.opengis.net/gml/3.2\"><gml:pos>12.496365</gml:pos></gml:Point>", RDFModelEnums.RDFDatatypes.GEOSPARQL_GML)]
[DataRow("hello", RDFModelEnums.RDFDatatypes.XSD_ANYURI)]
[DataRow("http:/hello#", RDFModelEnums.RDFDatatypes.XSD_ANYURI)]
[DataRow("http:// ", RDFModelEnums.RDFDatatypes.XSD_ANYURI)]
Expand Down Expand Up @@ -388,6 +406,12 @@ public void ShouldCreateTypedLiteralOfTimeSpanCategory(string value, RDFModelEnu
public void ShouldNotCreateTypedLiteralOfStringCategory(string value, RDFModelEnums.RDFDatatypes datatype)
=> Assert.ThrowsException<RDFModelException>(() => new RDFTypedLiteral(value, datatype));

[DataTestMethod]
[DataRow("POINT(12.496365)", RDFModelEnums.RDFDatatypes.GEOSPARQL_WKT)]
[DataRow("<gml:Point xmlns:gml=\"http://www.opengis.net/gml/3.2\"><gml:pos>12.496365</gml:pos></gml:Point>", RDFModelEnums.RDFDatatypes.GEOSPARQL_GML)]
public void ShouldNotCreateTypedLiteralOfGeographicCategory(string value, RDFModelEnums.RDFDatatypes datatype)
=> Assert.ThrowsException<RDFModelException>(() => new RDFTypedLiteral(value, datatype));

[DataTestMethod]
[DataRow("value", RDFModelEnums.RDFDatatypes.XSD_BOOLEAN)]
[DataRow("", RDFModelEnums.RDFDatatypes.XSD_BOOLEAN)]
Expand Down Expand Up @@ -624,21 +648,25 @@ public void ShouldCreateCustomTypedLiteral()
{
RDFTypedLiteral tlit = new RDFTypedLiteral("abcdef", new RDFDatatype(new Uri("ex:length6"), RDFModelEnums.RDFDatatypes.XSD_STRING, [
new RDFMinLengthFacet(6), new RDFMaxLengthFacet(14) ]));

Assert.IsNotNull(tlit);
Assert.IsTrue(tlit.Value.Equals("abcdef"));
Assert.IsTrue(tlit.Datatype.ToString().Equals("ex:length6"));
Assert.ThrowsException<RDFModelException>(() => new RDFTypedLiteral("ab", new RDFDatatype(new Uri("ex:length6"), RDFModelEnums.RDFDatatypes.XSD_STRING, [
new RDFMinLengthFacet(6), new RDFMaxLengthFacet(14) ])));

RDFTypedLiteral tlit2 = new RDFTypedLiteral("36.6", new RDFDatatype(new Uri("ex:humanTemperature"), RDFModelEnums.RDFDatatypes.XSD_INTEGER, [
new RDFMinInclusiveFacet(36), new RDFMaxInclusiveFacet(37) ]));

RDFTypedLiteral tlit2 = new RDFTypedLiteral("37", new RDFDatatype(new Uri("ex:humanTemperature"), RDFModelEnums.RDFDatatypes.XSD_INTEGER, [
new RDFMinInclusiveFacet(36), new RDFMaxInclusiveFacet(39) ]));
Assert.IsNotNull(tlit2);
Assert.IsTrue(tlit2.Value.Equals("36.6"));
Assert.IsTrue(tlit2.Value.Equals("37"));
Assert.IsTrue(tlit2.Datatype.ToString().Equals("ex:humanTemperature"));
Assert.ThrowsException<RDFModelException>(() => new RDFTypedLiteral("37.6", new RDFDatatype(new Uri("ex:humanTemperature"), RDFModelEnums.RDFDatatypes.XSD_DOUBLE, [
new RDFMinInclusiveFacet(36), new RDFMaxInclusiveFacet(37) ])));
Assert.ThrowsException<RDFModelException>(() => new RDFTypedLiteral("39.5", new RDFDatatype(new Uri("ex:humanTemperature"), RDFModelEnums.RDFDatatypes.XSD_DOUBLE, [
new RDFMinInclusiveFacet(36), new RDFMaxInclusiveFacet(39) ])));

RDFTypedLiteral tlit3 = new RDFTypedLiteral("37", new RDFDatatype(new Uri("ex:humanTemperature"), RDFModelEnums.RDFDatatypes.XSD_INTEGER, []));
Assert.IsNotNull(tlit3);
Assert.IsTrue(tlit3.Value.Equals("37"));
Assert.IsTrue(tlit3.Datatype.ToString().Equals("ex:humanTemperature"));
Assert.ThrowsException<RDFModelException>(() => new RDFTypedLiteral("39.5", new RDFDatatype(new Uri("ex:humanTemperature"), RDFModelEnums.RDFDatatypes.XSD_INTEGER, null)));
}
#endregion
}
Expand Down
12 changes: 10 additions & 2 deletions RDFSharp/Model/RDFDatatype.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,16 @@ public RDFGraph ToRDFGraph()
/// Validates the given literal against the datatype
/// </summary>
internal (bool,string) Validate(string literalValue)
=> Facets.Count > 0 ? (Facets.TrueForAll(facet => facet.Validate(literalValue)), literalValue)
: RDFModelUtilities.ValidateTypedLiteral(literalValue, TargetDatatype);
{
//It should validate the target datatype
(bool,string) validatesTargetDatatype = RDFModelUtilities.ValidateTypedLiteral(literalValue, TargetDatatype);

//Then the eventual constraining facets
if (validatesTargetDatatype.Item1 && Facets.Count > 0)
return (Facets.TrueForAll(facet => facet.Validate(literalValue)), literalValue);
else
return validatesTargetDatatype;
}
#endregion
}
}
28 changes: 18 additions & 10 deletions RDFSharp/Model/RDFModelUtilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -555,16 +555,6 @@ internal static (bool,string) ValidateTypedLiteral(string literalValue, RDFModel
default:
return (true, literalValue);

case RDFModelEnums.RDFDatatypes.GEOSPARQL_WKT:
case RDFModelEnums.RDFDatatypes.GEOSPARQL_GML:
try
{
_ = datatype.Equals(RDFModelEnums.RDFDatatypes.GEOSPARQL_WKT) ? RDFGeoExpression.WKTReader.Read(literalValue)
: RDFGeoExpression.GMLReader.Read(literalValue);
return (true, literalValue);
}
catch { return (false, literalValue); }

case RDFModelEnums.RDFDatatypes.RDF_XMLLITERAL:
try
{
Expand Down Expand Up @@ -660,6 +650,24 @@ internal static (bool,string) ValidateTypedLiteral(string literalValue, RDFModel
return (isValidHexBinary, literalValue);
#endregion

#region GEOGRAPHIC CATEGORY
case RDFModelEnums.RDFDatatypes.GEOSPARQL_WKT:
try
{
_ = RDFGeoExpression.WKTReader.Read(literalValue);
return (true, literalValue);
}
catch { return (false, literalValue); }

case RDFModelEnums.RDFDatatypes.GEOSPARQL_GML:
try
{
_ = RDFGeoExpression.GMLReader.Read(literalValue);
return (true, literalValue);
}
catch { return (false, literalValue); }
#endregion

#region BOOLEAN CATEGORY
case RDFModelEnums.RDFDatatypes.XSD_BOOLEAN:
if (bool.TryParse(literalValue, out bool outBool))
Expand Down
14 changes: 13 additions & 1 deletion RDFSharp/Model/RDFTypedLiteral.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public RDFTypedLiteral(string value, RDFDatatype datatype)
//Validation against semantic of given datatype
(bool,string) validationResult = Datatype.Validate(value ?? string.Empty);
if (!validationResult.Item1)
throw new RDFModelException("Cannot create RDFTypedLiteral because given \"value\" parameter (" + value + ") is not well-formed against given \"datatype\" parameter (" + Datatype + ")");
throw new RDFModelException("Cannot create RDFTypedLiteral because given \"value\" parameter (" + value + ") is not well-formed against given \"datatype\" parameter (" + Datatype + ") which is based on \"" + Datatype.TargetDatatype + "\" ");
Value = validationResult.Item2;
}
#endregion
Expand Down Expand Up @@ -134,6 +134,18 @@ public bool HasStringDatatype()
case RDFModelEnums.RDFDatatypes.XSD_TOKEN:
case RDFModelEnums.RDFDatatypes.XSD_BASE64BINARY:
case RDFModelEnums.RDFDatatypes.XSD_HEXBINARY:
return true;
default: return false;
}
}

/// <summary>
/// Checks if the datatype of this typed literal is compatible with geosparql
/// </summary>
public bool HasGeographicDatatype()
{
switch (Datatype.TargetDatatype)
{
case RDFModelEnums.RDFDatatypes.GEOSPARQL_WKT:
case RDFModelEnums.RDFDatatypes.GEOSPARQL_GML:
return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,8 @@ internal override RDFPatternMember ApplyExpression(DataRow row)
Geometry leftGeometryLAZ = null;
Geometry rightGeometry = null;
Geometry rightGeometryLAZ = null;
if (leftArgumentPMember is RDFTypedLiteral leftArgumentTypedLiteral
&& (leftArgumentTypedLiteral.Datatype.ToString().Equals(RDFVocabulary.GEOSPARQL.WKT_LITERAL.ToString()) ||
leftArgumentTypedLiteral.Datatype.ToString().Equals(RDFVocabulary.GEOSPARQL.GML_LITERAL.ToString())))
if (leftArgumentPMember is RDFTypedLiteral leftArgumentTypedLiteral
&& leftArgumentTypedLiteral.HasGeographicDatatype())
{
//Parse WGS84 WKT/GML left geometry
leftGeometry = leftArgumentTypedLiteral.Datatype.ToString().Equals(RDFVocabulary.GEOSPARQL.WKT_LITERAL.ToString()) ?
Expand All @@ -126,9 +125,8 @@ internal override RDFPatternMember ApplyExpression(DataRow row)
if (HasRightArgument)
{
//If so, it must be a well-formed GEO literal (WKT/GML)
if (rightArgumentPMember is RDFTypedLiteral rightArgumentTypedLiteral
&& (rightArgumentTypedLiteral.Datatype.ToString().Equals(RDFVocabulary.GEOSPARQL.WKT_LITERAL.ToString()) ||
rightArgumentTypedLiteral.Datatype.ToString().Equals(RDFVocabulary.GEOSPARQL.GML_LITERAL.ToString())))
if (rightArgumentPMember is RDFTypedLiteral rightArgumentTypedLiteral
&& rightArgumentTypedLiteral.HasGeographicDatatype())
{
//Parse WGS84 WKT/GML right geometry
rightGeometry = rightArgumentTypedLiteral.Datatype.ToString().Equals(RDFVocabulary.GEOSPARQL.WKT_LITERAL.ToString()) ?
Expand Down Expand Up @@ -217,7 +215,7 @@ internal override RDFPatternMember ApplyExpression(DataRow row)
case RDFQueryEnums.RDFGeoEgenhoferRelations.Meet:
sfEgenhoferRelate = leftGeometryLAZ.Relate(rightGeometryLAZ, "FT*******")
|| leftGeometryLAZ.Relate(rightGeometryLAZ, "F**T*****")
|| leftGeometryLAZ.Relate(rightGeometryLAZ, "F***T****");
|| leftGeometryLAZ.Relate(rightGeometryLAZ, "F***T****");
break;
case RDFQueryEnums.RDFGeoEgenhoferRelations.Overlap:
sfEgenhoferRelate = leftGeometryLAZ.Relate(rightGeometryLAZ, "T*T***T**");
Expand Down

0 comments on commit 26266cf

Please sign in to comment.