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.
36 using System
.Globalization
;
37 using System
.Xml
.Schema
;
39 namespace System
.Xml
{
41 public class XmlConvert
{
43 const string encodedColon
= "_x003A_";
44 const NumberStyles floatStyle
= NumberStyles
.AllowCurrencySymbol
|
45 NumberStyles
.AllowExponent
|
46 NumberStyles
.AllowDecimalPoint
|
47 NumberStyles
.AllowLeadingSign
;
49 static readonly string [] datetimeFormats
= {
51 "yyyy-MM-ddTHH:mm:ss",
52 "yyyy-MM-ddTHH:mm:ss.f",
53 "yyyy-MM-ddTHH:mm:ss.ff",
54 "yyyy-MM-ddTHH:mm:ss.fff",
55 "yyyy-MM-ddTHH:mm:ss.ffff",
56 "yyyy-MM-ddTHH:mm:ss.fffff",
57 "yyyy-MM-ddTHH:mm:ss.ffffff",
58 "yyyy-MM-ddTHH:mm:ss.fffffff",
59 "yyyy-MM-ddTHH:mm:sszzz",
60 "yyyy-MM-ddTHH:mm:ss.fzzz",
61 "yyyy-MM-ddTHH:mm:ss.ffzzz",
62 "yyyy-MM-ddTHH:mm:ss.fffzzz",
63 "yyyy-MM-ddTHH:mm:ss.ffffzzz",
64 "yyyy-MM-ddTHH:mm:ss.fffffzzz",
65 "yyyy-MM-ddTHH:mm:ss.ffffffzzz",
66 "yyyy-MM-ddTHH:mm:ss.fffffffzzz",
67 "yyyy-MM-ddTHH:mm:ssZ",
68 "yyyy-MM-ddTHH:mm:ss.fZ",
69 "yyyy-MM-ddTHH:mm:ss.ffZ",
70 "yyyy-MM-ddTHH:mm:ss.fffZ",
71 "yyyy-MM-ddTHH:mm:ss.ffffZ",
72 "yyyy-MM-ddTHH:mm:ss.fffffZ",
73 "yyyy-MM-ddTHH:mm:ss.ffffffZ",
74 "yyyy-MM-ddTHH:mm:ss.fffffffZ",
91 "HH:mm:ss.fffffffzzz",
125 private static string TryDecoding (string s
)
127 if (s
== null || s
.Length
< 6)
132 c
= (char) Int32
.Parse (s
.Substring (1, 4), NumberStyles
.HexNumber
, CultureInfo
.InvariantCulture
);
134 return s
[0] + DecodeName (s
.Substring (1));
138 return c
.ToString ();
139 return c
+ DecodeName (s
.Substring (6));
142 public static string DecodeName (string name
)
144 if (name
== null || name
.Length
== 0)
147 int pos
= name
.IndexOf ('_');
148 if (pos
== -1 || pos
+ 6 >= name
.Length
)
151 if ((name
[pos
+ 1] != 'X' && name
[pos
+ 1] != 'x') || name
[pos
+ 6] != '_')
152 return name
[0] + DecodeName (name
.Substring (1));
154 return name
.Substring (0, pos
) + TryDecoding (name
.Substring (pos
+ 1));
157 public static string EncodeLocalName (string name
)
159 string encoded
= EncodeName (name
);
160 int pos
= encoded
.IndexOf (':');
163 return encoded
.Replace (":", encodedColon
);
166 internal static bool IsInvalid (char c
, bool firstOnlyLetter
)
168 if (c
== ':') // Special case. allowed in EncodeName, but encoded in EncodeLocalName
172 return !XmlChar
.IsFirstNameChar (c
);
174 return !XmlChar
.IsNameChar (c
);
177 private static string EncodeName (string name
, bool nmtoken
)
179 StringBuilder sb
= new StringBuilder ();
180 int length
= name
.Length
;
181 for (int i
= 0; i
< length
; i
++) {
183 if (IsInvalid (c
, i
== 0 && !nmtoken
))
184 sb
.AppendFormat ("_x{0:X4}_", (int) c
);
185 else if (c
== '_' && i
+ 6 < length
&& name
[i
+1] == 'x' && name
[i
+ 6] == '_')
186 sb
.Append ("_x005F_");
190 return sb
.ToString ();
193 public static string EncodeName (string name
)
195 return EncodeName (name
, false);
198 public static string EncodeNmToken(string name
)
200 return EncodeName (name
, true);
203 // {true, false, 1, 0}
204 public static bool ToBoolean(string s
)
206 s
= s
.Trim (XmlChar
.WhitespaceChars
);
218 throw new FormatException(s
+ " is not a valid boolean value");
222 // LAMESPEC: It has been documented as public, but is marked as internal.
223 internal static string ToBinHexString (byte [] buffer
)
225 StringWriter w
= new StringWriter ();
226 WriteBinHex (buffer
, 0, buffer
.Length
, w
);
227 return w
.ToString ();
230 internal static void WriteBinHex (byte [] buffer
, int index
, int count
, TextWriter w
)
233 throw new ArgumentNullException ("buffer");
235 throw new ArgumentOutOfRangeException ("index", index
, "index must be non negative integer.");
237 throw new ArgumentOutOfRangeException ("count", count
, "count must be non negative integer.");
238 if (buffer
.Length
< index
+ count
)
239 throw new ArgumentOutOfRangeException ("index and count must be smaller than the length of the buffer.");
241 // Copied from XmlTextWriter.WriteBinHex ()
242 int end
= index
+ count
;
243 for (int i
= index
; i
< end
; i
++) {
244 int val
= buffer
[i
];
248 w
.Write ((char) (high
+ 55));
250 w
.Write ((char) (high
+ 0x30));
252 w
.Write ((char) (low
+ 55));
254 w
.Write ((char) (low
+ 0x30));
258 public static byte ToByte(string s
)
260 return Byte
.Parse(s
, CultureInfo
.InvariantCulture
);
263 public static char ToChar(string s
)
265 return Char
.Parse(s
);
268 public static DateTime
ToDateTime(string s
)
270 return ToDateTime(s
, datetimeFormats
);
273 public static DateTime
ToDateTime(string s
, string format
)
275 DateTimeFormatInfo d
= new DateTimeFormatInfo();
276 d
.FullDateTimePattern
= format
;
277 return DateTime
.Parse(s
, d
);
280 public static DateTime
ToDateTime(string s
, string[] formats
)
282 DateTimeStyles style
= DateTimeStyles
.AllowLeadingWhite
|
283 DateTimeStyles
.AllowTrailingWhite
;
284 return DateTime
.ParseExact (s
, formats
, DateTimeFormatInfo
.InvariantInfo
, style
);
287 public static Decimal
ToDecimal(string s
)
289 return Decimal
.Parse(s
, CultureInfo
.InvariantCulture
);
292 public static double ToDouble(string s
)
295 throw new ArgumentNullException();
297 return Double
.PositiveInfinity
;
299 return Double
.NegativeInfinity
;
302 return Double
.Parse (s
, floatStyle
, CultureInfo
.InvariantCulture
);
305 public static Guid
ToGuid(string s
)
310 public static short ToInt16(string s
)
312 return Int16
.Parse(s
, CultureInfo
.InvariantCulture
);
315 public static int ToInt32(string s
)
317 return Int32
.Parse(s
, CultureInfo
.InvariantCulture
);
320 public static long ToInt64(string s
)
322 return Int64
.Parse(s
, CultureInfo
.InvariantCulture
);
325 [CLSCompliant (false)]
326 public static SByte
ToSByte(string s
)
328 return SByte
.Parse(s
, CultureInfo
.InvariantCulture
);
331 public static float ToSingle(string s
)
334 throw new ArgumentNullException();
336 return Single
.PositiveInfinity
;
338 return Single
.NegativeInfinity
;
341 return Single
.Parse(s
, floatStyle
, CultureInfo
.InvariantCulture
);
344 public static string ToString(Guid
value)
346 return value.ToString("D", CultureInfo
.InvariantCulture
);
349 public static string ToString(int value)
351 return value.ToString(CultureInfo
.InvariantCulture
);
354 public static string ToString(short value)
356 return value.ToString(CultureInfo
.InvariantCulture
);
359 public static string ToString(byte value)
361 return value.ToString(CultureInfo
.InvariantCulture
);
364 public static string ToString(long value)
366 return value.ToString(CultureInfo
.InvariantCulture
);
369 public static string ToString(char value)
371 return value.ToString(CultureInfo
.InvariantCulture
);
374 public static string ToString(bool value)
376 if (value) return "true";
380 [CLSCompliant (false)]
381 public static string ToString(SByte
value)
383 return value.ToString(CultureInfo
.InvariantCulture
);
386 public static string ToString(Decimal
value)
388 return value.ToString (CultureInfo
.InvariantCulture
);
391 [CLSCompliant (false)]
392 public static string ToString(UInt64
value)
394 return value.ToString(CultureInfo
.InvariantCulture
);
397 public static string ToString (TimeSpan
value)
399 StringBuilder builder
= new StringBuilder ();
400 if (value.Ticks
< 0) {
401 builder
.Append ('-');
402 value = value.Negate ();
404 builder
.Append ('P');
406 builder
.Append (value.Days
).Append ('D');
407 if (value.Days
> 0 || value.Hours
> 0 || value.Minutes
> 0 || value.Seconds
> 0 || value.Milliseconds
> 0) {
410 builder
.Append (value.Hours
).Append ('H');
411 if (value.Minutes
> 0)
412 builder
.Append (value.Minutes
).Append ('M');
413 if (value.Seconds
> 0 || value.Milliseconds
> 0) {
414 builder
.Append (value.Seconds
);
415 if (value.Milliseconds
> 0)
416 builder
.Append ('.').AppendFormat ("{0:000}", value.Milliseconds
);
417 builder
.Append ('S');
420 return builder
.ToString ();
423 public static string ToString(double value)
425 if (Double
.IsNegativeInfinity(value)) return "-INF";
426 if (Double
.IsPositiveInfinity(value)) return "INF";
427 if (Double
.IsNaN(value)) return "NaN";
428 return value.ToString(CultureInfo
.InvariantCulture
);
431 public static string ToString(float value)
433 if (Single
.IsNegativeInfinity(value)) return "-INF";
434 if (Single
.IsPositiveInfinity(value)) return "INF";
435 if (Single
.IsNaN(value)) return "NaN";
436 return value.ToString(CultureInfo
.InvariantCulture
);
439 [CLSCompliant (false)]
440 public static string ToString(UInt32
value)
442 return value.ToString(CultureInfo
.InvariantCulture
);
445 [CLSCompliant (false)]
446 public static string ToString(UInt16
value)
448 return value.ToString(CultureInfo
.InvariantCulture
);
451 public static string ToString(DateTime
value)
453 return value.ToString("yyyy-MM-ddTHH:mm:ss.fffffffzzz", CultureInfo
.InvariantCulture
);
456 public static string ToString(DateTime
value, string format
)
458 return value.ToString(format
, CultureInfo
.InvariantCulture
);
461 public static TimeSpan
ToTimeSpan(string s
)
464 throw new ArgumentException ("Invalid format string for duration schema datatype.");
469 bool minusValue
= (start
== 1);
471 if (s
[start
] != 'P')
472 throw new ArgumentException ("Invalid format string for duration schema datatype.");
485 while (i
< s
.Length
) {
493 for (; i
< s
.Length
; i
++) {
494 if (!Char
.IsDigit (s
[i
]))
497 int value = int.Parse (s
.Substring (start
, i
- start
), CultureInfo
.InvariantCulture
);
508 days
+= 365 * (value / 12) + 30 * (value % 12);
510 } else if (isTime
&& parseStep
< 6) {
526 if (!isTime
|| parseStep
> 4)
533 if (!isTime
|| parseStep
> 6)
548 throw new ArgumentException ("Invalid format string for duration schema datatype.");
549 TimeSpan ts
= new TimeSpan (days
, hours
, minutes
, seconds
);
550 return minusValue
? -ts
: ts
;
553 [CLSCompliant (false)]
554 public static UInt16
ToUInt16(string s
)
556 return UInt16
.Parse(s
, CultureInfo
.InvariantCulture
);
559 [CLSCompliant (false)]
560 public static UInt32
ToUInt32(string s
)
562 return UInt32
.Parse(s
, CultureInfo
.InvariantCulture
);
565 [CLSCompliant (false)]
566 public static UInt64
ToUInt64(string s
)
568 return UInt64
.Parse(s
, CultureInfo
.InvariantCulture
);
571 public static string VerifyName (string name
)
574 throw new ArgumentNullException("name");
576 if (!XmlChar
.IsName (name
))
577 throw new XmlException("'" + name
+ "' is not a valid XML Name");
582 public static string VerifyNCName (string ncname
)
585 throw new ArgumentNullException("ncname");
587 if (!XmlChar
.IsNCName (ncname
))
588 throw new XmlException ("'" + ncname
+ "' is not a valid XML NCName");
593 public static string VerifyNMTOKEN (string name
)
595 internal static string VerifyNMTOKEN (string name
)
599 throw new ArgumentNullException("name");
601 if (!XmlChar
.IsNmToken (name
))
602 throw new XmlException("'" + name
+ "' is not a valid XML NMTOKEN");
607 // It is documented as public method, but in fact it is not.
608 internal static byte [] FromBinHexString (string s
)
610 char [] chars
= s
.ToCharArray ();
611 byte [] bytes
= new byte [chars
.Length
/ 2 + chars
.Length
% 2];
612 FromBinHexString (chars
, 0, chars
.Length
, bytes
);
616 internal static int FromBinHexString (char [] chars
, int offset
, int charLength
, byte [] buffer
)
618 int bufIndex
= offset
;
619 for (int i
= 0; i
< charLength
- 1; i
+= 2) {
620 buffer
[bufIndex
] = (chars
[i
] > '9' ?
621 (byte) (chars
[i
] - 'A' + 10) :
622 (byte) (chars
[i
] - '0'));
623 buffer
[bufIndex
] <<= 4;
624 buffer
[bufIndex
] += chars
[i
+ 1] > '9' ?
625 (byte) (chars
[i
+ 1] - 'A' + 10) :
626 (byte) (chars
[i
+ 1] - '0');
629 if (charLength
%2 != 0)
630 buffer
[bufIndex
++] = (byte)
631 ((chars
[charLength
- 1] > '9' ?
632 (byte) (chars
[charLength
- 1] - 'A' + 10) :
633 (byte) (chars
[charLength
- 1] - '0'))
636 return bufIndex
- offset
;