2 // System.Xml.XmlConvert
5 // Dwivedi, Ajay kumar (Adwiv@Yahoo.com)
6 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
7 // Alan Tam Siu Lung (Tam@SiuLung.com)
8 // Atsushi Enomoto (ginga@kit.hi-ho.ne.jp)
10 // (C) 2002 Ximian, Inc (http://www.ximian.com)
14 // Permission is hereby granted, free of charge, to any person obtaining
15 // a copy of this software and associated documentation files (the
16 // "Software"), to deal in the Software without restriction, including
17 // without limitation the rights to use, copy, modify, merge, publish,
18 // distribute, sublicense, and/or sell copies of the Software, and to
19 // permit persons to whom the Software is furnished to do so, subject to
20 // the following conditions:
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35 using System.Globalization;
36 using System.Xml.Schema;
38 namespace System.Xml {
40 public class XmlConvert {
42 const string encodedColon = "_x003A_";
43 const NumberStyles floatStyle = NumberStyles.AllowCurrencySymbol |
44 NumberStyles.AllowExponent |
45 NumberStyles.AllowDecimalPoint |
46 NumberStyles.AllowLeadingSign;
48 static readonly string [] datetimeFormats = {
50 "yyyy-MM-ddTHH:mm:ss",
51 "yyyy-MM-ddTHH:mm:ss.f",
52 "yyyy-MM-ddTHH:mm:ss.ff",
53 "yyyy-MM-ddTHH:mm:ss.fff",
54 "yyyy-MM-ddTHH:mm:ss.ffff",
55 "yyyy-MM-ddTHH:mm:ss.fffff",
56 "yyyy-MM-ddTHH:mm:ss.ffffff",
57 "yyyy-MM-ddTHH:mm:ss.fffffff",
58 "yyyy-MM-ddTHH:mm:sszzz",
59 "yyyy-MM-ddTHH:mm:ss.fzzz",
60 "yyyy-MM-ddTHH:mm:ss.ffzzz",
61 "yyyy-MM-ddTHH:mm:ss.fffzzz",
62 "yyyy-MM-ddTHH:mm:ss.ffffzzz",
63 "yyyy-MM-ddTHH:mm:ss.fffffzzz",
64 "yyyy-MM-ddTHH:mm:ss.ffffffzzz",
65 "yyyy-MM-ddTHH:mm:ss.fffffffzzz",
66 "yyyy-MM-ddTHH:mm:ssZ",
67 "yyyy-MM-ddTHH:mm:ss.fZ",
68 "yyyy-MM-ddTHH:mm:ss.ffZ",
69 "yyyy-MM-ddTHH:mm:ss.fffZ",
70 "yyyy-MM-ddTHH:mm:ss.ffffZ",
71 "yyyy-MM-ddTHH:mm:ss.fffffZ",
72 "yyyy-MM-ddTHH:mm:ss.ffffffZ",
73 "yyyy-MM-ddTHH:mm:ss.fffffffZ",
90 "HH:mm:ss.fffffffzzz",
124 private static string TryDecoding (string s)
126 if (s == null || s.Length < 6)
131 c = (char) Int32.Parse (s.Substring (1, 4), NumberStyles.HexNumber, CultureInfo.InvariantCulture);
133 return s [0] + DecodeName (s.Substring (1));
137 return c.ToString ();
138 return c + DecodeName (s.Substring (6));
141 public static string DecodeName (string name)
143 if (name == null || name.Length == 0)
146 int pos = name.IndexOf ('_');
147 if (pos == -1 || pos + 6 >= name.Length)
150 if ((name [pos + 1] != 'X' && name [pos + 1] != 'x') || name [pos + 6] != '_')
151 return name [0] + DecodeName (name.Substring (1));
153 return name.Substring (0, pos) + TryDecoding (name.Substring (pos + 1));
156 public static string EncodeLocalName (string name)
158 string encoded = EncodeName (name);
159 int pos = encoded.IndexOf (':');
162 return encoded.Replace (":", encodedColon);
165 internal static bool IsInvalid (char c, bool firstOnlyLetter)
167 if (c == ':') // Special case. allowed in EncodeName, but encoded in EncodeLocalName
171 return !XmlChar.IsFirstNameChar (c);
173 return !XmlChar.IsNameChar (c);
176 private static string EncodeName (string name, bool nmtoken)
178 StringBuilder sb = new StringBuilder ();
179 int length = name.Length;
180 for (int i = 0; i < length; i++) {
182 if (IsInvalid (c, i == 0 && !nmtoken))
183 sb.AppendFormat ("_x{0:X4}_", (int) c);
184 else if (c == '_' && i + 6 < length && name [i+1] == 'x' && name [i + 6] == '_')
185 sb.Append ("_x005F_");
189 return sb.ToString ();
192 public static string EncodeName (string name)
194 return EncodeName (name, false);
197 public static string EncodeNmToken(string name)
199 return EncodeName (name, true);
202 // {true, false, 1, 0}
203 public static bool ToBoolean(string s)
205 s = s.Trim (XmlChar.WhitespaceChars);
217 throw new FormatException(s + " is not a valid boolean value");
221 public static byte ToByte(string s)
223 return Byte.Parse(s, CultureInfo.InvariantCulture);
226 public static char ToChar(string s)
228 return Char.Parse(s);
231 public static DateTime ToDateTime(string s)
233 return ToDateTime(s, datetimeFormats);
236 public static DateTime ToDateTime(string s, string format)
238 DateTimeFormatInfo d = new DateTimeFormatInfo();
239 d.FullDateTimePattern = format;
240 return DateTime.Parse(s, d);
243 public static DateTime ToDateTime(string s, string[] formats)
245 DateTimeStyles style = DateTimeStyles.AllowLeadingWhite |
246 DateTimeStyles.AllowTrailingWhite;
247 return DateTime.ParseExact (s, formats, DateTimeFormatInfo.InvariantInfo, style);
250 public static Decimal ToDecimal(string s)
252 return Decimal.Parse(s, CultureInfo.InvariantCulture);
255 public static double ToDouble(string s)
258 throw new ArgumentNullException();
260 return Double.PositiveInfinity;
262 return Double.NegativeInfinity;
265 return Double.Parse (s, floatStyle, CultureInfo.InvariantCulture);
268 public static Guid ToGuid(string s)
273 public static short ToInt16(string s)
275 return Int16.Parse(s, CultureInfo.InvariantCulture);
278 public static int ToInt32(string s)
280 return Int32.Parse(s, CultureInfo.InvariantCulture);
283 public static long ToInt64(string s)
285 return Int64.Parse(s, CultureInfo.InvariantCulture);
288 [CLSCompliant (false)]
289 public static SByte ToSByte(string s)
291 return SByte.Parse(s, CultureInfo.InvariantCulture);
294 public static float ToSingle(string s)
297 throw new ArgumentNullException();
299 return Single.PositiveInfinity;
301 return Single.NegativeInfinity;
304 return Single.Parse(s, floatStyle, CultureInfo.InvariantCulture);
307 public static string ToString(Guid value)
309 return value.ToString("D", CultureInfo.InvariantCulture);
312 public static string ToString(int value)
314 return value.ToString(CultureInfo.InvariantCulture);
317 public static string ToString(short value)
319 return value.ToString(CultureInfo.InvariantCulture);
322 public static string ToString(byte value)
324 return value.ToString(CultureInfo.InvariantCulture);
327 public static string ToString(long value)
329 return value.ToString(CultureInfo.InvariantCulture);
332 public static string ToString(char value)
334 return value.ToString(CultureInfo.InvariantCulture);
337 public static string ToString(bool value)
339 if (value) return "true";
343 [CLSCompliant (false)]
344 public static string ToString(SByte value)
346 return value.ToString(CultureInfo.InvariantCulture);
349 public static string ToString(Decimal value)
351 return value.ToString (CultureInfo.InvariantCulture);
354 [CLSCompliant (false)]
355 public static string ToString(UInt64 value)
357 return value.ToString(CultureInfo.InvariantCulture);
360 public static string ToString (TimeSpan value)
362 StringBuilder builder = new StringBuilder ();
363 if (value.Ticks < 0) {
364 builder.Append ('-');
365 value = value.Negate ();
367 builder.Append ('P');
369 builder.Append (value.Days).Append ('D');
370 if (value.Days > 0 || value.Hours > 0 || value.Minutes > 0 || value.Seconds > 0 || value.Milliseconds > 0) {
373 builder.Append (value.Hours).Append ('H');
374 if (value.Minutes > 0)
375 builder.Append (value.Minutes).Append ('M');
376 if (value.Seconds > 0 || value.Milliseconds > 0) {
377 builder.Append (value.Seconds);
378 if (value.Milliseconds > 0)
379 builder.Append ('.').AppendFormat ("{0:000}", value.Milliseconds);
380 builder.Append ('S');
383 return builder.ToString ();
386 public static string ToString(double value)
388 if (Double.IsNegativeInfinity(value)) return "-INF";
389 if (Double.IsPositiveInfinity(value)) return "INF";
390 if (Double.IsNaN(value)) return "NaN";
391 return value.ToString(CultureInfo.InvariantCulture);
394 public static string ToString(float value)
396 if (Single.IsNegativeInfinity(value)) return "-INF";
397 if (Single.IsPositiveInfinity(value)) return "INF";
398 if (Single.IsNaN(value)) return "NaN";
399 return value.ToString(CultureInfo.InvariantCulture);
402 [CLSCompliant (false)]
403 public static string ToString(UInt32 value)
405 return value.ToString(CultureInfo.InvariantCulture);
408 [CLSCompliant (false)]
409 public static string ToString(UInt16 value)
411 return value.ToString(CultureInfo.InvariantCulture);
414 public static string ToString(DateTime value)
416 return value.ToString("yyyy-MM-ddTHH:mm:ss.fffffffzzz", CultureInfo.InvariantCulture);
419 public static string ToString(DateTime value, string format)
421 return value.ToString(format, CultureInfo.InvariantCulture);
424 public static TimeSpan ToTimeSpan(string s)
427 throw new ArgumentException ("Invalid format string for duration schema datatype.");
432 bool minusValue = (start == 1);
434 if (s [start] != 'P')
435 throw new ArgumentException ("Invalid format string for duration schema datatype.");
448 while (i < s.Length) {
456 for (; i < s.Length; i++) {
457 if (!Char.IsDigit (s [i]))
460 int value = int.Parse (s.Substring (start, i - start), CultureInfo.InvariantCulture);
471 days += 365 * (value / 12) + 30 * (value % 12);
473 } else if (isTime && parseStep < 6) {
489 if (!isTime || parseStep > 4)
496 if (!isTime || parseStep > 6)
511 throw new ArgumentException ("Invalid format string for duration schema datatype.");
512 TimeSpan ts = new TimeSpan (days, hours, minutes, seconds);
513 return minusValue ? -ts : ts;
516 [CLSCompliant (false)]
517 public static UInt16 ToUInt16(string s)
519 return UInt16.Parse(s, CultureInfo.InvariantCulture);
522 [CLSCompliant (false)]
523 public static UInt32 ToUInt32(string s)
525 return UInt32.Parse(s, CultureInfo.InvariantCulture);
528 [CLSCompliant (false)]
529 public static UInt64 ToUInt64(string s)
531 return UInt64.Parse(s, CultureInfo.InvariantCulture);
534 public static string VerifyName (string name)
537 throw new ArgumentNullException("name");
539 if(!XmlChar.IsName (name))
540 throw new XmlException("'" + name + "' is not a valid XML Name");
545 public static string VerifyNCName(string ncname)
548 throw new ArgumentNullException("ncname");
550 if(!XmlChar.IsNCName (ncname))
551 throw new XmlException ("'" + ncname + "' is not a valid XML NCName");
555 // It is documented as public method, but in fact it is not.
556 internal static byte [] FromBinHexString (string s)
558 char [] chars = s.ToCharArray ();
559 byte [] bytes = new byte [chars.Length / 2 + chars.Length % 2];
560 FromBinHexString (chars, 0, chars.Length, bytes);
564 internal static int FromBinHexString (char [] chars, int offset, int charLength, byte [] buffer)
566 int bufIndex = offset;
567 for (int i = 0; i < charLength - 1; i += 2) {
568 buffer [bufIndex] = (chars [i] > '9' ?
569 (byte) (chars [i] - 'A' + 10) :
570 (byte) (chars [i] - '0'));
571 buffer [bufIndex] <<= 4;
572 buffer [bufIndex] += chars [i + 1] > '9' ?
573 (byte) (chars [i + 1] - 'A' + 10) :
574 (byte) (chars [i + 1] - '0');
577 if (charLength %2 != 0)
578 buffer [bufIndex++] = (byte)
579 ((chars [charLength - 1] > '9' ?
580 (byte) (chars [charLength - 1] - 'A' + 10) :
581 (byte) (chars [charLength - 1] - '0'))
584 return bufIndex - offset;