2 using System
.Collections
;
6 public abstract class Resource
{
7 internal ArrayList extraKeys
;
9 internal class ExtraKey
{
14 public abstract string Uri { get; }
19 public override string ToString() {
20 if (Uri
!= null) return Uri
;
24 // These get rid of the warning about overring ==, !=.
25 // Since Entity and Literal override these, we're ok.
26 public override bool Equals(object other
) {
27 return base.Equals(other
);
29 public override int GetHashCode() {
30 return base.GetHashCode();
33 public static bool operator ==(Resource a
, Resource b
) {
34 if ((object)a
== null && (object)b
== null) return true;
35 if ((object)a
== null || (object)b
== null) return false;
38 public static bool operator !=(Resource a
, Resource b
) {
42 internal object GetResourceKey(object key
) {
43 if (extraKeys
== null) return null;
44 for (int i
= 0; i
< extraKeys
.Count
; i
++) {
45 Resource
.ExtraKey ekey
= (Resource
.ExtraKey
)extraKeys
[i
];
51 internal void SetResourceKey(object key
, object value) {
52 if (extraKeys
== null) extraKeys
= new ArrayList();
54 foreach (Resource
.ExtraKey ekey
in extraKeys
)
55 if (ekey
.Key
== key
) { extraKeys.Remove(ekey); break; }
57 Resource
.ExtraKey k
= new Resource
.ExtraKey();
66 public sealed class Entity
: Resource
{
68 int cachedHashCode
= -1;
70 public Entity(string uri
) { if (uri != null) this.uri = string.Intern(uri); }
72 public override string Uri
{
78 public static implicit operator Entity(string uri
) { return new Entity(uri); }
80 public override int GetHashCode() {
81 if (cachedHashCode
!= -1) return cachedHashCode
;
84 cachedHashCode
= Uri
.GetHashCode();
85 } else if (extraKeys
!= null && extraKeys
.Count
== 1) {
86 ExtraKey v
= (ExtraKey
)extraKeys
[0];
87 cachedHashCode
= unchecked(v
.Key
.GetHashCode() + v
.Value
.GetHashCode());
90 // If there's no Uri or ExtraKeys info, then this
91 // object is only equal to itself. It's then safe
92 // to use object.GetHashCode().
93 if (cachedHashCode
== -1) cachedHashCode
= base.GetHashCode();
95 return cachedHashCode
;
98 public override bool Equals(object other
) {
99 if (object.ReferenceEquals(this, other
)) return true;
100 if (!(other
is Entity
)) return false;
102 // If anonymous, then we have to compare extraKeys.
103 if ((Uri
== null && ((Resource
)other
).Uri
== null)) {
104 ArrayList otherkeys
= ((Resource
)other
).extraKeys
;
105 if (otherkeys
!= null && extraKeys
!= null) {
106 for (int vi1
= 0; vi1
< extraKeys
.Count
; vi1
++) {
107 ExtraKey v1
= (ExtraKey
)extraKeys
[vi1
];
108 for (int vi2
= 0; vi2
< otherkeys
.Count
; vi2
++) {
109 ExtraKey v2
= (ExtraKey
)otherkeys
[vi2
];
110 if (v1
.Key
== v2
.Key
)
111 return v1
.Value
.Equals(v2
.Value
);
119 return ((Resource
)other
).Uri
!= null && ((Resource
)other
).Uri
== Uri
;
122 // Although these do the same as Resource's operator overloads,
123 // having these plus the implict string conversion allows
124 // these operators to work with entities and strings.
126 public static bool operator ==(Entity a
, Entity b
) {
127 if ((object)a
== null && (object)b
== null) return true;
128 if ((object)a
== null || (object)b
== null) return false;
131 public static bool operator !=(Entity a
, Entity b
) {
136 public sealed class Literal
: Resource
{
137 private string value, lang
, type
;
139 public Literal(string value) : this(value, null, null) {
142 public Literal(string value, string language
, string dataType
) {
144 throw new ArgumentNullException("value");
145 this.value = string.Intern(value);
146 this.lang
= language
;
147 this.type
= dataType
;
150 public static explicit operator Literal(string value) { return new Literal(value); }
152 public override string Uri { get { return null; }
}
154 public string Value { get { return value; }
}
155 public string Language { get { return lang; }
}
156 public string DataType { get { return type; }
}
158 public override bool Equals(object other
) {
159 if (other
== null) return false;
160 if (!(other
is Literal
)) return false;
161 Literal literal
= (Literal
)other
;
162 if (Value
!= literal
.Value
) return false;
163 if (different(Language
, literal
.Language
)) return false;
164 if (different(DataType
, literal
.DataType
)) return false;
168 private bool different(string a
, string b
) {
169 if ((object)a
== (object)b
) return false;
170 if (a
== null || b
== null) return true;
174 public override int GetHashCode() {
175 return Value
.GetHashCode();
178 public override string ToString() {
179 System
.Text
.StringBuilder ret
= new System
.Text
.StringBuilder();
181 ret
.Append(N3Writer
.Escape(Value
));
184 if (Language
!= null) {
186 ret
.Append(N3Writer
.Escape(Language
));
189 if (DataType
!= null) {
191 ret
.Append(N3Writer
.Escape(DataType
));
194 return ret
.ToString();
197 public static Literal
Parse(string literal
, NamespaceManager namespaces
) {
198 if (literal
.Length
< 2 || literal
[0] != '\"') throw new FormatException("Literal value must start with a quote.");
199 int quote
= literal
.LastIndexOf('"');
200 if (quote
<= 0) throw new FormatException("Literal value must have an end quote (" + literal
+ ")");
201 string value = literal
.Substring(1, quote
-1);
202 literal
= literal
.Substring(quote
+1);
204 value = value.Replace("\\\"", "\"");
205 value = value.Replace("\\\\", "\\");
208 string datatype
= null;
210 if (literal
.Length
>= 2 && literal
[0] == '@') {
211 int type
= literal
.IndexOf("^^");
212 if (type
== -1) lang
= literal
.Substring(1);
214 lang
= literal
.Substring(1, type
);
215 literal
= literal
.Substring(type
);
219 if (literal
.StartsWith("^^")) {
220 if (literal
.StartsWith("^^<") && literal
.EndsWith(">")) {
221 datatype
= literal
.Substring(3, literal
.Length
-4);
223 if (namespaces
== null)
224 throw new ArgumentException("No NamespaceManager was given to resolve the QName in the literal string.");
225 datatype
= namespaces
.Resolve(literal
.Substring(2));
229 return new Literal(value, lang
, datatype
);
234 public abstract class LiteralFilter : Resource {
235 public LiteralFilter() : base(null) { }
237 public override string Uri { get { return null; } }
239 public abstract bool Matches(Literal literal);
242 public interface SQLLiteralFilter {
243 string GetSQLFunction();
246 public class LiteralNumericComparison : LiteralFilter, SQLLiteralFilter {
250 public LiteralNumericComparison(double value, Op comparison) {
251 this.value = value; this.comparison = comparison;
263 public override bool Matches(Literal literal) {
265 if (!double.TryParse(literal.Value, System.Globalization.NumberStyles.Any, null, out v)) return false;
267 switch (comparison) {
268 case Op.Equal: return v == value;
269 case Op.NotEqual: return v != value;
270 case Op.GreaterThan: return v > value;
271 case Op.GreaterThanOrEqual: return v >= value;
272 case Op.LessThan: return v < value;
273 case Op.LessThanOrEqual: return v <= value;
274 default: return false;
278 public string GetSQLFunction() {
279 switch (comparison) {
280 case Op.Equal: return "literal = " + value;
281 case Op.NotEqual: return "literal != " + value;
282 case Op.GreaterThan: return "literal > " + value;
283 case Op.GreaterThanOrEqual: return "literal >= " + value;
284 case Op.LessThan: return "literal < " + value;
285 case Op.LessThanOrEqual: return "literal <= " + value;
286 default: return null;
291 public class LiteralStringComparison : LiteralFilter, SQLLiteralFilter {
295 public LiteralStringComparison(string value, Op comparison) {
296 this.value = value; this.comparison = comparison;
308 public override bool Matches(Literal literal) {
309 string v = literal.Value;
311 switch (comparison) {
312 case Op.Equal: return v == value;
313 case Op.NotEqual: return v != value;
314 case Op.GreaterThan: return v.CompareTo(value) > 0;
315 case Op.GreaterThanOrEqual: return v.CompareTo(value) >= 0;
316 case Op.LessThan: return v.CompareTo(value) < 0;
317 case Op.LessThanOrEqual: return v.CompareTo(value) <= 0;
318 default: return false;
322 public string GetSQLFunction() {
323 switch (comparison) {
324 case Op.Equal: return "literal = " + value;
325 case Op.NotEqual: return "literal != " + value;
326 case Op.GreaterThan: return "literal > " + value;
327 case Op.GreaterThanOrEqual: return "literal >= " + value;
328 case Op.LessThan: return "literal < " + value;
329 case Op.LessThanOrEqual: return "literal <= " + value;
330 default: return null;
337 namespace SemWeb
.Bind
{
342 public Any(Entity entity
, Store model
) {
347 public Entity Entity { get { return ent; }
}
348 public Store Model { get { return model; }
}
350 public string Uri { get { return ent.Uri; }
}
352 private Resource
toRes(object value) {
353 if (value == null) return null;
354 if (value is Resource
) return (Resource
)value; // shouldn't happen
355 if (value is string) return new Literal((string)value);
356 if (value is Any
) return ((Any
)value).ent
;
357 throw new ArgumentException("value is not of a recognized type");
360 protected void AddValue(Entity predicate
, object value, bool forward
) {
361 if (value == null) throw new ArgumentNullException("value");
362 Resource v
= toRes(value);
363 if (!forward
&& !(v
is Entity
)) throw new ArgumentException("Cannot set this property to a literal value.");
364 Statement
add = new Statement(ent
, predicate
, v
);
365 if (!forward
) add = add.Invert();
368 protected void RemoveValue(Entity predicate
, object value, bool forward
) {
369 if (value == null) throw new ArgumentNullException("value");
370 Resource v
= toRes(value);
371 if (!forward
&& !(v
is Entity
)) throw new ArgumentException("Cannot set this property to a literal value.");
372 Statement rem
= new Statement(ent
, predicate
, v
);
373 if (!forward
) rem
= rem
.Invert();
377 protected void SetFuncProperty(Entity predicate
, object value, bool forward
) {
378 Resource v
= toRes(value);
379 Statement search
= new Statement(ent
, predicate
, null);
380 Statement replace
= new Statement(ent
, predicate
, v
);
382 if (v
!= null && !(v
is Entity
)) throw new ArgumentException("Cannot set this property to a literal value.");
383 search
= search
.Invert();
384 replace
= replace
.Invert();
388 foreach (Statement s
in model
.Select(search
)) {
389 model
.Replace(s
, replace
);
394 model
.Remove(search
);
398 protected void SetNonFuncProperty(Entity predicate
, object[] values
, bool forward
) {
399 Statement search
= new Statement(ent
, predicate
, null);
401 search
= search
.Invert();
403 model
.Remove(search
);
404 if (values
!= null) {
405 foreach (object value in values
) {
406 Resource v
= toRes(value);
407 if (v
== null) throw new ArgumentNullException("element of values array");
408 if (!forward
&& !(v
is Entity
)) throw new ArgumentException("Cannot set this property to a literal value.");
409 Statement
add = new Statement(ent
, predicate
, v
);
410 if (!forward
) add = add.Invert();