Un constructor de Delphi / Lazarus / C ++ de clase simple y pequeña para el análisis rápido de JSON.
Algunos puntos de interés:
McJSON ), solo una clase ( TMcJsonItem ). uses
McJSON;
...
function Test99 (out Msg: string): Boolean;
var
Json: TMcJsonItem;
i: Integer;
begin
Msg := ' Test: Github readme.md content ' ;
Json := TMcJsonItem.Create();
try
try
// add some pairs.
Json.Add( ' key1 ' ).AsInteger := 1 ;
Json.Add( ' key2 ' ).AsBoolean := True;
Json.Add( ' key3 ' ).AsNumber := 1.234 ;
Json.Add( ' key4 ' ).AsString := ' value 1 ' ;
// add an array
Json.Add( ' array ' , jitArray);
for i := 1 to 3 do
Json[ ' array ' ].Add.AsInteger := i;
// save a backup to file
if (Json[ ' array ' ].Count = 3 ) then
Json.SaveToFile( ' test99.json ' );
// remove an item
Json.Delete( ' array ' );
// oops, load the backup
if (Json.Count = 4 ) then
Json.LoadFromFile( ' test99.json ' );
// test final result
Result := (Json.AsJSON = ' {"key1":1,"key2":true,"key3":1.234,"key4":"value 1","array":[1,2,3]} ' );
except
Result := False;
end ;
finally
Json.Free;
end ;
end ; Producirá testtest99.json :
{
"key1" : 1 ,
"key2" : true ,
"key3" : 1.234 ,
"key4" : " value 1 " ,
"array" : [
1 ,
2 ,
3
]
}# include " McJson.hpp "
...
bool Test99 (AnsiString& Msg)
{
bool Result;
TMcJsonItem* Json = NULL ;
Msg = " Test: Github readme.md content " ;
Json = new TMcJsonItem ();
try
{
try
{ // add some pairs.
Json-> Add ( " key1 " )-> AsInteger = 1 ;
Json-> Add ( " key2 " )-> AsBoolean = true ;
Json-> Add ( " key3 " )-> AsNumber = 1.234 ;
Json-> Add ( " key4 " )-> AsString = " value 1 " ;
// add an array
Json-> Add ( " array " , jitArray);
for ( int i = 1 ; i <= 3 ; i++)
Json-> Values [ " array " ]-> Add ()-> AsInteger = i;
// save a backup to file
if (Json-> Values [ " array " ]-> Count == 3 )
Json-> SaveToFile ( " test99.json " );
// remove an item
Json-> Delete ( " array " );
// oops, load the backup
if (Json-> Count == 4 )
Json-> LoadFromFile ( " test99.json " );
// test final result
Result = (Json-> AsJSON ==
" { " key1 " :1, " key2 " :true, " key3 " :1.234, " key4 " : " value 1 " , " array " :[1,2,3]} " );
}
catch (...)
{
Result = false ;
}
}
__finally
{
if (Json) delete (Json);
}
return (Result);
} Considere las pruebas unitarias de Leer en la carpeta test para una lista completa de casos de uso McJSON .
Solo usa la propiedad AsJSON
var
N: TMcJsonItem;
begin
N := TMcJsonItem.Create;
N.AsJSON := ' {"i": 123, "f": 123.456, "s": "abc", "b": true, "n": null} ' ;
// use N here
N.Free;
end ; Si desea verificar si una cadena JSON es válida:
Answer := N.Check( ' {"i":[123} ' ); // Answer will be false El método Check no aumentará ninguna excepción. El ejemplo anterior atrapará y ocultará el Error while parsing text: "expected , got }" at pos "10" . Si necesita atrapar y administrar excepciones, use CheckException como:
try
Answer := N.CheckException( ' {"k":1, "k":2} ' ); // Answer will be false
except
on E: Exception do
begin
// Error while parsing text: "duplicated key k" at pos "11"
end ;
end ; McJSON permite una forma simple de acceder a los elementos a través de rutas. Podemos usar '/', '' o '.' como separadores de ruta.
N.AsJSON := ' {"o": {"k1":"v1", "k2":"v2"}} ' ;
// access and change second object's value
N.Path( ' o.k2 ' ).AsString := ' value2 ' ;Resultados en:
{
"o" : {
"k1" : " v1 " ,
"k2" : " value2 "
}
} Tenga en cuenta que Path() aún no acepta índices, como este:
N.AsJSON := ' {"o": [{"k1":"v1"}, {"k2":"v2"}] ' ;
N.Path( ' o[1].k2 ' ).AsString := ' value2 ' ; Dado que la versión 1.0.4 McJSON permite usar ShorteNers de propiedades como en los objetos de datos JSON de Andreas Hausladen.
// access (automatic creation as in JDO)
Obj.S[ ' foo ' ] := ' bar ' ;
Obj.S[ ' bar ' ] := ' foo ' ;
// array creation, Obj is the owner of 'array'
Obj.A[ ' array ' ].Add.AsInteger := 10 ;
Obj.A[ ' array ' ].Add.AsInteger := 20 ;
// object creation, 'array' is the owner of ChildObj
ChildObj := Obj[ ' array ' ].Add(jitObject);
ChildObj.D[ ' value ' ] := 12.3 ;
// array creation, ChildObj is the owner of 'subarray'
ChildObj.A[ ' subarray ' ].Add.AsInteger := 100 ;
ChildObj.A[ ' subarray ' ].Add.AsInteger := 200 ;Resultados en:
{
"foo" : " bar " ,
"bar" : " foo " ,
"array" :[
10 ,
20 ,
{
"value" : 12.3 ,
"subarray" :[
100 ,
200
]
}
]
}Aquí le mostramos cómo acceder a todos los elementos (niños) de un objeto JSON y cambiar su tipo de valor y contenido.
N.AsJSON := ' {"o": {"k1":"v1", "k2":"v2"}} ' ;
// type and value: from string to integer
for i := 0 to N[ ' o ' ].Count- 1 do
N[ ' o ' ].Items[i].AsInteger := i+ 1 ; Resultados en:
{
"o" : {
"k1" : 1 ,
"k2" : 2
}
} Podemos usar las propiedades de Items[index] y Values['key'] para acceder a elementos dentro de objetos y matrices. Desde la versión 0.9.5 , podemos usar At(index, 'key') o At('key', index) como acortadores.
N.AsJSON := ' {"a": [{"k1":1,"k2":2},{"k1":10,"k2":20}]} ' ;
// how to access k2 of second object.
i := N[ ' a ' ].Items[ 1 ].Values[ ' k2 ' ].AsInteger; // i will be equal to 20
i := N[ ' a ' ].Items[ 1 ][ ' k2 ' ].AsInteger; // uses the Values[] as default property
i := N[ ' a ' ].At( 1 , ' k2 ' ).AsInteger; // shortener: index, key
i := N.At( ' a ' , 1 )[ ' k2 ' ].AsInteger; // shortener: key, index Y hay otros usos sin el parámetro key :
N.AsJSON := ' {"k1":1,"k2":2,"k3":3,"k4":4} ' ;
i := N.Items[ 2 ].AsInteger; // i will be equal to 3
i := N.At( 2 ).AsInteger; // shortener: just index
i := N.At( ' k3 ' ).AsInteger; // shortener: just keyUsando Delphi Enumerator, puede explorar los hijos y los valores de los objetos del elemento.
var
N, item: TMcJsonItem;
begin
N := TMcJsonItem.Create;
N.AsJSON := ' {"o": {"k1":"v1", "k2":"v2"}} ' ;
for item in N[ ' o ' ] do
// use item here, e.g. item.Key, item.Value, item.AsStringCambie todos los valores de un objeto con múltiples elementos. No tan común por ahí.
N.AsJSON := ' {"o": {"k1":"v1", "k2":"v2"}} ' ;
N[ ' o ' ].AsString := ' str ' ;Resultados en:
{
"o" : {
"k1" : " str " ,
"k2" : " str "
}
} Y si es necesario cambiar el tipo de o :
N[ ' o ' ].ItemType := jitValue;
N[ ' o ' ].AsString := ' str ' ;Resultados en:
{
"o" : " str "
}Convertir de matriz a tipo de objeto y viceversa. Además, no tan común por ahí.
N.AsJSON := ' { "k1": ["1", "2"], "k2": {"1": "a", "2": "b"} } ' ;
N[ ' k1 ' ].ItemType := jitObject; // convert array to object with items
N[ ' k2 ' ].ItemType := jitArray ; // convert object with items to array Resultados en:
{
"k1" : {
"0" : " 1 " ,
"1" : " 2 "
},
"k2" : [
" a " ,
" b "
]
}Inserte algunos elementos con teclas y posición.
P.Insert( ' c ' , 0 ).AsInteger := 3 ;
P.Insert( ' b ' , 0 ).AsInteger := 2 ;
P.Insert( ' a ' , 0 ).AsInteger := 1 ;Resultados en:
{
"a" : 1 ,
"b" : 2 ,
"c" : 3
}Además, es posible insertar objetos en matrices.
Q.AsJSON := ' {"x":0} ' ;
P.ItemType := jitArray;
P.Insert(Q, 1 );Resultados en:
[
1 ,
{
"x" : 0
},
2 ,
3
] IMPORTANTE : Desde la versión 0.9.3, Add() e Insert() clonará argumentos de tipo TMcJsonItem . Entonces, también tenemos que liberar la memoria para Q :
P.Free;
Q.Free; Dado que las cadenas de la versión 1.0.5 se pueden escapar con la función de ayuda McJsonEscapeString() :
N.AsJSON := ' {"path": ' + McJsonEscapeString( ' dirsubdir ' ) + ' } ' ; Resultados en:
{
"path" : " \ dir \ subdir "
} En la versión 1.0.6 se introdujo el enum TJEscapeType utilizado en McJsonEscapeString() con estos niveles de escape:
jetNormal : Escapa #8 #9 #10 #12 #13 " .jetStrict : Normal + / .jetUnicode : Strict + uXXXX .jetNone : compatibilidad con versiones anteriores. Estos niveles están inspirados en la función de ayuda de Lázaro StringToJSONString() de la biblioteca fpjson.
Veamos cómo inspeccionar toda la estructura, tipos y valores de datos internos de un objeto TMcJsonItem .
// ---------------------------------------------------------------------------
void
TFormMain::Inspect (TMcJsonItem* AMcJItem, AnsiString Ident)
{
if (!AMcJItem) return ;
// log current
MyLog ( Ident + ItemToStr (AMcJItem) );
// log child
if ( AMcJItem-> HasChild )
{
Ident = " " + Ident;
for ( int i= 0 ; i < AMcJItem-> Count ; i++)
{ // use Value not Child because are note using Key[].
Inspect ( AMcJItem-> Items [i], Ident );
}
}
}
// ---------------------------------------------------------------------------
String
TFormMain::ItemToStr (TMcJsonItem* AMcJItem) const
{
String Ans = " " ;
if (AMcJItem)
Ans = AMcJItem-> GetTypeStr () +
" ; " + AMcJItem-> GetValueStr () +
" ; Key= " + AMcJItem-> Key +
" ; Value= " + AMcJItem-> Value +
" ; JSON= " + AMcJItem-> AsJSON ;
return (Ans);
}
// --------------------------------------------------------------------------- Y usando un ejemplo como testInspect.json :
{
"foo" : " bar " ,
"array" : [
100 ,
20
],
"arrayObj" : [
{
"key1" : 1.0
},
{
"key2" : 2.0
}
],
"Msg" : [
" #1 UTF8 example: motivação " ,
" #2 Scapes: btnfr\ uFFFF "\ "
]
} Llamar Inspect() con un objeto Json cargado con testInspect.json :
TMcJsonItem* Json = new TMcJsonItem();
if (Json)
{
Json-> LoadFromFile ( " testInspect.json " );
Inspect (Json);
delete (Json);
}Resultados en:
object; string; Key=; Value=; JSON={"foo":"bar","array":[100,20],"arrayObj":[{"key1":1.0},{"key2":2.0}],"Msg":["#1 UTF8 example: motivação","#2 Scapes: btnfru"\"]}
value; string; Key=foo; Value=bar; JSON="foo":"bar"
array; string; Key=array; Value=; JSON="array":[100,20]
value; number; Key=; Value=100; JSON=100
value; number; Key=; Value=20; JSON=20
array; string; Key=arrayObj; Value=; JSON="arrayObj":[{"key1":1.0},{"key2":2.0}]
object; string; Key=; Value=; JSON={"key1":1.0}
value; number; Key=key1; Value=1.0; JSON="key1":1.0
object; string; Key=; Value=; JSON={"key2":2.0}
value; number; Key=key2; Value=2.0; JSON="key2":2.0
array; string; Key=Msg; Value=; JSON="Msg":["#1 UTF8 example: motivação","#2 Scapes: btnfruFFFF"\"]
value; string; Key=; Value=#1 UTF8 example: motivação; JSON="#1 UTF8 example: motivação"
value; string; Key=; Value=#2 Scapes: btnfruFFFF"\; JSON="#2 Scapes: btnfruFFFF"\"
Desde la versión 0.9.0 , las teclas vacías se analizarán y se verificarán con los errores:
N.AsJSON := ' {"": "value"} ' ; Y ToString() producirá un objeto JSON válido:
{
"" : " value "
}Internamente, usará la cadena constante C_empty_Key como contenido del campo FKey.
Desde la versión 0.9.2 , las cadenas con rupturas de línea no escapadas se analizarán con errores:
N.AsJSON := ' {"key": "value ' + # 13 + ' "} ' ;Aumentará la excepción:
Error while parsing text: "line break" at pos "14"
McJSON puede cargarse de archivos ASCII y UTF-8 (con o sin BOM). Ver el método LoadFromFile . El método SaveToFile escribirá utilizando la codificación UTF-8. Nota : Desde la PERTION 1.0.4, el código fuente del proyecto de prueba en Lázaro se convirtió a UTF-8, por lo que el parámetro asUTF8 se estableció en false .
El mundo no es perfecto y tampoco. Aquí hay algunos problemas conocidos:
TMcJsonItem se instancian en la estructura jerárquica utilizando listas fChild , hay un problema para crear campos que se propagan automáticamente entre los elementos. Una solución en estudio trata de crear una nueva clase matriz TMcJson que los objetos serán como las raíces y tener objetos TMcJsonItem como sus hijos. Se ha realizado una prueba de rendimiento con las unidades originales de myJSON , LkJson , JsonTools y uJSON . Aquí hay un resumen de las pruebas.
{... {"keyi":"valuei"}... }Y sobre el compilador y la máquina utilizados:
La siguiente tabla resume los resultados 1 :
| Biblioteca | Generar | Ahorrar | Analizar gramaticalmente | Carga | Acceso | Total |
|---|---|---|---|---|---|---|
McJSON 2 | .11 S | .07 S | .12 S | .09 S | .83 S | 1.25 s |
LkJson 2 | .30 s | .11 S | .47 S | .36 S | .01 S | 1.24 S |
JsonTools | 48.00 s | .70 S | 39.00 s | 40.00 s | .48 S | 1.2 min |
myJSON | 50.00 s | .07 S | 5.1 min | 7.7 min | 1.60 s | 13.1 min |
uJSON | 18.6 min | 20.1 min | 17.5 min | 4.31 S | 53.02 s | 57.6 min |
McJSONJson->Add("key")->AsString = "value" .JsonP->AsJSON = Json->AsJSON .LkJsonTlkBalTree .dynamic_cast haciendo el código verbosy.Json->Add("key", "value") .JsonP = dynamic_cast<TlkJSONObject*>(TlkJSON::ParseText(NULL, TlkJSON::GenerateText(NULL, Json))) .JsonToolsJson->Add("key", "value") .JsonP->Value = Json->AsJson .myJSONJson->Item["key"]->setStr("value") .JsonP->Code = Json->getJSON() .uJSONLkJson , pero la colección de las clases también forzará el lanzamiento con dynamic_cast .uJSON , parece haber un problema de rendimiento relacionado con toString() .Json->put("key", "value") .JsonP = new TJSONObject(Json->toString()) .SaveToFile no existe, por lo que ha usado TStringList->SaveToFile() después de llenar Text con Json->toString() . Métrica: tiempo promedio en segundos para 5 ejecuciones consecutivas. El total es el promedio de las pruebas parciales. Algunos resultados se convirtieron en minutos (min). ↩
Versión 1.0.5. Prueba mejorada JSON 0.9.0 Proyecto que se lanzará pronto. ↩ ↩ 2