ABAP ve JSON
JSON formatı bugünlerde yaygın olarak kullanılıyor. SAP ABAP kullanarak geliştirme yaparken JSON formatlı veriyi yorumlama, okuma ya da oluşturmaya ihtiyaç duyabiliyoruz. Bu blog yazısında ihtiyaç duyduğumuz işlemleri nasıl yapabileceğimizi anlatmaya çalışacağım.
ABAP kullanımına başlamadan önce JSON (JavaScript Object Notation) hakkında biraz bilgi vermek gerekirse:
- JavaScript programlama dili standardının bir alt kümesini temel alır.
- Programcılar için okuması ve yazması kolaydır.
- Makinelerin ayrıştırması ve oluşturması kolaydır.
- İki yapı üzerine kuruludur:
- Ad-değer çiftlerinden oluşan bir koleksiyon
- Sıralı bir değerler listesi
JSON Örnekleri
İlk örnek, ad ve değer çiftlerinden oluşan bir koleksiyona sahiptir. Bu çiftler malzeme(matnr), malzeme tanımı(maktx), temel ölçü birimini(meins) ve değerlerini içeren aşağıdaki yapıda gösterilmiştir.
{ "matnr": "50065557", "maktx": "Test Malzeme", "meins": "ST" }
Aşağıdaki ikinci örnek, ilk örnekteki koleksiyonların listesini gösterir.
{ "materials": [ { "matnr": "50065557", "maktx": "Test Malzeme", "meins": "ST" }, { "matnr": "50065558", "maktx": "Test Malzeme2", "meins": "ST" }, { "matnr": "50065559", "maktx": "Test Malzeme3", "meins": "ST" } ] }
JSON ve XML
JSON, XML'e benzer şekilde çalışır. Her ikisi de programcı tarafından okunabilir, her ikisi de hiyerarşiktir ve çeşitli programlama dillerinde kullanılmaktadır. Ancak JSON, XML'den daha basittir, tagleri kullanmaz ve bu nedenle daha kısadır, okuması ve yazması kolaydır.
Şimdi JSON'un ABAP'ta nasıl işlenebileceğine geri dönelim.
ABAP'ta JSON Verilerinin Doğrulanması
CL_SXML_STRING_READER sınıfını kullanarak verinin doğruluğunu kontrol edeceğiz. Yukarıda bahsettiğim gibi JSON ve XML benzer olduğundan, her ikisi için de aynı sınıf kullanılabilir.
DATA lv_json TYPE string VALUE '{"matnr":"50065557","maktx":"Test Malzeme","meins":"ST"}'. DATA(lo_reader) = cl_sxml_string_reader=>create( cl_abap_codepage=>convert_to( lv_json ) ). TRY. lo_reader->next_node( ). lo_reader->skip_node( ). cl_demo_output=>display( 'JSON is valid' ). CATCH cx_sxml_parse_error INTO DATA(lx_parse_error). cl_demo_output=>display( lx_parse_error->get_text( ) ). ENDTRY.
JSON geçerli olduğunda, “JSON is valid” çıktısını alırız.
Ardından, JSON stringimizi hata alacak şekilde değiştirelim ve yeniden deneyelim.
DATA lv_json TYPE string VALUE '{"matnr":"50065557","maktx":"Test Malzeme","meins":"ST"ASL}'. DATA(lo_reader) = cl_sxml_string_reader=>create( cl_abap_codepage=>convert_to( lv_json ) ). TRY. lo_reader->next_node( ). lo_reader->skip_node( ). cl_demo_output=>display( 'JSON is valid' ). CATCH cx_sxml_parse_error INTO DATA(lx_parse_error). cl_demo_output=>display( lx_parse_error->get_text( ) ). ENDTRY.
Programı yürüttüğümüzde “Error while parsing an XML stream: '',' or '}' expected at 'ASL}''.” Çıktısını alırız.
ABAP’ta JSON Verilerinin Okunması
/UI2/CL_JSON sınıfını kullanarak veriyi okuyacak ve ayrıştıracağız. Bunu yapabilmek için farklı alternatiflerimiz de var ama başlangıç için iyi bir seçenek.
TYPES: BEGIN OF ty_material, matnr TYPE string, maktx TYPE string, meins TYPE string, END OF ty_material. DATA: lv_json TYPE string, lr_data TYPE REF TO data, ls_material TYPE ty_material, lt_material TYPE STANDARD TABLE OF ty_material. FIELD-SYMBOLS TYPE ANY TABLE. lv_json = '{"materials": [{"matnr":"50065557","maktx":"Test Malzeme","meins":"ST"},' && '{"matnr":"50065558","maktx":"Test Malzeme2","meins":"ST"},' && '{"matnr":"50065559","maktx":"Test Malzeme3","meins":"ST"} ] } '. /ui2/cl_json=>deserialize( EXPORTING json = lv_json pretty_name = /ui2/cl_json=>pretty_mode-user assoc_arrays = abap_true CHANGING data = lr_data ). IF lr_data IS BOUND. ASSIGN lr_data->* TO FIELD-SYMBOL(). ASSIGN COMPONENT 'MATERIALS' OF STRUCTURE TO FIELD-SYMBOL(). ASSIGN ->* TO . LOOP AT ASSIGNING FIELD-SYMBOL(). DO 3 TIMES. CASE sy-index. WHEN 1. DATA(lv_fname) = 'MATNR'. WHEN 2. lv_fname = 'MAKTX'. WHEN 3. lv_fname = 'MEINS'. ENDCASE. ASSIGN COMPONENT sy-index OF STRUCTURE ls_material TO FIELD-SYMBOL(). ASSIGN ->* TO FIELD-SYMBOL(). ASSIGN COMPONENT lv_fname OF STRUCTURE TO FIELD-SYMBOL(). IF IS ASSIGNED AND IS ASSIGNED. ASSIGN ->* TO FIELD-SYMBOL(). IF IS ASSIGNED. = . ENDIF. ENDIF. ENDDO. APPEND ls_material TO lt_material. ENDLOOP. cl_demo_output=>display( lt_material ). ENDIF.
Çalıştırdığımızda programın çıktısı aşağıdaki gibi olacaktır.
ABAP’ta JSON Verilerinin Oluşturulması
SELECT * FROM scarr INTO TABLE @DATA(lt_scarr). DATA(lv_json) = /ui2/cl_json=>serialize( data = lt_scarr compress = abap_true pretty_name = /ui2/cl_json=>pretty_mode-camel_case ). " Display JSON in ABAP CALL TRANSFORMATION sjson2html SOURCE XML lv_json RESULT XML DATA(lvc_html). cl_abap_browser=>show_html( title = 'Sample JSON' html_string = cl_abap_codepage=>convert_from( lvc_html ) ).
Programın çıktısı aşağıdaki gibi olacaktır.
Yukarıdaki örnekte, JSON'u HTML olarak görüntülemek için CALL TRANSFORMATION kullandık. Burada internal table -> JSON dönüşümü olarak kullanacağız.
DATA lv_json TYPE string. SELECT * FROM scarr INTO TABLE @DATA(lt_scarr). DATA(lo_writer) = cl_sxml_string_writer=>create( type = if_sxml=>co_xt_json ). CALL TRANSFORMATION id SOURCE values = lt_scarr RESULT XML lo_writer. cl_abap_conv_in_ce=>create( )->convert( EXPORTING input = lo_writer->get_output( ) IMPORTING data = lv_json ).
JSON stringi, debugta aşağıdaki gibi görünür.
Oluşturduğumuz stringi CALL TRANSFORMATION yoluyla hala dönüştürebiliriz.
CLEAR lt_scarr. CALL TRANSFORMATION id SOURCE XML lv_json RESULT values = lt_scarr. cl_demo_output=>display( lt_scarr ).
Programın çıktısı aşağıdaki gibi olacaktır.
Daha fazla bilgiye erişmek için CL_SXML_TABLE_READER sınıfını ve nasıl kullanılacağını araştırabilirsiniz. Ayrıca SABAPDEMOS paketinde DEMO_JSON_* ile başlayan demo programları inceleyebilirsiniz.