static readonly string [] datetimeFormats = {
// dateTime
+#if NET_2_0
+ "yyyy-MM-ddTHH:mm:sszzz",
+ "yyyy-MM-ddTHH:mm:ss.FFFFFFFzzz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ss.FFFFFFFZ",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mm:ss.FFFFFFF",
+ "HH:mm:ss",
+ "HH:mm:ss.FFFFFFF",
+ "HH:mm:sszzz",
+ "HH:mm:ss.FFFFFFFzzz",
+ "HH:mm:ssZ",
+ "HH:mm:ss.FFFFFFFZ",
+#else // it is not required in trunk but should make it easy to backport...
"yyyy-MM-ddTHH:mm:sszzz",
"yyyy-MM-ddTHH:mm:ss.fzzz",
"yyyy-MM-ddTHH:mm:ss.ffzzz",
"HH:mm:ss.fffffZ",
"HH:mm:ss.ffffffZ",
"HH:mm:ss.fffffffZ",
+#endif
// date
"yyyy-MM-dd",
"yyyy-MM-ddzzz",
"---ddZ",
};
-#if NET_2_0
- static readonly string [] defaultDateTimeFormats = new string [] {
- "yyyy-MM-ddTHH:mm:ss", // dateTime(1)
- "yyyy-MM-ddTHH:mm:ss.FFFFFFF", // dateTime(2)
- "yyyy-MM-dd", // date
- "HH:mm:ss", // time
- "yyyy-MM", // gYearMonth
- "yyyy", // gYear
- "--MM-dd", // gMonthDay
- "---dd", // gDay
- };
-
- static readonly string [] roundtripDateTimeFormats;
- static readonly string [] localDateTimeFormats;
- static readonly string [] utcDateTimeFormats;
- static readonly string [] unspecifiedDateTimeFormats;
-
- static XmlConvert ()
- {
- int l = defaultDateTimeFormats.Length;
- roundtripDateTimeFormats = new string [l];
- localDateTimeFormats = new string [l];
- utcDateTimeFormats = new string [l * 3];
- unspecifiedDateTimeFormats = new string [l * 4];
- for (int i = 0; i < l; i++) {
- string s = defaultDateTimeFormats [i];
- localDateTimeFormats [i] = s + "zzz";
- roundtripDateTimeFormats [i] = s + 'K';
- utcDateTimeFormats [i * 3] = s;
- utcDateTimeFormats [i * 3 + 1] = s + 'Z';
- utcDateTimeFormats [i * 3 + 2] = s + "zzz";
- unspecifiedDateTimeFormats [i * 4] = s;
- unspecifiedDateTimeFormats [i * 4 + 1] = localDateTimeFormats [i];
- unspecifiedDateTimeFormats [i * 4 + 2] = roundtripDateTimeFormats [i];
- unspecifiedDateTimeFormats [i * 4 + 3] = utcDateTimeFormats [i];
- }
- }
-#endif
static DateTimeStyles _defaultStyle = DateTimeStyles.AllowLeadingWhite | DateTimeStyles.AllowTrailingWhite;
public XmlConvert()
}
#if NET_2_0
- public static DateTime ToDateTime (string value, XmlDateTimeSerializationMode mode)
+ public static DateTime ToDateTime (string s, XmlDateTimeSerializationMode dateTimeOption)
{
- DateTime dt;
- switch (mode) {
+ switch (dateTimeOption) {
case XmlDateTimeSerializationMode.Local:
- dt = ToDateTime (value, localDateTimeFormats);
- return dt == DateTime.MinValue || dt == DateTime.MaxValue ? dt : dt.ToLocalTime ();
+ return ToDateTime(s, datetimeFormats, _defaultStyle | DateTimeStyles.AssumeLocal).ToLocalTime();
case XmlDateTimeSerializationMode.RoundtripKind:
- return ToDateTime (value, roundtripDateTimeFormats, _defaultStyle | DateTimeStyles.RoundtripKind);
+ return ToDateTime(s, datetimeFormats, _defaultStyle | DateTimeStyles.RoundtripKind);
case XmlDateTimeSerializationMode.Utc:
- dt = ToDateTime (value, utcDateTimeFormats);
- return dt == DateTime.MinValue || dt == DateTime.MaxValue ? dt : dt.ToUniversalTime ();
- case XmlDateTimeSerializationMode.Unspecified:
- return ToDateTime (value, unspecifiedDateTimeFormats);
+ return ToDateTime(s, datetimeFormats, _defaultStyle | DateTimeStyles.AssumeUniversal).ToUniversalTime();
default:
- return ToDateTime (value, defaultDateTimeFormats);
+ return new DateTime (ToDateTime(s, datetimeFormats, _defaultStyle | DateTimeStyles.RoundtripKind).Ticks, DateTimeKind.Unspecified);
}
}
#endif
private static DateTime ToDateTime (string s, string [] formats, DateTimeStyles style)
{
- return DateTime.ParseExact (s, formats, DateTimeFormatInfo.InvariantInfo, style);
+ try {
+ return DateTime.ParseExact (s, formats, DateTimeFormatInfo.InvariantInfo, style);
+ } catch (ArgumentOutOfRangeException) {
+ return DateTime.MinValue;
+ }
}
public static Decimal ToDecimal(string s)
while (Char.IsWhiteSpace (s [sEndPos]))
sEndPos--;
+ if (TryParseStringConstant ("NaN", s, sidx, sEndPos))
+ return Single.NaN;
if (TryParseStringConstant ("INF", s, sidx, sEndPos))
return Single.PositiveInfinity;
if (TryParseStringConstant ("-INF", s, sidx, sEndPos))
return Single.NegativeInfinity;
- if (TryParseStringConstant ("NaN", s, sidx, sEndPos))
- return Single.NaN;
+ // Handle these here because Single.Parse("Infinity") is invalid while XmlConvert.ToSingle("Infinity") is valid.
+ if (TryParseStringConstant ("Infinity", s, sidx, sEndPos))
+ return Single.PositiveInfinity;
+ if (TryParseStringConstant ("-Infinity", s, sidx, sEndPos))
+ return Single.NegativeInfinity;
return 0;
}
StringBuilder builder = new StringBuilder ();
if (value.Ticks < 0) {
+ if (value == TimeSpan.MinValue)
+ return "-P10675199DT2H48M5.4775808S"; // There's one fewer tick on the positive side, so we cannot Negate this value; just hard-code it
builder.Append ('-');
value = value.Negate ();
}
builder.Append ('P');
if (value.Days > 0)
builder.Append (value.Days).Append ('D');
- if (value.Days > 0 || value.Hours > 0 || value.Minutes > 0 || value.Seconds > 0 || value.Milliseconds > 0) {
+ long ticks = value.Ticks % TimeSpan.TicksPerMillisecond;
+ if (value.Hours > 0 || value.Minutes > 0 || value.Seconds > 0 || value.Milliseconds > 0 || ticks > 0) {
builder.Append('T');
if (value.Hours > 0)
builder.Append (value.Hours).Append ('H');
if (value.Minutes > 0)
builder.Append (value.Minutes).Append ('M');
- if (value.Seconds > 0 || value.Milliseconds > 0) {
+ if (value.Seconds > 0 || value.Milliseconds > 0 || ticks > 0) {
builder.Append (value.Seconds);
- long ticks = value.Ticks % TimeSpan.TicksPerMillisecond;
+ bool trimZero = true;
if (ticks > 0)
builder.Append ('.').AppendFormat ("{0:0000000}", value.Ticks % TimeSpan.TicksPerSecond);
else if (value.Milliseconds > 0)
builder.Append ('.').AppendFormat ("{0:000}", value.Milliseconds);
+ else
+ trimZero = false;
+ if (trimZero)
+ while (builder [builder.Length - 1] == '0')
+ builder.Remove (builder.Length - 1, 1);
builder.Append ('S');
}
}
#if NET_2_0
- public static string ToString (DateTime value, XmlDateTimeSerializationMode mode)
+ public static string ToString (DateTime value, XmlDateTimeSerializationMode dateTimeOption)
{
// Unlike usual DateTime formatting, it preserves
// MaxValue/MinValue as is.
- switch (mode) {
+ switch (dateTimeOption) {
case XmlDateTimeSerializationMode.Local:
return (value == DateTime.MinValue ? DateTime.MinValue : value == DateTime.MaxValue ? value : value.ToLocalTime ()).ToString (
"yyyy-MM-ddTHH:mm:ss.FFFFFFFzzz",
public static TimeSpan ToTimeSpan(string s)
{
+ s = s.Trim (XmlChar.WhitespaceChars);
if (s.Length == 0)
throw new FormatException ("Invalid format string for duration schema datatype.");
}
- public static string VerifyNCName (string ncname)
+ public static string VerifyNCName (string name)
{
- if (ncname == null || ncname.Length == 0)
- throw new ArgumentNullException("ncname");
+ if (name == null || name.Length == 0)
+ throw new ArgumentNullException("name");
- if (!XmlChar.IsNCName (ncname))
- throw new XmlException ("'" + ncname + "' is not a valid XML NCName");
- return ncname;
+ if (!XmlChar.IsNCName (name))
+ throw new XmlException ("'" + name + "' is not a valid XML NCName");
+ return name;
}
-#if NET_2_0
- public static string VerifyTOKEN (string name)
-#else
- internal static string VerifyTOKEN (string name)
-#endif
+ public static string VerifyTOKEN (string token)
{
- if (name == null)
- throw new ArgumentNullException("name");
+ if (token == null)
+ throw new ArgumentNullException("token");
- if (name.Length == 0)
- return name;
+ if (token.Length == 0)
+ return token;
- if (XmlChar.IsWhitespace (name [0]) ||
- XmlChar.IsWhitespace (name [name.Length - 1]))
+ if (XmlChar.IsWhitespace (token [0]) ||
+ XmlChar.IsWhitespace (token [token.Length - 1]))
throw new XmlException ("Whitespace characters (#xA, #xD, #x9, #x20) are not allowed as leading or trailing whitespaces of xs:token.");
- for (int i = 0; i < name.Length; i++)
- if (XmlChar.IsWhitespace (name [i]) && name [i] != ' ')
- throw new XmlException ("Either #xA, #xD or #x9 are not allowed inside xs:token.");
+ for (int i = 0; i < token.Length; i++)
+ if (XmlChar.IsWhitespace (token [i]) && token [i] != ' ')
+ throw new XmlException ("Either #xA, #xD or #x9 are not allowed inside xs:token.");
- return name;
+ return token;
}
#if NET_2_0
public static DateTimeOffset ToDateTimeOffset (string s, string [] formats)
{
- return DateTimeOffset.ParseExact (s, formats, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal);
+ DateTimeStyles style = DateTimeStyles.AllowLeadingWhite |
+ DateTimeStyles.AllowTrailingWhite |
+ DateTimeStyles.AssumeUniversal;
+ return DateTimeOffset.ParseExact (s, formats, CultureInfo.InvariantCulture, style);
}
public static string ToString (DateTimeOffset value)
return new Uri (s, UriKind.RelativeOrAbsolute);
}
+#endif
+
+#if NET_4_0
+ public static bool IsNCNameChar (char ch)
+ {
+ return XmlChar.IsNCNameChar (ch);
+ }
+
+ public static bool IsPublicIdChar (char ch)
+ {
+ return XmlChar.IsPubidChar (ch);
+ }
+
+ public static bool IsStartNCNameChar (char ch)
+ {
+ return XmlChar.IsFirstNameChar (ch);
+ }
+
+ public static bool IsWhitespaceChar (char ch)
+ {
+ return XmlChar.IsWhitespace (ch);
+ }
+
+ public static bool IsXmlChar (char ch)
+ {
+ return XmlChar.IsValid (ch);
+ }
+
+ public static bool IsXmlSurrogatePair (char lowChar, char highChar)
+ {
+ return 0xD800 <= lowChar && lowChar <= 0xDBFF && 0xDC00 <= highChar && highChar <= 0xDFFF;
+ }
+
+ public static string VerifyPublicId (string publicId)
+ {
+ if (publicId == null)
+ throw new ArgumentNullException ("publicId");
+ if (XmlChar.IsPubid (publicId))
+ return publicId;
+ throw new XmlException (string.Format ("'{0}' is not a valid PUBLIC ID", publicId));
+ }
+
+ public static string VerifyWhitespace (string content)
+ {
+ if (content == null)
+ throw new ArgumentNullException ("content");
+ if (XmlChar.IsWhitespace (content))
+ return content;
+ throw new XmlException (string.Format ("'{0}' is not whitespace", content));
+ }
+
+ public static string VerifyXmlChars (string content)
+ {
+ if (content == null)
+ throw new ArgumentNullException ("content");
+ var idx = XmlChar.IndexOfInvalid (content, true);
+ if (idx < 0)
+ return content;
+ throw new XmlException (string.Format ("Invalid XML character was found in the content, at index {0}.", idx));
+ }
#endif
}
}