18 votos

DataTable a JSON

Recientemente he necesarios para serializar un objeto datatable a JSON. Donde estoy todavía estamos en .Net 2.0, así que no puedo usar el JSON serializador .Net 3.5. Me di cuenta de esto debe haber sido hecho antes, así que me puse a buscar en línea y encontrar un número de diferentes opciones. Algunos de ellos dependen de las bibliotecas adicionales, que yo iba a tener un tiempo difícil de empujar a través de aquí. Otros requieren la primera conversión a List<Dictionary<>>, que parecía un poco incómodo e innecesario. Otro de los tratados todos los valores como una cadena. Por una razón u otra no pude conseguir realmente detrás de cualquiera de ellos, así que me decidí a rodar mi propia, que se publica a continuación.

Como se puede ver a partir de la lectura de la //TODO comentarios, es incompleta en algunos lugares. Este código ya está en producción, por lo que se hace "trabajar" en el sentido básico. Los lugares donde es incompleta son lugares donde sabemos que nuestros datos de la producción de no en la actualidad golpear (no timespans o matrices de bytes en la db). La razón por la que estoy posteando es que me siento como esto puede ser un poco mejor, y me gustaría ayudar a que el acabado y la mejora de este código. Cualquier entrada de la recepción.

Tenga en cuenta que esta capacidad se basa en .Net 3.5 y posteriores, y por ello la única razón para utilizar este código ahora es que si usted todavía está limitado .Net 2.0. Incluso entonces, JSON.Net se ha convertido en el ir a la biblioteca para este tipo de cosas.

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("\"", @"\""") + "\"";
    }
}

Actualización:
Esto es viejo, pero lo que quería señalar algo acerca de cómo este código controla las fechas. El formato que utiliza tuvo sentido en su momento, por el fundamento exacto en la url. Sin embargo, ese razonamiento incluye lo siguiente:

Para ser perfectamente honesto, JSON Esquema de resolver el problema por lo que es posible "subtipo" de una cadena como un literal de fecha, pero este es todavía un trabajo en progreso y que tomará tiempo antes de que cualquier significativo de la adopción es alcanzado.

Bien, el tiempo ha pasado. Hoy en día, está bien utilizar la ISO 8601 formato de fecha. Yo no voy a molestar a cambiar el código, la causa de la verdad: este es antiguo. Acaba de ir JSON.Net.

5voto

Powerlord Puntos 43989

Te ayudaría a convencer a sus jefes para instalar una biblioteca, si es de Microsoft extensiones de AJAX .NET 2.0?

Se incluyen en ellos es el Sistema.Web.Secuencia de comandos.La serialización.JavascriptSerializer, que se utiliza en el Paso 4 de la última enlace en tu post.

2voto

TheVillageIdiot Puntos 22158

Hey budy, está aquí en el Rick's blog Serializar el objeto DataTable el uso de Json.NET. En él se explica en detalle cómo se puede lograr mediante Json.NET de James Newton Rey.

1voto

tuinstoel Puntos 6329

He encontrado este: http://www.bramstein.com/projects/xsltjson/ Usted puede convertir su tabla de datos a xml y el uso de una hoja de estilos xslt para transformar el xml a json.

Es más una solución de una solución real.

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by: