将 JSON xstring 反序列化为 ABAP 中的结构
Deserializing JSON xstring to structure in ABAP
我想将 JSON 字符串反序列化为如下定义的结构:
TYPES: BEGIN OF json_subobject,
c TYPE i,
d TYPE decfloat34,
END OF json_subobject.
TYPES: BEGIN OF json_object,
a TYPE c LENGTH 10,
b TYPE json_subobject,
END OF json_object.
DATA: foo TYPE json_object.
我在 JSON 中对这个结构建模如下:
{
"a":"FooBar",
"b":{
"c":9,
"d":3.14
}
}
现在,我写了一个简单的程序来尝试上面JSON 上的CALL TRANSFORMATION 语句以及上面的结构定义。该程序应该反序列化 JSON(硬编码到变量 lv_xmls 中)并打印出结果结构的内容。结构的内容应该与原始JSON的内容相匹配。这是程序:
TYPES: BEGIN OF json_subobject,
c TYPE i,
d TYPE decfloat34,
END OF json_subobject.
TYPES: BEGIN OF json_object,
a TYPE c LENGTH 10,
b TYPE json_subobject,
END OF json_object.
DATA: foo TYPE json_object.
DATA: lv_xmls TYPE string VALUE '{"a":"FooBar","b":{"c":9,"d":3.14}}',
lv_xmlb TYPE xstring.
TRY.
lv_xmlb = cl_abap_codepage=>convert_to(
source = lv_xmls
codepage = `UTF-8`
endian = space
replacement = '#'
ignore_cerr = abap_false ).
CATCH cx_parameter_invalid_range cx_sy_codepage_converter_init cx_sy_conversion_codepage cx_parameter_invalid_type.
ENDTRY.
WRITE: |Deserializing JSON ...|.
NEW-LINE.
CALL TRANSFORMATION id SOURCE XML lv_xmlb RESULT XML = foo.
WRITE: '{'.
NEW-LINE.
WRITE: | "a": "{ foo-a }",|.
NEW-LINE.
WRITE: | "b": \{|.
NEW-LINE.
WRITE: | "c": { foo-b-c },|.
NEW-LINE.
WRITE: | "d": { foo-b-d },|.
NEW-LINE.
WRITE: | \}|.
NEW-LINE.
WRITE: |\}|.
我期望的输出是:
Deserializing JSON ...
{
"a":"FooBar",
"b":{
"c":9,
"d":3.14
}
}
但不幸的是,我得到的输出是:
Deserializing JSON ...
{
"a":"",
"b":{
"c":0,
"d":0
}
}
看起来 CALL TRANSFORMATION 语句对我没有任何作用。
有没有 ABAP 大师可以告诉我如何在这个(希望如此)简单的案例中使用 CALL TRANSFORMATION?我已经环顾四周,发现 this helpful GitHub repo 演示了如何将 JSON 反序列化为 class,但为了简单起见,我更愿意将 JSON 反序列化为结构。我不完全确定如何使用 CALL TRANSFORMATION,因为我不熟悉 XSLT 和高级 XML 功能,所以如果可能,我将非常感谢现成的解决方案...
非常感谢,
约书亚
我不是一个好的 ABAP 开发者,所以我不知道是否有更好的代码来做这件事,但这对我有用:
TYPES: BEGIN OF json_subobject,
c TYPE i,
d TYPE decfloat34,
END OF json_subobject.
TYPES: BEGIN OF json_object,
a TYPE c LENGTH 10,
b TYPE json_subobject,
END OF json_object.
DATA: foo TYPE json_object,
writer TYPE REF TO cl_sxml_string_writer,
json TYPE xstring.
DATA: lv_xmls TYPE string VALUE '{"a":"FooBar","b":{"c":9,"d":3.14}}',
lv_xmlb TYPE xstring.
*TRY.
* lv_xmlb = cl_abap_codepage=>convert_to(
* source = lv_xmls
* codepage = `UTF-8`
* endian = space
* replacement = '#'
* ignore_cerr = abap_false ).
* CATCH cx_parameter_invalid_range cx_sy_codepage_converter_init cx_sy_conversion_codepage cx_parameter_invalid_type.
* ENDTRY.
WRITE: |Deserializing JSON ...|.
NEW-LINE.
cl_fdt_json=>json_to_data( EXPORTING iv_json = lv_xmls
CHANGING ca_data = foo ).
WRITE: '{'.
NEW-LINE.
WRITE: | "a": "{ foo-a }",|.
NEW-LINE.
WRITE: | "b": \{|.
NEW-LINE.
WRITE: | "c": { foo-b-c },|.
NEW-LINE.
WRITE: | "d": { foo-b-d },|.
NEW-LINE.
WRITE: | \}|.
NEW-LINE.
WRITE: |\}|.
此代码只是将 JSON 数组转换为内部 table。
我的回答分为两部分。根据我的说法,第一个是最适合 JSON 的解决方案,第二部分解释了为什么您的代码不适用于 CALL TRANSFORMATION ID
.
第 1 部分:
您最好使用更适合处理 JSON 的 SAP classes 之一。我更喜欢 class /UI2/CL_JSON
,根据我的说法,这是最 "open" class,因为它是 SAP 宣传最多的(见下面的文档),虽然没有官方支持(是的,这很难理解,欢迎来到 SAP 世界。
TYPES: BEGIN OF json_subobject,
c TYPE i,
d TYPE decfloat34,
END OF json_subobject.
TYPES: BEGIN OF json_object,
a TYPE c LENGTH 10,
b TYPE json_subobject,
END OF json_object.
DATA: foo TYPE json_object.
/ui2/cl_json=>deserialize(
EXPORTING json = '{"a":"FooBar","b":{"c":9,"d":3.14}}'
CHANGING data = foo ).
ASSERT foo = VALUE json_object(
a = 'FooBar'
b-c = 9
b-d = '3.14' ).
更多信息参考文档:
- Wiki on SCN, by the SAP author, Alexey Arseniev (or if he's not the original author, he's part of the team who maintains the class)
- Blog post on SCN: Parsing JSON in ABAP, by Kerem Koseoglu, on 2017/08/03
第 2 部分:
您使用 CALL TRANSFORMATION ID
的代码不起作用有两个原因:
- JSON 必须始终是一个 JSON 对象,其成员以根名称 (
RESULT rootname1 = var1 rootname2 = var2
) 命名。您只定义了一个名为 "XML" 的根,因此 JSON 应该类似于 {"X-ML":...}
(它是 X-ML
而不是 XML
因为特定的 ABAP reason )
- ABAP 组件名称以大写字母(A、B、C、D)内部存储在 SAP 中,身份转换
ID
区分大小写成员名称,因此 JSON 数据中的成员名称应为大写(您的所有名称均为小写 a、b、c、d)。
换句话说,如果您的输入 JSON 包含以下值,您的代码可能会工作:
lv_xmls = '{"X-ML":{"A":"FooBar","B":{"C":9,"D":3.14}}}'.
另一种解决方案可能包括创建自定义身份转换,将 JSON 成员名称转换为大写并添加虚拟根元素。但那是另外一回事了。
我想将 JSON 字符串反序列化为如下定义的结构:
TYPES: BEGIN OF json_subobject,
c TYPE i,
d TYPE decfloat34,
END OF json_subobject.
TYPES: BEGIN OF json_object,
a TYPE c LENGTH 10,
b TYPE json_subobject,
END OF json_object.
DATA: foo TYPE json_object.
我在 JSON 中对这个结构建模如下:
{
"a":"FooBar",
"b":{
"c":9,
"d":3.14
}
}
现在,我写了一个简单的程序来尝试上面JSON 上的CALL TRANSFORMATION 语句以及上面的结构定义。该程序应该反序列化 JSON(硬编码到变量 lv_xmls 中)并打印出结果结构的内容。结构的内容应该与原始JSON的内容相匹配。这是程序:
TYPES: BEGIN OF json_subobject,
c TYPE i,
d TYPE decfloat34,
END OF json_subobject.
TYPES: BEGIN OF json_object,
a TYPE c LENGTH 10,
b TYPE json_subobject,
END OF json_object.
DATA: foo TYPE json_object.
DATA: lv_xmls TYPE string VALUE '{"a":"FooBar","b":{"c":9,"d":3.14}}',
lv_xmlb TYPE xstring.
TRY.
lv_xmlb = cl_abap_codepage=>convert_to(
source = lv_xmls
codepage = `UTF-8`
endian = space
replacement = '#'
ignore_cerr = abap_false ).
CATCH cx_parameter_invalid_range cx_sy_codepage_converter_init cx_sy_conversion_codepage cx_parameter_invalid_type.
ENDTRY.
WRITE: |Deserializing JSON ...|.
NEW-LINE.
CALL TRANSFORMATION id SOURCE XML lv_xmlb RESULT XML = foo.
WRITE: '{'.
NEW-LINE.
WRITE: | "a": "{ foo-a }",|.
NEW-LINE.
WRITE: | "b": \{|.
NEW-LINE.
WRITE: | "c": { foo-b-c },|.
NEW-LINE.
WRITE: | "d": { foo-b-d },|.
NEW-LINE.
WRITE: | \}|.
NEW-LINE.
WRITE: |\}|.
我期望的输出是:
Deserializing JSON ...
{
"a":"FooBar",
"b":{
"c":9,
"d":3.14
}
}
但不幸的是,我得到的输出是:
Deserializing JSON ...
{
"a":"",
"b":{
"c":0,
"d":0
}
}
看起来 CALL TRANSFORMATION 语句对我没有任何作用。
有没有 ABAP 大师可以告诉我如何在这个(希望如此)简单的案例中使用 CALL TRANSFORMATION?我已经环顾四周,发现 this helpful GitHub repo 演示了如何将 JSON 反序列化为 class,但为了简单起见,我更愿意将 JSON 反序列化为结构。我不完全确定如何使用 CALL TRANSFORMATION,因为我不熟悉 XSLT 和高级 XML 功能,所以如果可能,我将非常感谢现成的解决方案...
非常感谢,
约书亚
我不是一个好的 ABAP 开发者,所以我不知道是否有更好的代码来做这件事,但这对我有用:
TYPES: BEGIN OF json_subobject,
c TYPE i,
d TYPE decfloat34,
END OF json_subobject.
TYPES: BEGIN OF json_object,
a TYPE c LENGTH 10,
b TYPE json_subobject,
END OF json_object.
DATA: foo TYPE json_object,
writer TYPE REF TO cl_sxml_string_writer,
json TYPE xstring.
DATA: lv_xmls TYPE string VALUE '{"a":"FooBar","b":{"c":9,"d":3.14}}',
lv_xmlb TYPE xstring.
*TRY.
* lv_xmlb = cl_abap_codepage=>convert_to(
* source = lv_xmls
* codepage = `UTF-8`
* endian = space
* replacement = '#'
* ignore_cerr = abap_false ).
* CATCH cx_parameter_invalid_range cx_sy_codepage_converter_init cx_sy_conversion_codepage cx_parameter_invalid_type.
* ENDTRY.
WRITE: |Deserializing JSON ...|.
NEW-LINE.
cl_fdt_json=>json_to_data( EXPORTING iv_json = lv_xmls
CHANGING ca_data = foo ).
WRITE: '{'.
NEW-LINE.
WRITE: | "a": "{ foo-a }",|.
NEW-LINE.
WRITE: | "b": \{|.
NEW-LINE.
WRITE: | "c": { foo-b-c },|.
NEW-LINE.
WRITE: | "d": { foo-b-d },|.
NEW-LINE.
WRITE: | \}|.
NEW-LINE.
WRITE: |\}|.
此代码只是将 JSON 数组转换为内部 table。
我的回答分为两部分。根据我的说法,第一个是最适合 JSON 的解决方案,第二部分解释了为什么您的代码不适用于 CALL TRANSFORMATION ID
.
第 1 部分:
您最好使用更适合处理 JSON 的 SAP classes 之一。我更喜欢 class /UI2/CL_JSON
,根据我的说法,这是最 "open" class,因为它是 SAP 宣传最多的(见下面的文档),虽然没有官方支持(是的,这很难理解,欢迎来到 SAP 世界。
TYPES: BEGIN OF json_subobject,
c TYPE i,
d TYPE decfloat34,
END OF json_subobject.
TYPES: BEGIN OF json_object,
a TYPE c LENGTH 10,
b TYPE json_subobject,
END OF json_object.
DATA: foo TYPE json_object.
/ui2/cl_json=>deserialize(
EXPORTING json = '{"a":"FooBar","b":{"c":9,"d":3.14}}'
CHANGING data = foo ).
ASSERT foo = VALUE json_object(
a = 'FooBar'
b-c = 9
b-d = '3.14' ).
更多信息参考文档:
- Wiki on SCN, by the SAP author, Alexey Arseniev (or if he's not the original author, he's part of the team who maintains the class)
- Blog post on SCN: Parsing JSON in ABAP, by Kerem Koseoglu, on 2017/08/03
第 2 部分:
您使用 CALL TRANSFORMATION ID
的代码不起作用有两个原因:
- JSON 必须始终是一个 JSON 对象,其成员以根名称 (
RESULT rootname1 = var1 rootname2 = var2
) 命名。您只定义了一个名为 "XML" 的根,因此 JSON 应该类似于{"X-ML":...}
(它是X-ML
而不是XML
因为特定的 ABAP reason ) - ABAP 组件名称以大写字母(A、B、C、D)内部存储在 SAP 中,身份转换
ID
区分大小写成员名称,因此 JSON 数据中的成员名称应为大写(您的所有名称均为小写 a、b、c、d)。
换句话说,如果您的输入 JSON 包含以下值,您的代码可能会工作:
lv_xmls = '{"X-ML":{"A":"FooBar","B":{"C":9,"D":3.14}}}'.
另一种解决方案可能包括创建自定义身份转换,将 JSON 成员名称转换为大写并添加虚拟根元素。但那是另外一回事了。