Merge pull request #820 from brendanzagaeski/master
[mono.git] / mcs / class / System.XML / System.Xml / XmlConvert.cs
index 7a9cc5d19d6c88e11e07f117ac30ca3f18e1af12..bac049be278329041cd437465060087ed38a8e55 100644 (file)
@@ -44,18 +44,30 @@ namespace System.Xml {
                const NumberStyles floatStyle = NumberStyles.AllowCurrencySymbol |
                        NumberStyles.AllowExponent | 
                        NumberStyles.AllowDecimalPoint |
-                       NumberStyles.AllowLeadingSign;
+                       NumberStyles.AllowLeadingSign |
+                       NumberStyles.AllowLeadingWhite |
+                       NumberStyles.AllowTrailingWhite;
                
+               const NumberStyles integerStyle = NumberStyles.Integer |
+                       NumberStyles.AllowLeadingWhite |
+                       NumberStyles.AllowTrailingWhite;
+
                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.f",
-                 "yyyy-MM-ddTHH:mm:ss.ff",
-                 "yyyy-MM-ddTHH:mm:ss.fff",
-                 "yyyy-MM-ddTHH:mm:ss.ffff",
-                 "yyyy-MM-ddTHH:mm:ss.fffff",
-                 "yyyy-MM-ddTHH:mm:ss.ffffff",
-                 "yyyy-MM-ddTHH:mm:ss.fffffff",
+                 "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",
@@ -72,6 +84,14 @@ namespace System.Xml {
                  "yyyy-MM-ddTHH:mm:ss.fffffZ",
                  "yyyy-MM-ddTHH:mm:ss.ffffffZ",
                  "yyyy-MM-ddTHH:mm:ss.fffffffZ",
+                 "yyyy-MM-ddTHH:mm:ss",
+                 "yyyy-MM-ddTHH:mm:ss.f",
+                 "yyyy-MM-ddTHH:mm:ss.ff",
+                 "yyyy-MM-ddTHH:mm:ss.fff",
+                 "yyyy-MM-ddTHH:mm:ss.ffff",
+                 "yyyy-MM-ddTHH:mm:ss.fffff",
+                 "yyyy-MM-ddTHH:mm:ss.ffffff",
+                 "yyyy-MM-ddTHH:mm:ss.fffffff",
                  // time
                  "HH:mm:ss",
                  "HH:mm:ss.f",
@@ -97,6 +117,7 @@ namespace System.Xml {
                  "HH:mm:ss.fffffZ",
                  "HH:mm:ss.ffffffZ",
                  "HH:mm:ss.fffffffZ",
+#endif
                  // date
                  "yyyy-MM-dd",
                  "yyyy-MM-ddzzz",
@@ -119,49 +140,8 @@ namespace System.Xml {
                  "---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;
-#if TARGET_JVM
-               static readonly string [] unspecifiedDateTimeFormats;
-#endif
-
-               static XmlConvert ()
-               {
-                       int l = defaultDateTimeFormats.Length;
-                       roundtripDateTimeFormats = new string [l];
-                       localDateTimeFormats = new string [l];
-                       utcDateTimeFormats = new string [l];
-#if TARGET_JVM
-                       unspecifiedDateTimeFormats = new string [l * 4];
-#endif
-                       for (int i = 0; i < l; i++) {
-                               string s = defaultDateTimeFormats [i];
-                               localDateTimeFormats [i] = s + "zzz";
-                               roundtripDateTimeFormats [i] = s + 'K';
-                               utcDateTimeFormats [i] = s + 'Z';
-#if TARGET_JVM
-                               unspecifiedDateTimeFormats [i * 4] = s;
-                               unspecifiedDateTimeFormats [i * 4 + 1] = localDateTimeFormats [i];
-                               unspecifiedDateTimeFormats [i * 4 + 2] = roundtripDateTimeFormats [i];
-                               unspecifiedDateTimeFormats [i * 4 + 3] = utcDateTimeFormats [i];
-#endif
-                       }
-               }
-#endif
-
+               static DateTimeStyles _defaultStyle = DateTimeStyles.AllowLeadingWhite | DateTimeStyles.AllowTrailingWhite;
+               
                public XmlConvert()
                {}
 
@@ -318,12 +298,22 @@ namespace System.Xml {
 
                public static byte ToByte(string s)
                {
-                       return Byte.Parse(s, CultureInfo.InvariantCulture);
+                       return Byte.Parse(s, NumberStyles.Integer, CultureInfo.InvariantCulture);
                }
 
                public static char ToChar(string s)
                {
+#if !NET_2_1
                        return Char.Parse(s);
+#else
+                       if (s == null)
+                               throw new ArgumentNullException ("s");
+
+                       if (s.Length != 1)
+                               throw new FormatException ("String contain more than one char");
+
+                       return s [0];
+#endif
                }
 
 #if NET_2_0
@@ -335,25 +325,17 @@ namespace System.Xml {
                }
                
 #if NET_2_0
-               public static DateTime ToDateTime (string value, XmlDateTimeSerializationMode mode)
+               public static DateTime ToDateTime (string s, XmlDateTimeSerializationMode dateTimeOption)
                {
-                       string modestr = null;
-                       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);
+                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:
-#if TARGET_JVM
-                               return ToDateTime (value, unspecifiedDateTimeFormats);
-#endif
+                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
@@ -363,15 +345,22 @@ namespace System.Xml {
                        //d.FullDateTimePattern = format;
                        //return DateTime.Parse(s, d);
                        DateTimeStyles style = DateTimeStyles.AllowLeadingWhite |
-                                              DateTimeStyles.AllowTrailingWhite;
+                                              DateTimeStyles.AllowTrailingWhite;                       
                        return DateTime.ParseExact (s, format, DateTimeFormatInfo.InvariantInfo, style);
                }
 
                public static DateTime ToDateTime(string s, string[] formats)
                {
-                       DateTimeStyles style = DateTimeStyles.AllowLeadingWhite |
-                                              DateTimeStyles.AllowTrailingWhite;
-                       return DateTime.ParseExact (s, formats, DateTimeFormatInfo.InvariantInfo, style);
+                       return ToDateTime (s, formats, _defaultStyle);                  
+               }
+
+               private static DateTime ToDateTime (string s, string [] formats, DateTimeStyles style) 
+               {
+                       try {
+                               return DateTime.ParseExact (s, formats, DateTimeFormatInfo.InvariantInfo, style);
+                       } catch (ArgumentOutOfRangeException) {
+                               return DateTime.MinValue;
+                       }
                }
                
                public static Decimal ToDecimal(string s)
@@ -383,51 +372,83 @@ namespace System.Xml {
                {
                        if (s == null)
                                throw new ArgumentNullException();
-                       if (s == "INF")
-                               return Double.PositiveInfinity;
-                       if (s == "-INF")
-                               return Double.NegativeInfinity;
-                       if (s == "NaN")
-                               return Double.NaN;
+
+                       float f = TryParseStringFloatConstants (s);
+                       if (f != 0)
+                               return f;
+
                        return Double.Parse (s, floatStyle, CultureInfo.InvariantCulture);
                }
 
-               public static Guid ToGuid(string s)
+               static float TryParseStringFloatConstants (string s)
+               {
+                       int sidx = 0;
+                       while (sidx < s.Length && Char.IsWhiteSpace (s [sidx]))
+                               sidx++;
+                       if (sidx == s.Length)
+                               throw new FormatException ();
+                       int sEndPos = s.Length - 1;
+                       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;
+                       // 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;
+               }
+
+               static bool TryParseStringConstant (string format, string s, int start, int end)
+               {
+                       return end - start + 1 == format.Length && String.CompareOrdinal (format, 0, s, start, format.Length) == 0;
+               }
+
+               public static Guid ToGuid (string s)
                {
-                       return new Guid(s);
+                       try {
+                               return new Guid(s);
+                       } catch (FormatException ex) {
+                               throw new FormatException (String.Format ("Invalid Guid input '{0}'", ex.InnerException));
+                       }
                }
 
                public static short ToInt16(string s)
                {
-                       return Int16.Parse (s, NumberStyles.Integer, CultureInfo.InvariantCulture);
+                       return Int16.Parse (s, integerStyle, CultureInfo.InvariantCulture);
                }
 
                public static int ToInt32(string s)
                {
-                       return Int32.Parse (s, NumberStyles.Integer, CultureInfo.InvariantCulture);
+                       return Int32.Parse (s, integerStyle, CultureInfo.InvariantCulture);
                }
 
                public static long ToInt64(string s)
                {
-                       return Int64.Parse (s, NumberStyles.Integer, CultureInfo.InvariantCulture);
+                       return Int64.Parse (s, integerStyle, CultureInfo.InvariantCulture);
                }
 
                [CLSCompliant (false)]
                public static SByte ToSByte(string s)
                {
-                       return SByte.Parse(s, CultureInfo.InvariantCulture);
+                       return SByte.Parse(s, integerStyle, CultureInfo.InvariantCulture);
                }
 
                public static float ToSingle(string s)
                {
                        if (s == null)
                                throw new ArgumentNullException();
-                       if (s == "INF")
-                               return Single.PositiveInfinity;
-                       if (s == "-INF")
-                               return Single.NegativeInfinity;
-                       if (s == "NaN")
-                               return Single.NaN;
+
+                       float f = TryParseStringFloatConstants (s);
+                       if (f != 0)
+                               return f;
+
                        return Single.Parse(s, floatStyle, CultureInfo.InvariantCulture);
                }
 
@@ -491,25 +512,33 @@ namespace System.Xml {
 
                        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');
                                }
@@ -522,7 +551,7 @@ namespace System.Xml {
                        if (Double.IsNegativeInfinity(value)) return "-INF";
                        if (Double.IsPositiveInfinity(value)) return "INF";
                        if (Double.IsNaN(value)) return "NaN";
-                       return value.ToString(CultureInfo.InvariantCulture);
+                       return value.ToString("R", CultureInfo.InvariantCulture);
                }
 
                public static string ToString(float value)
@@ -530,7 +559,7 @@ namespace System.Xml {
                        if (Single.IsNegativeInfinity(value)) return "-INF";
                        if (Single.IsPositiveInfinity(value)) return "INF";
                        if (Single.IsNaN(value)) return "NaN";
-                       return value.ToString(CultureInfo.InvariantCulture);
+                       return value.ToString("R", CultureInfo.InvariantCulture);
                }
 
                [CLSCompliant (false)]
@@ -554,37 +583,31 @@ namespace System.Xml {
                }
 
 #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.
-                       string modestr = null;
-                       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",
                                        CultureInfo.InvariantCulture);
-                               break;
                        case XmlDateTimeSerializationMode.RoundtripKind:
                                return value.ToString (
                                        "yyyy-MM-ddTHH:mm:ss.FFFFFFFK",
                                        CultureInfo.InvariantCulture);
-                               break;
                        default:
                                return value.ToString (
                                        "yyyy-MM-ddTHH:mm:ss.FFFFFFFzzz",
                                        CultureInfo.InvariantCulture);
-                               break;
                        case XmlDateTimeSerializationMode.Utc:
                                return (value == DateTime.MinValue ? DateTime.MinValue : value == DateTime.MaxValue ? value : value.ToUniversalTime ()).ToString (
                                        "yyyy-MM-ddTHH:mm:ss.FFFFFFFZ",
                                        CultureInfo.InvariantCulture);
-                               break;
                        case XmlDateTimeSerializationMode.Unspecified:
                                return value.ToString (
                                        "yyyy-MM-ddTHH:mm:ss.FFFFFFF",
                                        CultureInfo.InvariantCulture);
-                               break;
                        }
                }
 #endif
@@ -596,8 +619,9 @@ namespace System.Xml {
 
                public static TimeSpan ToTimeSpan(string s)
                {
+                       s = s.Trim (XmlChar.WhitespaceChars);
                        if (s.Length == 0)
-                               throw new ArgumentException ("Invalid format string for duration schema datatype.");
+                               throw new FormatException ("Invalid format string for duration schema datatype.");
 
                        int start = 0;
                        if (s [0] == '-')
@@ -605,7 +629,7 @@ namespace System.Xml {
                        bool minusValue = (start == 1);
 
                        if (s [start] != 'P')
-                               throw new ArgumentException ("Invalid format string for duration schema datatype.");
+                               throw new FormatException ("Invalid format string for duration schema datatype.");
                        start++;
 
                        int parseStep = 0;
@@ -700,7 +724,7 @@ namespace System.Xml {
                                start = i;
                        }
                        if (error)
-                               throw new ArgumentException ("Invalid format string for duration schema datatype.");
+                               throw new FormatException ("Invalid format string for duration schema datatype.");
                        TimeSpan ts = new TimeSpan (days, hours, minutes, seconds);
                        if (minusValue)
                                return TimeSpan.FromTicks (- (ts.Ticks + ticks));
@@ -711,19 +735,19 @@ namespace System.Xml {
                [CLSCompliant (false)]
                public static UInt16 ToUInt16(string s)
                {
-                       return UInt16.Parse(s, CultureInfo.InvariantCulture);
+                       return UInt16.Parse(s, NumberStyles.Integer, CultureInfo.InvariantCulture);
                }
 
                [CLSCompliant (false)]
                public static UInt32 ToUInt32(string s)
                {
-                       return UInt32.Parse(s, CultureInfo.InvariantCulture);
+                       return UInt32.Parse(s, NumberStyles.Integer, CultureInfo.InvariantCulture);
                }
 
                [CLSCompliant (false)]
                public static UInt64 ToUInt64(string s)
                {
-                       return UInt64.Parse(s, CultureInfo.InvariantCulture);
+                       return UInt64.Parse(s, NumberStyles.Integer, CultureInfo.InvariantCulture);
                }
 
                public static string VerifyName (string name)
@@ -737,37 +761,33 @@ namespace System.Xml {
                        
                }
 
-               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
@@ -827,17 +847,20 @@ namespace System.Xml {
 
                public static DateTimeOffset ToDateTimeOffset (string s, string format)
                {
-                       return ToDateTimeOffset (s, format);
+                       return DateTimeOffset.ParseExact (s, format, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal);
                }
 
                public static DateTimeOffset ToDateTimeOffset (string s, string [] formats)
                {
-                       return ToDateTimeOffset (s, formats);
+                       DateTimeStyles style = DateTimeStyles.AllowLeadingWhite |
+                                              DateTimeStyles.AllowTrailingWhite |
+                                              DateTimeStyles.AssumeUniversal;
+                       return DateTimeOffset.ParseExact (s, formats, CultureInfo.InvariantCulture, style);
                }
 
                public static string ToString (DateTimeOffset value)
                {
-                       return ToString (value, "yyyy-MM-ddTHH:mm:ss.fffffffzzz");
+                       return ToString (value, "yyyy-MM-ddTHH:mm:ss.FFFFFFFzzz");
                }
 
                public static string ToString (DateTimeOffset value, string format)
@@ -845,6 +868,74 @@ namespace System.Xml {
                        return value.ToString (format, CultureInfo.InvariantCulture);
                }
 #endif
+
+               // it is used only from 2.1 System.Xml.Serialization.dll from
+               // MS Silverlight SDK. We don't use it so far.
+               internal static Uri ToUri (string s)
+               {
+                       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
        }
 }