private bool TryWritingStartElement(IUriNode node) { FriendlyRdfXmlWriter.Split(node.Uri, out string nsUri, out string localName); if (!XmlSpecsHelper.IsNCName(localName)) { return(false); } this.writer.WriteStartElement(localName, nsUri); return(true); }
/// <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> /// Is something a valid partial QName? /// </summary> /// <param name="value">Value</param> /// <returns></returns> protected virtual bool IsValidPartialQName(String value) { String ns, localname; if (value.Contains(':')) { ns = value.Substring(0, value.IndexOf(':')); localname = value.Substring(value.IndexOf(':') + 1); } else { ns = value; localname = String.Empty; } //Namespace Validation if (!ns.Equals(String.Empty)) { //Allowed empty Namespace if (ns.StartsWith("-")) { //Can't start with a - return(false); } else { char[] nchars = ns.ToCharArray(); if (XmlSpecsHelper.IsNameStartChar(nchars[0]) && nchars[0] != '_') { if (nchars.Length > 1) { for (int i = 1; i < nchars.Length; i++) { //Not a valid Name Char if (!XmlSpecsHelper.IsNameChar(nchars[i])) { return(false); } if (nchars[i] == '.') { return(false); } } //If we reach here the Namespace is OK } else { //Only 1 Character which was valid so OK } } else { //Doesn't start with a valid Name Start Char return(false); } } } //Local Name Validation if (!localname.Equals(String.Empty)) { //Allowed empty Local Name char[] lchars = localname.ToCharArray(); if (XmlSpecsHelper.IsNameStartChar(lchars[0])) { if (lchars.Length > 1) { for (int i = 1; i < lchars.Length; i++) { //Not a valid Name Char if (!XmlSpecsHelper.IsNameChar(lchars[i])) { return(false); } if (lchars[i] == '.') { return(false); } } //If we reach here the Local Name is OK } else { //Only 1 Character which was valid so OK } } else { //Not a valid Name Start Char return(false); } } //If we reach here then it's all valid return(true); }
/// <summary> /// Compares two Nodes /// </summary> /// <param name="x">Node</param> /// <param name="y">Node</param> /// <returns></returns> public override int Compare(IValuedNode x, IValuedNode y) { // Nulls are less than everything if (x == null && y == null) { return(0); } if (x == null) { return(-1); } if (y == null) { return(1); } // If the Node Types are different use Node ordering if (x.NodeType != y.NodeType) { return(x.CompareTo(y)); } if (x.NodeType == NodeType.Literal) { try { // Do they have supported Data Types? String xtype, ytype; try { xtype = XmlSpecsHelper.GetSupportedDataType(x); ytype = XmlSpecsHelper.GetSupportedDataType(y); } catch (RdfException) { // Can't determine a Data Type for one/both of the Nodes so use Node ordering return(x.CompareTo(y)); } if (xtype.Equals(String.Empty) || ytype.Equals(String.Empty)) { // One/both has an unknown type if (x.Equals(y)) { // If RDF Term equality returns true then we return that they are equal return(0); } else { // If RDF Term equality returns false then we fall back to Node Ordering return(x.CompareTo(y)); } } else { // Both have known types SparqlNumericType xnumtype = x.NumericType; SparqlNumericType ynumtype = y.NumericType; SparqlNumericType numtype = (SparqlNumericType)Math.Max((int)xnumtype, (int)ynumtype); if (numtype != SparqlNumericType.NaN) { if (xnumtype == SparqlNumericType.NaN) { return(1); } else if (ynumtype == SparqlNumericType.NaN) { return(-1); } // Both are Numeric so use Numeric ordering try { return(this.NumericCompare(x, y, numtype)); } catch (FormatException) { if (x.Equals(y)) { return(0); } // Otherwise fall back to Node Ordering return(x.CompareTo(y)); } catch (RdfQueryException) { // If this errors try RDF Term equality since that might still give equality if (x.Equals(y)) { return(0); } // Otherwise fall back to Node Ordering return(x.CompareTo(y)); } } else if (xtype.Equals(ytype)) { switch (xtype) { case XmlSpecsHelper.XmlSchemaDataTypeDate: return(DateCompare(x, y)); case XmlSpecsHelper.XmlSchemaDataTypeDateTime: return(DateTimeCompare(x, y)); case XmlSpecsHelper.XmlSchemaDataTypeString: // Both Strings so use Lexical string ordering return(((ILiteralNode)x).Value.CompareTo(((ILiteralNode)y).Value)); default: // Use node ordering return(x.CompareTo(y)); } } else { String commontype = XmlSpecsHelper.GetCompatibleSupportedDataType(xtype, ytype, true); if (commontype.Equals(String.Empty)) { // Use Node ordering return(x.CompareTo(y)); } else { switch (commontype) { case XmlSpecsHelper.XmlSchemaDataTypeDate: return(DateCompare(x, y)); case XmlSpecsHelper.XmlSchemaDataTypeDateTime: return(DateTimeCompare(x, y)); default: // Use Node ordering return(x.CompareTo(y)); } } } } } catch { // If error then can't determine ordering so fall back to node ordering return(x.CompareTo(y)); } } else { // If not Literals use Node ordering return(x.CompareTo(y)); } }
/// <summary> /// Compares two Nodes /// </summary> /// <param name="x">Node</param> /// <param name="y">Node</param> /// <returns></returns> public virtual int Compare(INode x, INode y) { // Nulls are less than everything if (x == null && y == null) { return(0); } if (x == null) { return(-1); } if (y == null) { return(1); } // If the Node Types are different use Node ordering if (x.NodeType != y.NodeType) { return(x.CompareTo(y)); } if (x.NodeType == NodeType.Literal) { // Do they have supported Data Types? String xtype, ytype; try { xtype = XmlSpecsHelper.GetSupportedDataType(x); ytype = XmlSpecsHelper.GetSupportedDataType(y); } catch (RdfException) { // Can't determine a Data Type for one/both of the Nodes so use Node ordering return(x.CompareTo(y)); } if (xtype.Equals(String.Empty) || ytype.Equals(String.Empty)) { // One/both has an unknown type if (x.Equals(y)) { // If RDF Term equality returns true then we return that they are equal return(0); } else { // If RDF Term equality returns false then we error // UNLESS they have the same Datatype throw new RdfQueryException("Unable to determine ordering since one/both arguments has an Unknown Type"); } } else { // Both have known types SparqlNumericType xnumtype = SparqlSpecsHelper.GetNumericTypeFromDataTypeUri(xtype); SparqlNumericType ynumtype = SparqlSpecsHelper.GetNumericTypeFromDataTypeUri(ytype); SparqlNumericType numtype = (SparqlNumericType)Math.Max((int)xnumtype, (int)ynumtype); if (numtype != SparqlNumericType.NaN) { if (xnumtype == SparqlNumericType.NaN || ynumtype == SparqlNumericType.NaN) { // If one is non-numeric then we can't assume non-equality throw new RdfQueryException("Unable to determine ordering since one/both arguments does not return a Number"); } // Both are Numeric so use Numeric ordering try { return(this.NumericCompare(x, y, numtype)); } catch (FormatException) { if (x.Equals(y)) { return(0); } throw new RdfQueryException("Unable to determine ordering since one/both arguments does not contain a valid value for it's type"); } catch (RdfQueryException) { // If this errors try RDF Term equality since if (x.Equals(y)) { return(0); } throw new RdfQueryException("Unable to determine ordering since one/both arguments was not a valid numeric"); } } else if (xtype.Equals(ytype)) { switch (xtype) { case XmlSpecsHelper.XmlSchemaDataTypeDate: return(DateCompare(x, y)); case XmlSpecsHelper.XmlSchemaDataTypeDateTime: return(DateTimeCompare(x, y)); case XmlSpecsHelper.XmlSchemaDataTypeString: // Both Strings so use Lexical string ordering #if NETCORE return(Options.DefaultCulture.CompareInfo.Compare(((ILiteralNode)x).Value, ((ILiteralNode)y).Value, Options.DefaultComparisonOptions)); #else return(String.Compare(((ILiteralNode)x).Value, ((ILiteralNode)y).Value, Options.DefaultCulture, Options.DefaultComparisonOptions)); #endif default: // Use node ordering return(x.CompareTo(y)); } } else { String commontype = XmlSpecsHelper.GetCompatibleSupportedDataType(xtype, ytype, true); if (commontype.Equals(String.Empty)) { // Use Node ordering return(x.CompareTo(y)); } else { switch (commontype) { case XmlSpecsHelper.XmlSchemaDataTypeDate: return(DateCompare(x, y)); case XmlSpecsHelper.XmlSchemaDataTypeDateTime: return(DateTimeCompare(x, y)); default: // Use Node ordering return(x.CompareTo(y)); } } } } } else { // If not Literals use Node ordering return(x.CompareTo(y)); } }