我想将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?我已经环顾四周,发现这个有用的GitHub repo演示了如何将JSON反序列化为类,但为了简单起见,我更喜欢将JSON反格式化为结构。我不完全确定如何使用CALL TRANSFORMATION,因为我不熟悉XSLT和高级XML功能,所以如果可能的话,我非常感谢一个现成的解决方案。。。
提前感谢
约书亚
我的答案分为两部分。根据我的说法,第一部分是最适合JSON的解决方案,第二部分解释了为什么您的代码不能使用CALL TRANSFORMATION ID
。
第1部分:
您最好使用一个更适合处理JSON的SAP类。我更喜欢/UI2/CL_JSON
类,这是我认为最"开放"的类,因为它是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' ).
更多信息参考文件:
- SCN上的Wiki,由SAP作者Alexey Arseniev撰写(或者,如果他不是原作者,他是维护该类的团队的一员(
- 关于SCN的博客文章:在ABAP中解析JSON,作者Kerem Koseoglu,2017年8月3日
第2部分:
使用CALL TRANSFORMATION ID
的代码无法工作有两个原因:
- JSON必须始终是一个JSON对象,其成员以根名称(
RESULT rootname1 = var1 rootname2 = var2
(命名。您只定义了一个名为"XML"的根,因此JSON应该类似于{"X-ML":...}
(由于特定的ABAP原因,它是X-ML
而不是XML
( - 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成员名称转换为大写,并添加一个伪根元素。但那是另一回事。
我不是一个优秀的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数组转换为一个内部表。