2009-01-16 72 views
19

我最近需要將數據表序列化爲JSON。我在哪裏,我們仍然在.Net 2.0,所以我不能在.Net 3.5中使用JSON序列化程序。我覺得這一定是以前做過的,所以我去網上查了一下found一個numberdifferentoptions。其中一些取決於一個額外的圖書館,我會很難通過這裏。其他需要先轉換爲List<Dictionary<>>,這似乎有點尷尬和不必要。另一個處理所有的值像一個字符串。由於某種原因,我無法真正支持其中的任何一個,所以我決定推出自己的,這是張貼在下面。DataTable to JSON

正如您從閱讀//TODO評論可以看到的,它在一些地方是不完整的。這段代碼已經在製作中,所以它在基本意義上「起作用」。不完整的地方是我們知道我們的生產數據當前不會觸及它的地方(數據庫中沒有時間片或字節數組)。我在這裏發佈的原因是,我覺得這可能會更好一點,我希望幫助完成和改進此代碼。任何輸入歡迎。

請注意,此功能內置於.Net 3.5及更高版本,因此今天使用此代碼的唯一原因是如果您仍僅限於.Net 2.0。即使如此,JSON.Net已經成爲這類事情的goto庫。

public static class JSONHelper 
{ 
    public static string FromDataTable(DataTable dt) 
    { 
     string rowDelimiter = ""; 

     StringBuilder result = new StringBuilder("["); 
     foreach (DataRow row in dt.Rows) 
     { 
      result.Append(rowDelimiter); 
      result.Append(FromDataRow(row)); 
      rowDelimiter = ","; 
     } 
     result.Append("]"); 

     return result.ToString(); 
    } 

    public static string FromDataRow(DataRow row) 
    { 
     DataColumnCollection cols = row.Table.Columns; 
     string colDelimiter = ""; 

     StringBuilder result = new StringBuilder("{");  
     for (int i = 0; i < cols.Count; i++) 
     { // use index rather than foreach, so we can use the index for both the row and cols collection 
      result.Append(colDelimiter).Append("\"") 
        .Append(cols[i].ColumnName).Append("\":") 
        .Append(JSONValueFromDataRowObject(row[i], cols[i].DataType)); 

      colDelimiter = ","; 
     } 
     result.Append("}"); 
     return result.ToString(); 
    } 

    // possible types: 
    // http://msdn.microsoft.com/en-us/library/system.data.datacolumn.datatype(VS.80).aspx 
    private static Type[] numeric = new Type[] {typeof(byte), typeof(decimal), typeof(double), 
            typeof(Int16), typeof(Int32), typeof(SByte), typeof(Single), 
            typeof(UInt16), typeof(UInt32), typeof(UInt64)}; 

    // I don't want to rebuild this value for every date cell in the table 
    private static long EpochTicks = new DateTime(1970, 1, 1).Ticks; 

    private static string JSONValueFromDataRowObject(object value, Type DataType) 
    { 
     // null 
     if (value == DBNull.Value) return "null"; 

     // numeric 
     if (Array.IndexOf(numeric, DataType) > -1) 
      return value.ToString(); // TODO: eventually want to use a stricter format. Specifically: separate integral types from floating types and use the "R" (round-trip) format specifier 

     // boolean 
     if (DataType == typeof(bool)) 
      return ((bool)value) ? "true" : "false"; 

     // date -- see http://weblogs.asp.net/bleroy/archive/2008/01/18/dates-and-json.aspx 
     if (DataType == typeof(DateTime))  
      return "\"\\/Date(" + new TimeSpan(((DateTime)value).ToUniversalTime().Ticks - EpochTicks).TotalMilliseconds.ToString() + ")\\/\""; 

     // TODO: add Timespan support 
     // TODO: add Byte[] support 

     //TODO: this would be _much_ faster with a state machine 
     //TODO: way to select between double or single quote literal encoding 
     //TODO: account for database strings that may have single \r or \n line breaks 
     // string/char 
     return "\"" + value.ToString().Replace(@"\", @"\\").Replace(Environment.NewLine, @"\n").Replace("\"", @"\""") + "\""; 
    } 
} 

更新:
這是現在老了,但我想指出一些關於這個代碼是如何處理日期。我使用的格式在當時是有意義的,因爲網址中的確切原因。然而,這個理由包括以下內容:

老實說,JSON模式通過使字符串作爲日期文字「子類型」來解決問題,但這仍然在進行中,它會在達成任何重要的採納之前需要時間。

那麼,時間已經過去了。今天,只需使用ISO 8601日期格式即可。我不打算改變代碼,因爲真的:這是古老的。只要去使用JSON.Net。

+0

如果今天有人問到這個問題,它會代替代碼審查堆棧交換。我已經將其標記爲在那裏移動,但它引起我注意的唯一原因是它只是獲得了「着名問題」黃金徽章。在遷移中會失去這種觀點。 – 2012-05-08 14:18:45

+0

我認爲這將太舊以至於無法遷移。如果你還可以,它可以住在這裏? – Kev 2012-05-08 22:48:21

+0

我不介意,只是想着最合適的方式。我有其他舊東西移動。 – 2012-05-09 03:01:01

回答