数据表格转换为JSON

21
我最近需要将数据表序列化为JSON。我们使用的是.Net 2.0,无法使用.Net 3.5中的JSON序列化程序。我想这肯定已经做过了,所以我在网上搜寻发现很多 不同的 选项。其中一些依赖于其他库,我很难在此处推广使用。其他方法需要先转换为List<Dictionary<>>,这似乎有点笨拙和不必要。另一个方法将所有值视为字符串处理。出于某种原因,我不能真正支持它们中的任何一个,所以我决定自己动手写一个,如下所示。

从阅读//TODO注释可以看出,代码还有几个地方不完整。这段代码已经在生产环境中使用了,因此基本上是可行的。它不完整的地方是我们知道我们的生产数据目前不会触及它(数据库中没有时间跨度或字节数组)。我在这里发布的原因是我觉得这可以再好一点,并且我想要帮助完成和改进这段代码。欢迎任何意见。

请注意,这种功能已经内置在 .Net 3.5 及更高版本中,因此今天只有在您仍受限于 .Net 2.0 的情况下才需要使用此代码。即使如此,JSON.Net 已成为这种操作的首选库。

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 https://weblogs.asp.net/bleroy/dates-and-json
        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("\"", @"\""") + "\"";
    }
}

更新:
这篇文章现在有点过时了,但我想指出有关代码如何处理日期的一些事情。我当时使用的格式是有道理的,原因在注释的url中说明。然而,该理由包括以下内容:

老实说,JSON Schema 通过将字符串“子类型化”为日期文字确实解决了问题,但这仍然是正在进行的工作,在任何显著的采用之前需要时间。

好吧,时间已经过去了。今天,只需使用ISO 8601日期格式即可。我不会费力更改代码,因为这真的很古老。直接使用 JSON.Net 就可以了。


如果今天有人问起这个问题,它应该属于代码审查堆栈交换而不是其他地方。我已经标记它要移动到那里,但唯一引起我的注意的原因是它刚刚获得了“著名问题”金徽章。在迁移中失去那个视图计数将是很糟糕的。 - Joel Coehoorn
我认为这个迁移太旧了。如果您同意,它可以继续留在这里吗? - Kev
我无所谓,只是考虑最合适的选择。我已经移动了其他旧的东西。 - Joel Coehoorn
为什么这个问题还在得到投票?.Net 2现在已经8年了,后续版本可以直接转换为json。现在没有必要再需要类似的东西了。另外,顺便说一下,我现在知道原始代码的问题所在:我应该请求一个字符串作为参数传递给我的函数(或构造函数),并将我的json字符串写入该流中,以便让asp.net程序员通过Response.Output流进行传递。这应该会_极大地_提高性能/可扩展性。 - Joel Coehoorn
这很有趣。被关闭为一个四年后提出的问题的重复。 - Joel Coehoorn
显示剩余2条评论
1个回答

6

有没有一种方法可以在不安装额外库的情况下完成它? - Steam

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接