externo - json javascript ejemplo
Analizar tablas con caracteres Unicode en variables de JSON con SAS BASE (1)
Me enfrenté a un problema al analizar JSON con unicode char in vars. Entonces, tengo el próximo JSON (ejemplo):
{
"SASJSONExport":"1.0",
"SASTableData+TEST":[
{
"/u041f/u0435/u0440/u0435/u043c/u0435/u043d/u043d/u0430/u044f":2,
"/u0421/u0440/u0435/u0434/u043d/u0435/u0435":4,
"/u0421/u0442/u0440/u043e/u043a/u0430":"/u0427/u0442/u043e/u002d/u0442/u043e/u0031"
},
{
"/u041f/u0435/u0440/u0435/u043c/u0435/u043d/u043d/u0430/u044f":2,
"/u0421/u0440/u0435/u0434/u043d/u0435/u0435":2,
"/u0421/u0442/u0440/u043e/u043a/u0430":"/u0427/u0442/u043e/u002d/u0442/u043e/u0032"
},
{
"/u041f/u0435/u0440/u0435/u043c/u0435/u043d/u043d/u0430/u044f":1,
"/u0421/u0440/u0435/u0434/u043d/u0435/u0435":42,
"/u0421/u0442/u0440/u043e/u043a/u0430":"/u0427/u0442/u043e/u002d/u0442/u043e/u0033"
}
]
}
Para analizar la tabla desde JSON utilizo el motor SAS:
libname jsonfl JSON fileref=injson ;
El código decodifica más caracteres en las celdas, pero el nombre de los vars parece vals perdidos:
+--------------+---------------------------+------------+---------+---------+
| ordinal_root | ordinal_SASTableData_TEST | __________ | _______ | ______ |
+--------------+---------------------------+------------+---------+---------+
| 1 | 1 | 2 | 4 | Что-то1 |
| 1 | 2 | 2 | 2 | Что-то2 |
| 1 | 3 | 1 | 42 | Что-то3 |
+--------------+---------------------------+------------+---------+---------+
El encabezado debe verse así:
+--------------+---------------------------+------------+---------+---------+
| ordinal_root | ordinal_SASTableData_TEST | Переменная | Среднее | Строка |
+--------------+---------------------------+------------+---------+---------+
Así que decidí reemplazar los caracteres de variables sin codificación con nombres como este DIM_N_
. Y para eso debo encontrar todas las cadenas, que concuerden con la próxima expresión regular: /([/s/w/d//]+)/"/:/
Pero, para obtener cadenas de json, necesito establecer como delim el siguiente char ''{'',''}'',''['','']'','',''
. Pero si configuro esos caracteres como dlm, no ensamblaré json nuevamente. Así que decidí pegar antes del char ~
para configurarlo como dlm.
data delim;
infile injson lrecl=1073741823 nopad;
file delim;
input char1 $char1. @@;
if char1 in (''{'',''}'',''['','']'','','') then
put ''7E''x;
put char1 $CHAR1. @@;
run;
Recibí el archivo novalid json:
~
{"SASJSONExport":"1.0"~
,"SASTableData+TEST":~
[ ~
{"/u0056/u0061/u0072":2~
,"/u006d/u0065/u0061/u006e":4~
,"/u004e/u0061/u006d/u0065":"/u0073/u006d/u0074/u0068/u0031"~
}~
, ~
{"/u0056/u0061/u0072":2~
,"/u006d/u0065/u0061/u006e":2~
,"/u004e/u0061/u006d/u0065":"/u0073/u006d/u0074/u0068/u0032"~
}~
, ~
{"/u0056/u0061/u0072":1~
,"/u006d/u0065/u0061/u006e":42~
,"/u004e/u0061/u006d/u0065":"/u0073/u006d/u0074/u0068/u0033"~
} ~
]~
}
Entonces, como paso siguiente, estoy analizando JSON y uso ~
como delimitador:
data transfer;
length column $2000;
retain r;
infile delim delimiter=''7E''x nopad;
input char1 : $4000. @@;
r = prxparse(''/([/s/w/d//]+)/"/:/'');
pos = prxmatch(r,char1);
column = prxposn(r,1,char1);
n= _n_;
run;
Funciona ... Pero siento que esas son prácticas muy malas , y tiene límites.
UPD1
Opción,
options vAlidfmtname=long VALIDMEMNAME=extend VALIDVARNAME=any;
regreso:
+--------------+---------------------------+----------------------------+---------+--------------+
| ordinal_root | ordinal_SASTableData_TEST | __________ | _______ | ______ |
+--------------+---------------------------+----------------------------+---------+--------------+
| 1 | 1 | авфа2 фвафв = фвыа - тфвыа | 4 | Что-то1 ,,,, |
| 1 | 2 | авфа2 фвафв = фвыа - тфвыа | 2 | Что-то2 |
| 1 | 3 | авфа2 фвафв = фвыа - тфвыа | 2017 | Что-то3 |
+--------------+---------------------------+----------------------------+---------+--------------+
Entonces mis preguntas son:
- ¿Puedo decodificar todo el archivo sin la declaración de
infile
? - ¿Puedo usar el
infile delimiter
, pero establecer opciones smth para no eliminar el delimitador?
La crítica adecuada es bienvenida.
UPD
Llegué a la solución sin tener que editar manualmente el archivo de mapas json, pero usando una expresión regular.
libname _all_ clear;
filename _all_ clear;
filename _PDFOUT temp;
filename _GSFNAME temp;
proc datasets lib=work kill memtype=data nolist; quit;
filename jsf ''~/sasuser.v94/.json'' encoding=''utf-8'';
data _null_;
file jsf;
length js varchar(*);
retain js;
input;
js=unicode(_infile_);
put js;
datalines;
{
"SASJSONExport":"1.0",
"SASTableData+TEST":[
{
"/u041f/u0435/u0440/u0435/u043c/u0435/u043d/u043d/u0430/u044f":2,
"/u0421/u0440/u0435/u0434/u043d/u0435/u0435":4,
"/u0421/u0442/u0440/u043e/u043a/u0430":"/u0427/u0442/u043e/u002d/u0442/u043e/u0031"
},
{
"/u041f/u0435/u0440/u0435/u043c/u0435/u043d/u043d/u0430/u044f":2,
"/u0421/u0440/u0435/u0434/u043d/u0435/u0435":2,
"/u0421/u0442/u0440/u043e/u043a/u0430":"/u0427/u0442/u043e/u002d/u0442/u043e/u0032"
},
{
"/u041f/u0435/u0440/u0435/u043c/u0435/u043d/u043d/u0430/u044f":1,
"/u0421/u0440/u0435/u0434/u043d/u0435/u0435":42,
"/u0421/u0442/u0440/u043e/u043a/u0430":"/u0427/u0442/u043e/u002d/u0442/u043e/u0033"
}
]
}
;
run;
filename jsm ''~/sasuser.v94/.json.map'' encoding=''utf-8'';
libname jsd json fileref=jsf map=jsm automap=replace;
libname jsm json fileref=jsm;
data jsmm;
merge jsm.datasets jsm.datasets_variables;
by ordinal_DATASETS;
run;
proc sort data=jsmm; by ordinal_root ordinal_DATASETS; run;
data _null_;
set work.jsmm end=last;
if _N_=1 then do;
length s varchar(*) ds varchar(*);
retain s ds prx;
s=''{"DATASETS":['';
ds='''';
prx=prxparse(''/[^_]/'');
end;
if ds=dsname then s=s||'','';
else do;
ds=dsname;
if _N_^=1 then s=s||'']},'';
s=cats(s,''{"DSNAME":"'',ds,''","TABLEPATH":"'',tablepath,''","VARIABLES":['');
end;
s=cats(s,''{"NAME":"'',name,''","TYPE":"'',type,''","PATH":"'',path,''"'');
if prxmatch(prx,name) > length(name) then
s=cats(s,'',"LABEL":"'',scan(path,-1,''/''),''"'');
s=s||''}'';
if last then do;
s=s||'']}]}'';
file jsm;
put s;
end;
run;
libname jsd json fileref=jsf map=jsm;
proc print data=jsd.SASTableData_TEST label noobs; run;
La primera variante de la solución
Es la solución rápida y sucia.
Primero preparando los datos de entrada:
libname _all_ clear;
filename _all_ clear;
filename jsf ''~/sasuser.v94/.json'' encoding=''utf-8'';
data _null_;
file jsf;
length js varchar(*);
input;
js=unicode(_infile_);
put js;
datalines;
{
"SASJSONExport":"1.0",
"SASTableData+TEST": [
{
"/u041f/u0435/u0440/u0435/u043c/u0435/u043d/u043d/u0430/u044f":2,
"/u0421/u0440/u0435/u0434/u043d/u0435/u0435":4,
"/u0421/u0442/u0440/u043e/u043a/u0430":"/u0427/u0442/u043e/u002d/u0442/u043e/u0031"
},
{
"/u041f/u0435/u0440/u0435/u043c/u0435/u043d/u043d/u0430/u044f":2,
"/u0421/u0440/u0435/u0434/u043d/u0435/u0435":2,
"/u0421/u0442/u0440/u043e/u043a/u0430":"/u0427/u0442/u043e/u002d/u0442/u043e/u0032"
},
{
"/u041f/u0435/u0440/u0435/u043c/u0435/u043d/u043d/u0430/u044f":1,
"/u0421/u0440/u0435/u0434/u043d/u0435/u0435":42,
"/u0421/u0442/u0440/u043e/u043a/u0430":"/u0427/u0442/u043e/u002d/u0442/u043e/u0033"
}
]
}
;
run;
El archivo de salida .json
:
{
"SASJSONExport":"1.0",
"SASTableData+TEST": [
{
"Переменная":2,
"Среднее":4,
"Строка":"Что-то1"
},
{
"Переменная":2,
"Среднее":2,
"Строка":"Что-то2"
},
{
"Переменная":1,
"Среднее":42,
"Строка":"Что-то3"
}
]
}
Luego crea el archivo json map .json.map
:
filename jsmf ''~/sasuser.v94/.json.map'' encoding=''utf-8'';
libname jsm json fileref=jsf map=jsmf automap=create;
Los contenidos de .json.map
:
{
"DATASETS": [
{
"DSNAME": "root",
"TABLEPATH": "/root",
"VARIABLES": [
{
"NAME": "ordinal_root",
"TYPE": "ORDINAL",
"PATH": "/root"
},
{
"NAME": "SASJSONExport",
"TYPE": "CHARACTER",
"PATH": "/root/SASJSONExport",
"CURRENT_LENGTH": 3
}
]
},
{
"DSNAME": "SASTableData_TEST",
"TABLEPATH": "/root/SASTableData+TEST",
"VARIABLES": [
{
"NAME": "ordinal_root",
"TYPE": "ORDINAL",
"PATH": "/root"
},
{
"NAME": "ordinal_SASTableData_TEST",
"TYPE": "ORDINAL",
"PATH": "/root/SASTableData+TEST"
},
{
"NAME": "____________________",
"TYPE": "NUMERIC",
"PATH": "/root/SASTableData+TEST/Переменная"
},
{
"NAME": "______________",
"TYPE": "NUMERIC",
"PATH": "/root/SASTableData+TEST/Среднее"
},
{
"NAME": "____________",
"TYPE": "CHARACTER",
"PATH": "/root/SASTableData+TEST/Строка",
"CURRENT_LENGTH": 12
}
]
}
]
}
Cambiemos un poco el archivo eliminando la descripción del conjunto de datos no necesario y agregando etiquetas:
{
"DATASETS": [
{
"DSNAME": "SASTableData_TEST",
"TABLEPATH": "/root/SASTableData+TEST",
"VARIABLES": [
{
"NAME": "ordinal_root",
"TYPE": "ORDINAL",
"PATH": "/root"
},
{
"NAME": "ordinal_SASTableData_TEST",
"TYPE": "ORDINAL",
"PATH": "/root/SASTableData+TEST"
},
{
"NAME": "____________________",
"TYPE": "NUMERIC",
"PATH": "/root/SASTableData+TEST/Переменная",
"LABEL": "Переменная"
},
{
"NAME": "______________",
"TYPE": "NUMERIC",
"PATH": "/root/SASTableData+TEST/Среднее",
"LABEL": "Среднее"
},
{
"NAME": "____________",
"TYPE": "CHARACTER",
"PATH": "/root/SASTableData+TEST/Строка",
"LABEL": "Строка",
"CURRENT_LENGTH": 12
}
]
}
]
}
E intenta de nuevo:
libname jsd json fileref=jsf map=jsmf;
proc print data=jsd.SASTableData_TEST label noobs; run;
El resultado:
+--------------+---------------------------+- ----------+---------+-----------+
| ordinal_root | ordinal_SASTableData_TEST | Переменная | Среднее | Строка |
+--------------+---------------------------+------------+---------+-----------+
| 1 | 1 | 2 | 4 | Что-то1 |
| 1 | 2 | 2 | 2 | Что-то2 |
| 1 | 3 | 1 | 42 | Что-то3 |
+--------------+---------------------------+------------+---------+-----------+
Todo fue hecho en SAS University Edition.