Skip to content

Commit 5f1cdc5

Browse files
author
Marco De Salvo
committed
#360 Add support for HasLang expression from SPARQL-1.2
1 parent eb0591d commit 5f1cdc5

File tree

2 files changed

+360
-0
lines changed

2 files changed

+360
-0
lines changed
Lines changed: 260 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,260 @@
1+
/*
2+
Copyright 2012-2025 Marco De Salvo
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
using Microsoft.VisualStudio.TestTools.UnitTesting;
18+
using System.Data;
19+
using RDFSharp.Model;
20+
using RDFSharp.Query;
21+
22+
namespace RDFSharp.Test.Query
23+
{
24+
[TestClass]
25+
public class RDFHasLangExpressionTest
26+
{
27+
#region Tests
28+
[TestMethod]
29+
public void ShouldCreateHasLangExpressionWithExpression()
30+
{
31+
RDFHasLangExpression expression = new RDFHasLangExpression(
32+
new RDFAddExpression(new RDFVariable("?V1"), new RDFVariable("?V2")));
33+
34+
Assert.IsNotNull(expression);
35+
Assert.IsNotNull(expression.LeftArgument);
36+
Assert.IsNull(expression.RightArgument);
37+
Assert.IsTrue(expression.ToString().Equals("(HASLANG((?V1 + ?V2)))"));
38+
Assert.IsTrue(expression.ToString([]).Equals("(HASLANG((?V1 + ?V2)))"));
39+
}
40+
41+
[TestMethod]
42+
public void ShouldCreateHasLangExpressionWithVariable()
43+
{
44+
RDFHasLangExpression expression = new RDFHasLangExpression(
45+
new RDFVariable("?V1"));
46+
47+
Assert.IsNotNull(expression);
48+
Assert.IsNotNull(expression.LeftArgument);
49+
Assert.IsNull(expression.RightArgument);
50+
Assert.IsTrue(expression.ToString().Equals("(HASLANG(?V1))"));
51+
Assert.IsTrue(expression.ToString([]).Equals("(HASLANG(?V1))"));
52+
}
53+
54+
[TestMethod]
55+
public void ShouldThrowExceptionOnCreatingHasLangExpressionWithExpressionBecauseNullLeftArgument()
56+
=> Assert.ThrowsException<RDFQueryException>(() => new RDFHasLangExpression(null as RDFExpression));
57+
58+
[TestMethod]
59+
public void ShouldThrowExceptionOnCreatingHasLangExpressionWithVariableBecauseNullLeftArgument()
60+
=> Assert.ThrowsException<RDFQueryException>(() => new RDFHasLangExpression(null as RDFVariable));
61+
62+
[TestMethod]
63+
public void ShouldApplyExpressionWithExpressionAndCalculateResultOnNull()
64+
{
65+
DataTable table = new DataTable();
66+
table.Columns.Add("?A", typeof(string));
67+
DataRow row = table.NewRow();
68+
row["?A"] = null;
69+
table.Rows.Add(row);
70+
table.AcceptChanges();
71+
72+
RDFHasLangExpression expression = new RDFHasLangExpression(
73+
new RDFVariableExpression(new RDFVariable("?A")));
74+
RDFPatternMember expressionResult = expression.ApplyExpression(table.Rows[0]);
75+
76+
Assert.IsNotNull(expressionResult);
77+
Assert.IsTrue(expressionResult.Equals(RDFTypedLiteral.False));
78+
}
79+
80+
[TestMethod]
81+
public void ShouldApplyExpressionWithExpressionAndCalculateResultOnResource()
82+
{
83+
DataTable table = new DataTable();
84+
table.Columns.Add("?A", typeof(string));
85+
DataRow row = table.NewRow();
86+
row["?A"] = new RDFResource("ex:subj").ToString();
87+
table.Rows.Add(row);
88+
table.AcceptChanges();
89+
90+
RDFHasLangExpression expression = new RDFHasLangExpression(
91+
new RDFVariableExpression(new RDFVariable("?A")));
92+
RDFPatternMember expressionResult = expression.ApplyExpression(table.Rows[0]);
93+
94+
Assert.IsNotNull(expressionResult);
95+
Assert.IsTrue(expressionResult.Equals(RDFTypedLiteral.False));
96+
}
97+
98+
[TestMethod]
99+
public void ShouldApplyExpressionWithExpressionAndCalculateResultOnPlainLiteral()
100+
{
101+
DataTable table = new DataTable();
102+
table.Columns.Add("?A", typeof(string));
103+
DataRow row = table.NewRow();
104+
row["?A"] = new RDFPlainLiteral("hello").ToString();
105+
table.Rows.Add(row);
106+
table.AcceptChanges();
107+
108+
RDFHasLangExpression expression = new RDFHasLangExpression(
109+
new RDFVariableExpression(new RDFVariable("?A")));
110+
RDFPatternMember expressionResult = expression.ApplyExpression(table.Rows[0]);
111+
112+
Assert.IsNotNull(expressionResult);
113+
Assert.IsTrue(expressionResult.Equals(RDFTypedLiteral.False));
114+
}
115+
116+
[TestMethod]
117+
public void ShouldApplyExpressionWithExpressionAndCalculateResultOnPlainLiteralWithLanguage()
118+
{
119+
DataTable table = new DataTable();
120+
table.Columns.Add("?A", typeof(string));
121+
DataRow row = table.NewRow();
122+
row["?A"] = new RDFPlainLiteral("hello","en-US").ToString();
123+
table.Rows.Add(row);
124+
table.AcceptChanges();
125+
126+
RDFHasLangExpression expression = new RDFHasLangExpression(
127+
new RDFVariableExpression(new RDFVariable("?A")));
128+
RDFPatternMember expressionResult = expression.ApplyExpression(table.Rows[0]);
129+
130+
Assert.IsNotNull(expressionResult);
131+
Assert.IsTrue(expressionResult.Equals(RDFTypedLiteral.True));
132+
}
133+
134+
[TestMethod]
135+
public void ShouldApplyExpressionWithExpressionAndCalculateResultOnTypedLiteral()
136+
{
137+
DataTable table = new DataTable();
138+
table.Columns.Add("?A", typeof(string));
139+
DataRow row = table.NewRow();
140+
row["?A"] = new RDFTypedLiteral("hello", RDFModelEnums.RDFDatatypes.RDFS_LITERAL).ToString();
141+
table.Rows.Add(row);
142+
table.AcceptChanges();
143+
144+
RDFHasLangExpression expression = new RDFHasLangExpression(
145+
new RDFVariableExpression(new RDFVariable("?A")));
146+
RDFPatternMember expressionResult = expression.ApplyExpression(table.Rows[0]);
147+
148+
Assert.IsNotNull(expressionResult);
149+
Assert.IsTrue(expressionResult.Equals(RDFTypedLiteral.False));
150+
}
151+
152+
[TestMethod]
153+
public void ShouldApplyExpressionWithExpressionAndNotCalculateResultBecauseNotBoundVariable()
154+
{
155+
DataTable table = new DataTable();
156+
table.Columns.Add("?A", typeof(string));
157+
DataRow row = table.NewRow();
158+
row["?A"] = new RDFTypedLiteral("45", RDFModelEnums.RDFDatatypes.XSD_NORMALIZEDSTRING).ToString();
159+
table.Rows.Add(row);
160+
table.AcceptChanges();
161+
162+
RDFHasLangExpression expression = new RDFHasLangExpression(
163+
new RDFVariableExpression(new RDFVariable("?Q")));
164+
RDFPatternMember expressionResult = expression.ApplyExpression(table.Rows[0]);
165+
166+
Assert.IsNotNull(expressionResult);
167+
Assert.IsTrue(expressionResult.Equals(RDFTypedLiteral.False));
168+
}
169+
170+
[TestMethod]
171+
public void ShouldApplyExpressionWithVariableAndCalculateResultOnResource()
172+
{
173+
DataTable table = new DataTable();
174+
table.Columns.Add("?A", typeof(string));
175+
DataRow row = table.NewRow();
176+
row["?A"] = new RDFResource("ex:subj").ToString();
177+
table.Rows.Add(row);
178+
table.AcceptChanges();
179+
180+
RDFHasLangExpression expression = new RDFHasLangExpression(
181+
new RDFVariable("?A"));
182+
RDFPatternMember expressionResult = expression.ApplyExpression(table.Rows[0]);
183+
184+
Assert.IsNotNull(expressionResult);
185+
Assert.IsTrue(expressionResult.Equals(RDFTypedLiteral.False));
186+
}
187+
188+
[TestMethod]
189+
public void ShouldApplyExpressionWithVariableAndCalculateResultOnPlainLiteral()
190+
{
191+
DataTable table = new DataTable();
192+
table.Columns.Add("?A", typeof(string));
193+
DataRow row = table.NewRow();
194+
row["?A"] = new RDFPlainLiteral("hello").ToString();
195+
table.Rows.Add(row);
196+
table.AcceptChanges();
197+
198+
RDFHasLangExpression expression = new RDFHasLangExpression(
199+
new RDFVariable("?A"));
200+
RDFPatternMember expressionResult = expression.ApplyExpression(table.Rows[0]);
201+
202+
Assert.IsNotNull(expressionResult);
203+
Assert.IsTrue(expressionResult.Equals(RDFTypedLiteral.False));
204+
}
205+
206+
[TestMethod]
207+
public void ShouldApplyExpressionWithVariableAndCalculateResultOnPlainLiteralWithLanguage()
208+
{
209+
DataTable table = new DataTable();
210+
table.Columns.Add("?A", typeof(string));
211+
DataRow row = table.NewRow();
212+
row["?A"] = new RDFPlainLiteral("hello", "en-US").ToString();
213+
table.Rows.Add(row);
214+
table.AcceptChanges();
215+
216+
RDFHasLangExpression expression = new RDFHasLangExpression(
217+
new RDFVariable("?A"));
218+
RDFPatternMember expressionResult = expression.ApplyExpression(table.Rows[0]);
219+
220+
Assert.IsNotNull(expressionResult);
221+
Assert.IsTrue(expressionResult.Equals(RDFTypedLiteral.True));
222+
}
223+
224+
[TestMethod]
225+
public void ShouldApplyExpressionWithVariableAndCalculateResultOnTypedLiteral()
226+
{
227+
DataTable table = new DataTable();
228+
table.Columns.Add("?A", typeof(string));
229+
DataRow row = table.NewRow();
230+
row["?A"] = new RDFTypedLiteral("hello", RDFModelEnums.RDFDatatypes.RDFS_LITERAL).ToString();
231+
table.Rows.Add(row);
232+
table.AcceptChanges();
233+
234+
RDFHasLangExpression expression = new RDFHasLangExpression(
235+
new RDFVariable("?A"));
236+
RDFPatternMember expressionResult = expression.ApplyExpression(table.Rows[0]);
237+
238+
Assert.IsNotNull(expressionResult);
239+
Assert.IsTrue(expressionResult.Equals(RDFTypedLiteral.False));
240+
}
241+
242+
[TestMethod]
243+
public void ShouldApplyExpressionWithVariableAndNotCalculateResultBecauseNotBoundVariable()
244+
{
245+
DataTable table = new DataTable();
246+
table.Columns.Add("?A", typeof(string));
247+
DataRow row = table.NewRow();
248+
row["?A"] = new RDFTypedLiteral("45", RDFModelEnums.RDFDatatypes.XSD_NORMALIZEDSTRING).ToString();
249+
table.Rows.Add(row);
250+
table.AcceptChanges();
251+
252+
RDFHasLangExpression expression = new RDFHasLangExpression(
253+
new RDFVariable("?Q"));
254+
RDFPatternMember expressionResult = expression.ApplyExpression(table.Rows[0]);
255+
256+
Assert.IsNull(expressionResult);
257+
}
258+
#endregion
259+
}
260+
}
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/*
2+
Copyright 2012-2025 Marco De Salvo
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
using RDFSharp.Model;
18+
using System.Collections.Generic;
19+
using System.Data;
20+
using System.Text;
21+
22+
namespace RDFSharp.Query
23+
{
24+
/// <summary>
25+
/// RDFHasLangExpression represents a language-detector function to be applied on a query results table.
26+
/// </summary>
27+
public class RDFHasLangExpression : RDFExpression
28+
{
29+
#region Ctors
30+
/// <summary>
31+
/// Default-ctor to build a hasLang function with given arguments
32+
/// </summary>
33+
public RDFHasLangExpression(RDFExpression leftArgument) : base(leftArgument, null as RDFExpression) { }
34+
35+
/// <summary>
36+
/// Default-ctor to build a hasLang function with given arguments
37+
/// </summary>
38+
public RDFHasLangExpression(RDFVariable leftArgument) : base(leftArgument, null as RDFExpression) { }
39+
#endregion
40+
41+
#region Interfaces
42+
/// <summary>
43+
/// Gives the string representation of the hasLang function
44+
/// </summary>
45+
public override string ToString()
46+
=> ToString(new List<RDFNamespace>());
47+
internal override string ToString(List<RDFNamespace> prefixes)
48+
{
49+
StringBuilder sb = new StringBuilder();
50+
51+
//(HASLANG(L))
52+
sb.Append("(HASLANG(");
53+
if (LeftArgument is RDFExpression expLeftArgument)
54+
sb.Append(expLeftArgument.ToString(prefixes));
55+
else
56+
sb.Append(RDFQueryPrinter.PrintPatternMember((RDFPatternMember)LeftArgument, prefixes));
57+
sb.Append("))");
58+
59+
return sb.ToString();
60+
}
61+
#endregion
62+
63+
#region Methods
64+
/// <summary>
65+
/// Applies the hasLang function on the given datarow
66+
/// </summary>
67+
internal override RDFPatternMember ApplyExpression(DataRow row)
68+
{
69+
RDFTypedLiteral expressionResult = null;
70+
71+
#region Guards
72+
if (LeftArgument is RDFVariable && !row.Table.Columns.Contains(LeftArgument.ToString()))
73+
return expressionResult;
74+
#endregion
75+
76+
try
77+
{
78+
#region Evaluate Arguments
79+
//Evaluate left argument (Expression VS Variable)
80+
RDFPatternMember leftArgumentPMember = null;
81+
if (LeftArgument is RDFExpression leftArgumentExpression)
82+
leftArgumentPMember = leftArgumentExpression.ApplyExpression(row);
83+
else
84+
leftArgumentPMember = RDFQueryUtilities.ParseRDFPatternMember(row[LeftArgument.ToString()].ToString());
85+
#endregion
86+
87+
#region Calculate Result
88+
if (leftArgumentPMember is RDFPlainLiteral leftArgumentPMemberPLiteral && leftArgumentPMemberPLiteral.HasLanguage())
89+
expressionResult = RDFTypedLiteral.True;
90+
else
91+
expressionResult = RDFTypedLiteral.False;
92+
#endregion
93+
}
94+
catch { /* Just a no-op, since type errors are normal when trying to face variable's bindings */ }
95+
96+
return expressionResult;
97+
}
98+
#endregion
99+
}
100+
}

0 commit comments

Comments
 (0)