public void NodeLiteralLanguageSpecifierCase1() { NodeFactory factory = new NodeFactory(); ILiteralNode lcase = factory.CreateLiteralNode("example", "en-gb"); ILiteralNode ucase = factory.CreateLiteralNode("example", "en-GB"); Assert.True(EqualityHelper.AreLiteralsEqual(lcase, ucase)); }
/// <summary> /// Determines whether this Node is equal to a Graph Literal Node /// </summary> /// <param name="other">Graph Literal Node</param> /// <returns></returns> public override bool Equals(IGraphLiteralNode other) { if (ReferenceEquals(this, other)) { return(true); } return(EqualityHelper.AreGraphLiteralsEqual(this, other)); }
public void NodeAsValuedTimeSpan() { INode orig = new TimeSpan(1, 0, 0).ToLiteral(_graph); IValuedNode valued = orig.AsValuedNode(); Assert.AreEqual(((ILiteralNode)orig).Value, ((ILiteralNode)valued).Value); Assert.IsTrue(EqualityHelper.AreUrisEqual(((ILiteralNode)orig).DataType, ((ILiteralNode)valued).DataType)); Assert.AreEqual(typeof(TimeSpanNode), valued.GetType()); }
/// <summary> /// Determines whether this Node is equal to a Literal Node /// </summary> /// <param name="other">Literal Node</param> /// <returns></returns> public override bool Equals(ILiteralNode other) { if (ReferenceEquals(this, other)) { return(true); } if (other == null) { return(false); } return(EqualityHelper.AreLiteralsEqual(this, other)); }
/// <summary> /// Determines whether this Node is equal to a URI Node. /// </summary> /// <param name="other">URI Node.</param> /// <returns></returns> public override bool Equals(IUriNode other) { if ((Object)other == null) { return(false); } if (ReferenceEquals(this, other)) { return(true); } return(EqualityHelper.AreUrisEqual(_uri, other.Uri)); }
/// <summary> /// Determines whether this Node is equal to a Variable Node /// </summary> /// <param name="other">Variable Node</param> /// <returns></returns> public override bool Equals(IVariableNode other) { if ((Object)other == null) { return(false); } if (ReferenceEquals(this, other)) { return(true); } return(EqualityHelper.AreVariablesEqual(this, other)); }
/// <summary> /// Determines whether two URIs are equal /// </summary> /// <param name="a">First URI Node</param> /// <param name="b">Second URI Node</param> /// <returns></returns> public static bool AreUrisEqual(IUriNode a, IUriNode b) { if (ReferenceEquals(a, b)) { return(true); } if (a == null) { if (b == null) { return(true); } return(false); } else if (b == null) { return(false); } return(EqualityHelper.AreUrisEqual(a.Uri, b.Uri)); }
/// <summary> /// Implementation of the Equals method for Graph Literal Nodes. Graph Literals are considered Equal if their respective Subgraphs are equal /// </summary> /// <param name="other">Object to compare the Node with</param> /// <returns></returns> public override bool Equals(INode other) { if ((Object)other == null) { return(false); } if (ReferenceEquals(this, other)) { return(true); } if (other.NodeType == NodeType.GraphLiteral) { return(EqualityHelper.AreGraphLiteralsEqual(this, (IGraphLiteralNode)other)); } else { //Can only be equal to a Graph Literal Node return(false); } }
/// <summary> /// Gets whether this Node is equal to some other Node /// </summary> /// <param name="other">Node to test</param> /// <returns></returns> public override bool Equals(INode other) { if ((Object)other == null) { return(false); } if (ReferenceEquals(this, other)) { return(true); } if (other.NodeType == NodeType.Variable) { return(EqualityHelper.AreVariablesEqual(this, (IVariableNode)other)); } else { // Can only be equal to other Variables return(false); } }
/// <summary> /// Implementation of Equality for Uri Nodes. /// </summary> /// <param name="other">Object to compare with.</param> /// <returns></returns> /// <remarks> /// URI Nodes are considered equal if the string form of their URIs match using Ordinal string comparison. /// </remarks> public override bool Equals(INode other) { if ((Object)other == null) { return(false); } if (ReferenceEquals(this, other)) { return(true); } if (other.NodeType == NodeType.Uri) { Uri temp = ((IUriNode)other).Uri; return(EqualityHelper.AreUrisEqual(_uri, temp)); } else { // Can only be equal to UriNodes return(false); } }
/// <summary> /// Implementation of Equals for Blank Nodes. /// </summary> /// <param name="other">Object to compare with the Blank Node.</param> /// <returns></returns> /// <remarks> /// Blank Nodes are considered equal if their internal IDs match precisely and they originate from the same Graph. /// </remarks> public override bool Equals(INode other) { if ((Object)other == null) { return(false); } if (ReferenceEquals(this, other)) { return(true); } if (other.NodeType == NodeType.Blank) { IBlankNode temp = (IBlankNode)other; return(EqualityHelper.AreBlankNodesEqual(this, temp)); } else { // Can only be equal to Blank Nodes return(false); } }
/// <summary> /// Compares two Literal Nodes. /// </summary> /// <param name="a">First Literal Node.</param> /// <param name="b">Second Literal Node.</param> /// <param name="culture">Culture to use for lexical string comparisons where more natural comparisons are not possible/applicable.</param> /// <param name="comparisonOptions">String Comparison options used for lexical string comparisons where more natural comparisons are not possible/applicable.</param> /// <returns></returns> public static int CompareLiterals(ILiteralNode a, ILiteralNode b, CultureInfo culture, CompareOptions comparisonOptions) { if (ReferenceEquals(a, b)) { return(0); } if (a == null) { if (b == null) { return(0); } return(-1); } else if (b == null) { return(1); } // initialize required culture and comparison options if (culture == null) { culture = Options.DefaultCulture; } if (comparisonOptions == CompareOptions.None) { comparisonOptions = Options.DefaultComparisonOptions; } // Literal Nodes are ordered based on Type and lexical form if (a.DataType == null && b.DataType != null) { // Untyped Literals are less than Typed Literals // Return a -1 to indicate this return(-1); } else if (a.DataType != null && b.DataType == null) { // Typed Literals are greater than Untyped Literals // Return a 1 to indicate this return(1); } else if (a.DataType == null && b.DataType == null) { return(culture.CompareInfo.Compare(a.Value, b.Value, comparisonOptions)); } else if (EqualityHelper.AreUrisEqual(a.DataType, b.DataType)) { // Are we using a known and orderable DataType? String type = a.DataType.AbsoluteUri; if (!XmlSpecsHelper.IsSupportedType(type)) { // Don't know how to order so use specified order on the value return(culture.CompareInfo.Compare(a.Value, b.Value, comparisonOptions)); } else { try { switch (type) { case XmlSpecsHelper.XmlSchemaDataTypeBoolean: // Can use Lexical ordering for this so use specified order on the value bool aBool, bBool; if (Boolean.TryParse(a.Value, out aBool)) { if (Boolean.TryParse(b.Value, out bBool)) { return(aBool.CompareTo(bBool)); } else { return(-1); } } else { if (Boolean.TryParse(b.Value, out bBool)) { return(1); } goto default; } case XmlSpecsHelper.XmlSchemaDataTypeByte: // Remember that xsd:byte is actually equivalent to SByte in .Net // Extract the Byte Values and compare sbyte aSByte, bSByte; if (SByte.TryParse(a.Value, out aSByte)) { if (SByte.TryParse(b.Value, out bSByte)) { return(aSByte.CompareTo(bSByte)); } else { return(-1); } } else { if (SByte.TryParse(b.Value, out bSByte)) { return(1); } goto default; } case XmlSpecsHelper.XmlSchemaDataTypeUnsignedByte: // Remember that xsd:unsignedByte is equivalent to Byte in .Net // Extract the Byte Values and compare byte aByte, bByte; if (Byte.TryParse(a.Value, out aByte)) { if (Byte.TryParse(b.Value, out bByte)) { return(aByte.CompareTo(bByte)); } else { return(-1); } } else { if (Byte.TryParse(b.Value, out bByte)) { return(1); } else { goto default; } } case XmlSpecsHelper.XmlSchemaDataTypeInt: case XmlSpecsHelper.XmlSchemaDataTypeInteger: case XmlSpecsHelper.XmlSchemaDataTypeLong: case XmlSpecsHelper.XmlSchemaDataTypeShort: // Extract the Integer Values and compare long aInt64, bInt64; if (Int64.TryParse(a.Value, out aInt64)) { if (Int64.TryParse(b.Value, out bInt64)) { return(aInt64.CompareTo(bInt64)); } else { return(-1); } } else { if (Int64.TryParse(b.Value, out bInt64)) { return(1); } else { goto default; } } case XmlSpecsHelper.XmlSchemaDataTypeNegativeInteger: case XmlSpecsHelper.XmlSchemaDataTypeNonPositiveInteger: // Extract the Integer Values, ensure negative and compare long aNegInt, bNegInt; if (Int64.TryParse(a.Value, out aNegInt)) { if (Int64.TryParse(b.Value, out bNegInt)) { if (aNegInt >= 0) { if (bNegInt >= 0) { goto default; } else { return(1); } } else if (bNegInt >= 0) { return(-1); } else { return(aNegInt.CompareTo(bNegInt)); } } else if (aNegInt >= 0) { goto default; } else { return(-1); } } else { if (Int64.TryParse(b.Value, out bNegInt)) { if (bNegInt >= 0) { goto default; } else { return(1); } } else { goto default; } } case XmlSpecsHelper.XmlSchemaDataTypeUnsignedInt: case XmlSpecsHelper.XmlSchemaDataTypeUnsignedLong: case XmlSpecsHelper.XmlSchemaDataTypeUnsignedShort: case XmlSpecsHelper.XmlSchemaDataTypeNonNegativeInteger: case XmlSpecsHelper.XmlSchemaDataTypePositiveInteger: // Unsigned Integers // Note that for NonNegativeInteger and PositiveInteger we don't need to do the // same checking we have to do for their inverse types since parsing into an // Unsigned Long ensures that they must be positive ulong aUInt64, bUInt64; if (UInt64.TryParse(a.Value, out aUInt64)) { if (UInt64.TryParse(b.Value, out bUInt64)) { return(aUInt64.CompareTo(bUInt64)); } else { return(-1); } } else { if (UInt64.TryParse(b.Value, out bUInt64)) { return(1); } else { goto default; } } case XmlSpecsHelper.XmlSchemaDataTypeDouble: // Extract the Double Values and compare double aDouble, bDouble; if (Double.TryParse(a.Value, NumberStyles.Any, CultureInfo.InvariantCulture, out aDouble)) { if (Double.TryParse(b.Value, NumberStyles.Any, CultureInfo.InvariantCulture, out bDouble)) { return(aDouble.CompareTo(bDouble)); } else { return(-1); } } else { if (Double.TryParse(b.Value, NumberStyles.Any, CultureInfo.InvariantCulture, out bDouble)) { return(1); } else { goto default; } } case XmlSpecsHelper.XmlSchemaDataTypeDecimal: // Extract the Decimal Values and compare decimal aDecimal, bDecimal; if (decimal.TryParse(a.Value, NumberStyles.Any, CultureInfo.InvariantCulture, out aDecimal)) { if (decimal.TryParse(b.Value, NumberStyles.Any, CultureInfo.InvariantCulture, out bDecimal)) { return(aDecimal.CompareTo(bDecimal)); } else { return(-1); } } else { if (decimal.TryParse(b.Value, NumberStyles.Any, CultureInfo.InvariantCulture, out bDecimal)) { return(1); } else { goto default; } } case XmlSpecsHelper.XmlSchemaDataTypeFloat: // Extract the Float Values and compare float aFloat, bFloat; if (Single.TryParse(a.Value, NumberStyles.Any, CultureInfo.InvariantCulture, out aFloat)) { if (Single.TryParse(b.Value, NumberStyles.Any, CultureInfo.InvariantCulture, out bFloat)) { return(aFloat.CompareTo(bFloat)); } else { return(-1); } } else { if (Single.TryParse(b.Value, NumberStyles.Any, CultureInfo.InvariantCulture, out bFloat)) { return(1); } else { goto default; } } case XmlSpecsHelper.XmlSchemaDataTypeHexBinary: // Extract the numeric value of the Hex encoded Binary and compare long aHex, bHex; if (Int64.TryParse(a.Value, NumberStyles.HexNumber, null, out aHex)) { if (Int64.TryParse(b.Value, NumberStyles.HexNumber, null, out bHex)) { return(aHex.CompareTo(bHex)); } else { return(-1); } } else { if (Int64.TryParse(b.Value, NumberStyles.HexNumber, null, out bHex)) { return(1); } else { goto default; } } case XmlSpecsHelper.XmlSchemaDataTypeBase64Binary: // Extract the numeric value of the Base 64 encoded Binary and compare byte[] aBin, bBin; try { aBin = Convert.FromBase64String(a.Value); try { bBin = Convert.FromBase64String(b.Value); if (aBin.Length > bBin.Length) { return(1); } else if (aBin.Length < bBin.Length) { return(-1); } else { for (int i = 0; i < aBin.Length; i++) { if (aBin[i] != bBin[i]) { return(aBin[i].CompareTo(bBin[i])); } } return(0); } } catch { return(-1); } } catch { try { bBin = Convert.FromBase64String(b.Value); return(1); } catch { goto default; } } case XmlSpecsHelper.XmlSchemaDataTypeString: // String Type // Can use Lexical Ordering for thisgoto default; case XmlSpecsHelper.XmlSchemaDataTypeAnyUri: // Uri Type // Try and convert to a URI and use lexical ordering Uri aUri, bUri; try { aUri = UriFactory.Create(a.Value); try { bUri = UriFactory.Create(b.Value); return(CompareUris(aUri, bUri)); } catch { return(-1); } } catch { try { bUri = UriFactory.Create(b.Value); return(1); } catch { goto default; } } case XmlSpecsHelper.XmlSchemaDataTypeDate: case XmlSpecsHelper.XmlSchemaDataTypeDateTime: // Extract the Date Times and compare DateTimeOffset aDateTimeOffset, bDateTimeOffset; if (DateTimeOffset.TryParse(a.Value, out aDateTimeOffset)) { if (DateTimeOffset.TryParse(b.Value, out bDateTimeOffset)) { return(aDateTimeOffset.CompareTo(bDateTimeOffset)); } else { return(-1); } } else { if (DateTimeOffset.TryParse(b.Value, out bDateTimeOffset)) { return(1); } else { goto default; } } case XmlSpecsHelper.XmlSchemaDataTypeDuration: case XmlSpecsHelper.XmlSchemaDataTypeDayTimeDuration: // Extract the TimeSpan's and compare TimeSpan aTimeSpan, bTimeSpan; try { aTimeSpan = XmlConvert.ToTimeSpan(a.Value); try { bTimeSpan = XmlConvert.ToTimeSpan(b.Value); return(aTimeSpan.CompareTo(bTimeSpan)); } catch { return(-1); } } catch { try { bTimeSpan = XmlConvert.ToTimeSpan(b.Value); return(1); } catch { goto default; } } default: // Don't know how to order so use lexical ordering on the value // return String.Compare(a.Value, b.Value, culture, comparisonOptions); return(culture.CompareInfo.Compare(a.Value, b.Value, comparisonOptions)); } } catch { // There was some error suggesting a non-valid value for a type // e.g. "example"^^xsd:integer // In this case just use lexical ordering on the value // return String.Compare(a.Value, b.Value, culture, comparisonOptions); return(culture.CompareInfo.Compare(a.Value, b.Value, comparisonOptions)); } } } else { // No way of ordering by value if the Data Types are different // Order by Data Type Uri // This is required or the Value ordering between types won't occur correctly return(CompareUris(a.DataType, b.DataType)); } }
/// <summary> /// Determines whether two URIs are equal. /// </summary> /// <param name="x">URI.</param> /// <param name="y">URI.</param> /// <returns></returns> public bool Equals(Uri x, Uri y) { return(EqualityHelper.AreUrisEqual(x, y)); }
internal void Discard() { try { _persisting = true; _removedGraphs.Clear(); // Read-Only managers have no persistence if (_manager.IsReadOnly) { return; } // No actions mean no persistence necessary if (_actions.Count == 0) { return; } // Important - For discard we reverse the list of actions so that we // rollback the actions in appropriate order _actions.Reverse(); if (_manager.UpdateSupported) { // Persist based on Triple level actions // First group Triple together based on Graph URI while (_actions.Count > 0) { TripleStorePersistenceAction action = _actions[0]; if (action.IsTripleAction) { Queue <TriplePersistenceAction> actions = new Queue <TriplePersistenceAction>(); Uri currUri = _actions[0].TripleAction.Triple.GraphUri; actions.Enqueue(_actions[0].TripleAction); _actions.RemoveAt(0); // Find all the Triple actions related to this Graph up to the next non-Triple action for (int i = 0; i < _actions.Count && _actions[i].IsTripleAction; i++) { if (EqualityHelper.AreUrisEqual(currUri, _actions[i].TripleAction.Triple.GraphUri)) { actions.Enqueue(_actions[i].TripleAction); _actions.RemoveAt(i); i--; } } // Split the Triples for this Graph into batches of adds and deletes to ensure // accurate persistence of the actions bool toDelete = false; List <Triple> batch = new List <Triple>(); while (actions.Count > 0) { TriplePersistenceAction next = actions.Dequeue(); if (next.IsDelete != toDelete) { if (batch.Count > 0) { // Process a batch whenever we find a switch between additions and removals // This ensures that regardless of the logic in UpdateGraph() we force // additions and removals to happen in the order we care about // Important - For discard we flip the actions in order to reverse them // i.e. additions become removals and vice versa // Also for discard we only need to alter the in-memory state not actually // do any persistence since the actions will never have been persisted if (toDelete) { this[currUri].Assert(batch); } else { this[currUri].Retract(batch); } batch.Clear(); } toDelete = next.IsDelete; } batch.Add(next.Triple); } // Ensure the final batch (if any) gets processed if (batch.Count > 0) { // Important - For discard we flip the actions in order to reverse them // i.e. additions become removals and vice versa // Also for discard we only need to alter the in-memory state not actually // do any persistence since the actions will never have been persisted if (toDelete) { this[currUri].Assert(batch); } else { this[currUri].Retract(batch); } } } else { switch (action.GraphAction.Action) { case GraphPersistenceActionType.Added: // Need to remove from being in-memory Remove(action.GraphAction.Graph.BaseUri); break; case GraphPersistenceActionType.Deleted: // Need to add back into memory Add(action.GraphAction.Graph, false); break; } _actions.RemoveAt(0); } } } else { // Persist based on Graph level actions foreach (TripleStorePersistenceAction action in _actions) { // Important - For discard we flip the actions in order to reverse them // i.e. additions become removals and vice versa if (action.IsGraphAction) { if (action.GraphAction.Action == GraphPersistenceActionType.Added) { Remove(action.GraphAction.Graph.BaseUri); } else if (action.GraphAction.Action == GraphPersistenceActionType.Deleted) { Add(action.GraphAction.Graph, false); } } } } } finally { _persisting = false; } }
internal void Flush() { try { _persisting = true; _removedGraphs.Clear(); // Read-Only managers have no persistence if (_manager.IsReadOnly) { return; } // No actions means no persistence necessary if (_actions.Count == 0) { return; } if (_manager.UpdateSupported) { // Persist based on Triple level actions // First group Triple together based on Graph URI while (_actions.Count > 0) { TripleStorePersistenceAction action = _actions[0]; if (action.IsTripleAction) { Queue <TriplePersistenceAction> actions = new Queue <TriplePersistenceAction>(); Uri currUri = action.TripleAction.Triple.GraphUri; actions.Enqueue(_actions[0].TripleAction); _actions.RemoveAt(0); // Find all the Triple actions related to this Graph up to the next non-Triple action for (int i = 0; i < _actions.Count && _actions[i].IsTripleAction; i++) { if (EqualityHelper.AreUrisEqual(currUri, _actions[i].TripleAction.Triple.GraphUri)) { actions.Enqueue(_actions[i].TripleAction); _actions.RemoveAt(i); i--; } } // Split the Triple Actions for this Graph into batches of adds and deletes to ensure // accurate persistence of the actions bool toDelete = false; List <Triple> batch = new List <Triple>(); while (actions.Count > 0) { TriplePersistenceAction next = actions.Dequeue(); if (next.IsDelete != toDelete) { if (batch.Count > 0) { // Process a batch whenever we find a switch between additions and removals // This ensures that regardless of the logic in UpdateGraph() we force // additions and removals to happen in the order we care about if (toDelete) { _manager.UpdateGraph(currUri, null, batch); } else { _manager.UpdateGraph(currUri, batch, null); } batch.Clear(); } toDelete = next.IsDelete; } batch.Add(next.Triple); } // Ensure the final batch (if any) gets processed if (batch.Count > 0) { if (toDelete) { _manager.UpdateGraph(currUri, null, batch); } else { _manager.UpdateGraph(currUri, batch, null); } } } else { switch (action.GraphAction.Action) { case GraphPersistenceActionType.Added: // No need to do anything in-memory as will be in the graph collection // Call SaveGraph() with an empty graph to create the relevant graph // If Triples were added these will be persisted separately with // TriplePersistenceActions Graph g = new Graph(); g.BaseUri = action.GraphAction.Graph.BaseUri; _manager.SaveGraph(g); break; case GraphPersistenceActionType.Deleted: // No need to do anything in-memory as won't be in the graph collection // If DeleteGraph() is supported call it to delete the relevant graph if (_manager.DeleteSupported) { _manager.DeleteGraph(action.GraphAction.Graph.BaseUri); } break; } _actions.RemoveAt(0); } } } else { // Persist based on Graph level actions foreach (TripleStorePersistenceAction action in _actions) { if (action.IsGraphAction) { if (action.GraphAction.Action == GraphPersistenceActionType.Added) { _manager.SaveGraph(action.GraphAction.Graph); } else if (action.GraphAction.Action == GraphPersistenceActionType.Deleted && _manager.DeleteSupported) { // Can only delete graphs if deletion is supported _manager.DeleteGraph(action.GraphAction.Graph.BaseUri); } } } } } finally { _persisting = false; } }
/// <summary> /// Determines whether this Node is equal to another. /// </summary> /// <param name="other">Other Blank Node.</param> /// <returns></returns> public override bool Equals(IBlankNode other) { return(EqualityHelper.AreBlankNodesEqual(this, other)); }
/// <summary> /// Determines whether two Literals are equal /// </summary> /// <param name="a">First Literal</param> /// <param name="b">Second Literal</param> /// <returns></returns> public static bool AreLiteralsEqual(ILiteralNode a, ILiteralNode b) { if (ReferenceEquals(a, b)) { return(true); } if (a == null) { if (b == null) { return(true); } return(false); } else if (b == null) { return(false); } //Language Tags must be equal (if present) //If they don't have language tags then they'll both be set to String.Empty which will give true if (a.Language.Equals(b.Language, StringComparison.OrdinalIgnoreCase)) { //Datatypes must be equal (if present) //If they don't have Data Types then they'll both be null //Otherwise the URIs must be equal if (a.DataType == null && b.DataType == null) { //Use String equality to get the result return(a.Value.Equals(b.Value, StringComparison.Ordinal)); } else if (a.DataType == null) { //We have a Null DataType but the other Node doesn't so can't be equal return(false); } else if (b.DataType == null) { //The other Node has a Null DataType but we don't so can't be equal return(false); } else if (EqualityHelper.AreUrisEqual(a.DataType, b.DataType)) { //We have equal DataTypes so use String Equality to evaluate if (Options.LiteralEqualityMode == LiteralEqualityMode.Strict) { //Strict Equality Mode uses Ordinal Lexical Comparison for Equality as per W3C RDF Spec return(a.Value.Equals(b.Value, StringComparison.Ordinal)); } else { //Loose Equality Mode uses Value Based Comparison for Equality of Typed Nodes return(a.CompareTo(b) == 0); } } else { //Data Types didn't match return(false); } } else { //Language Tags didn't match return(false); } }