Формати JSON и YAML¶
У поглављу о обради текста смо научили како коришћењем регуларних израза и контекстно слободних граматика и технике рекурзивног спуста можемо имплементирати парсере за различите облике правилно структурираних текстуалних садржаја. У овом поглављу ћемо видети алтернативу том приступу. Наиме, постоје неки добро познати формати (на пример, JSON, YAML, XML) који се могу употребити за структурирање текстуалног садржаја, а за које већ постоје готови парсери у већини савремених програмских језика. Уместо да дефинишемо свој специфичан улазни формат за запис жељених података и да програмирамо специфичан парсер за тај формат, често има смисла своје податке записати у неком од тих распрострањених формата и употребити готова парсер за одабрани формат.
Наведени формати се обично користе за чување одређених мета-података (на пример, података о имена аутора, датуму креирања, опису садржаја и слично), за опис конфигурационих параметара тј. подешавања софтвера, за пренос мање количине података преко веба и слично. Скренимо пажњу на то да се веће количине података обично чувају у базама података, јер се за разлику од текстуалних формата подаци у базама чувају на начин који омогућава веома ефикасну претрагу, проширивање, ажурирање и брисање.
JSON¶
JSON (енгл. JavaScript Object Notation) је формат за запис података који потиче из језика JavaScript, али је постао толико уобичајен да се данас користи из великог броја различитих програмских језика (укључујући и C#). У наставку нећемо описивати све детаље овог формата, већ ћемо кроз неколико примера покушати да опишемо оне најкоришћеније. Податке у формату JSON најчешће записујемо у облику објеката (структура, тј. речника) и низова. На пример, наредни JSON запис садржи податке о ученику Петру Петровићу.
{ "ime": "Petar", "prezime": "Petrović", "prosek": 4.75 }
У питању је објекат (речник) са три поља: поље ime
чија је
вредност Petar
, поље vrednost
чија је вредност Petrovic
и
поље prosek
чија је вредност нумеричка и износи 4,75. Сви објекти
се записују у витичастим заградама, док се и називи поља (кључеви)
записују под наводницима. Текстуалне вредности поља се такође записују
под наводницима, док се бројевне вредности записују уобичајено, без
наводника (уз коришћење децималне тачке, а не запете ако су у питању
рационални бројеви).
Низови вредности се наводе између угластих заграда. На пример, запис
["Pera", "Ana", "Jovana"]
представља низ од три ниске (имена ученика). Слично, можемо дефинисати и низ бројева (на пример, оцена једног ученика).
[5, 3, 4, 5, 5]
Елементни низова могу бити и други низови или објекти. У наредном примеру је описан низ ученика.
[
{
"ime": "Petar",
"prezime": "Petrovic",
},
{
"ime": "Ana",
"prezime": "Anić"
}
]
Приметимо да формат није осетљив на белине (размаке, преласке у нови ред и слично), па се може користити произвољан стил назубљивања ради повећања читљивости.
Иако формат JSON допушта и прављење низова у којима се мешају подаци различитог типа, то нећемо користити.
Детаљније информације о формату JSON можете пронаћи на интернету (на пример, https://www.json.org/, https://en.wikipedia.org/wiki/JSON).
Приступ JSON формату из C# програма¶
Прикажимо сада како да из програма у језику C# учитамо податке из
формата JSON. Од верзије .NET 6.0 (која се испоручује уз Visual
Studio 2022) постоји библиотечка подршка за рад са форматом JSON
(раније је за то било потребно инсталирати неку специјализовану
библиотеку, а најпознатија таква библиотека је била Newtonsoft Json.NET
).
Сасвим природно, желимо да се објекти записани у формату JSON у нашем
програму представе C# објектима, а низови C# низовима или
листама. Зато је прво потребно у нашем програму дефинисати класе
објеката које ћемо учитати. Кренимо од програма који учитава само
податке о једном ученику. Дефинишемо класу Ucenik
која има два
поља (ime
и prezime
) типа string?
. Упитник иза назива типа
није грешка, већ у језику C# означава посебан тип, анулирајући
стринг (енгл. nullable string). Анулирајући типови (енгл. nullable
types) служе да се нагласи да нека вредност може остати недодељена
(null
) и компилатор тера програмера да приликом приступа садржају
провери да ли је вредност null
(и обичан стринг може имати
вредност null
, али компилатор не јавља грешку ако програмер, на
пример, покуша да испише стринг, а да није претходно проверио да ли је
вредност null
, што може довести до изузетка и насилног прекида
програма). Када учитавамо податке из JSON записа немамо гаранцију да
ће тај запис садржати и име и презиме и могуће је да ће неко поље
остати непопуњено, због чега је увек пожељно користити анулирајуће
типове.
Претпоставимо, за почетак, да је JSON опис задат помоћу ниске json
унутар самог C# програма (касније ћемо показати како се опис може
учитати из датотеке). Парсирање (каже се и десеријализација) се
врши статичком методом JsonSerializer.Deserialize
. Тој методи се
као шаблонски параметар између заграда <...>
наводи класа која се
на улазу очекује, а као обичан параметар се наводи ниска која садржи
JSON опис. Да би се ова метода могла користити потребно је укључити
именски простор System.Text.Json
. Метода враћа објекат дате класе
који такође треба да буде анулирајућег типа (у нашем случају
Ucenik?
), јер је могуће да читање тог објекта није
успело. Приметимо да се приступ пољима анулирајућих објеката врши уз
навођење упитника након имена променљиве (у том случају програм неће
бити насилно прекинут са радом ако променљива има вредност null
).
Прикажимо сада како бисмо учитали податке о низу ученика записаном у
формату JSON. Бирамо да их након учитавања сместимо у листу. Пре
исписа елемената листе проверавамо да ли је листа успешно учитана
(поредимо вредност променљиве ucenici
са null
) и ако јесте,
надаље можемо слободно да се понашамо као да је у питању променљива
обичног, а не анулирајућег типа.
У наредном програму приказујемо како да JSON запис учитамо из
датотеке. Претпоставићемо да се датотека зове ucenici.json
, да је
смештена у истом директоријуму као програм који пишемо и да има
следећи садржај:
Најједноставнији начин да уитамо цео садржај датотеке у ниску у
програму је коришћењем методе File.ReadAllText
којој се прослеђује
назив тј. путања до датотеке. Пошто приликом покушаја читања може доћи
до разних изузетака (на пример, наведена датотека не мора да постоји),
пожељно је употребити обраду изузетака (try/catch
).
Поред парсирања JSON записа (десеријализације), подржана је
обратна операција (серијализација) којом се C# објекти и низови
преводе у JSON формат. Наредни програм листу ученика записује у
формату JSON. Користи се статичка метода JsonSerializer.Serialize
,
која враћа ниску са JSON записом прослеђених података. Да би ниска
била лепо форматирана, наводе се и додатне опције
new JsonSerializerOptions { WriteIndented = true }
.
YAML¶
Формат YAML представља алтернативу формату JSON. За разлику од формата JSON који занемарује белине и допушта слободно форматирање улаза, формат YAML користи белине и угнежђавање да би наметнуо структуру. Размотримо пример листе ученика:
- ime: Petar
prezime: Petrović
prosek: 4.75
- ime: Ana
prezime: Anić
prosek: 5.00
Елементи низа су наведени у облику набрајања, а речник се препознаје навођењем кључева и вредности раздвојених двотачкама. Нагласимо да постоје и други начини за опис низова и речника (на пример, за навођење низова се поново могу користити угласте заграде). Приметимо да је број унетих карактера мањи него када се користи JSON (на пример, ниске нису ограђене наводницима). Са друге стране, формат је осетљивији на грешке (да је, на пример, поље које садржи презиме било увучено један карактер више или мање, запис не би био исправан). Препуштамо вам да више о овом формату потражите на интернету (на пример, https://yaml.org/, https://en.wikipedia.org/wiki/YAML).
Формат YAML се користи ређе од формата JSON из C# програма, тако да не
постоји библиотечка подршка за рад са њим. Једноставна серијализација
података у YAML и десеријализација из YAML-а се може постићи
коришћењем библиотеке YamlDotNet
. Њу је пре коришћења потребно
инсталирати, а најједноставнији начин да се то уради је коришћење
алатке која се назива NuGet
и која омогућава да веома једноставно
инсталирате разне библиотеке које могу бити корисне приликом
програмирања у језику C#. Ова алатка је интегрисана у Visual Studio.
Упутство како се NuGet користи из окружења Visual Studio je доступно
овде:
https://docs.microsoft.com/en-us/nuget/consume-packages/install-use-packages-visual-studio
https://docs.microsoft.com/en-us/nuget/quickstart/install-and-use-a-package-in-visual-studio
Инсталирање пакета YamlDotNet
може бити још једноставније. Довољно
је отворити конзолни прозор (опцијом менија Tools -> NuGet Package Manager -> Package Manager Console
) и затим унети наредбу
PM> Install-Package YamlDotNet
Када је библиотека YamlDotNet
инсталирана, можемо је
употребити. На пример, наредни програм врши серијализацију низа
ученика и на екран (у конзолни прозор) исписује податке о датим
ученицима у формату YAML. Приметимо да је на почетку програма било
потребно укључивање потребног именског простора YamlDotNet.Serialization
.
Након покретања програма у конзолу се исписује следећи садржај:
- ime: Pera
prezime: Peric
- ime: Ana
prezime: Anic
За вежбу вам остављамо да проучите како се може вршити десеријализација тј. учитавање података из датотеке у формату YAML.
Креирај JSON датотеку која садржи податке о неколико књига из твоје кућне библиотеке. Дефиниши класе за представљање књига и напиши C# програм који учитава податке о књимага из JSON датотеке и приказује их у графичкој апликацији. Омогући измену података о књигама, додавање нових књига и брисање књига у графичкој апликацији. Омогући чување измењених података у JSON датотеци. Прилагоди апликацију тако да поред JSON формата подржава и YAML.