Application Development Discussions
Join the discussions or start your own on all things application development, including tools and APIs, programming models, and keeping your skills sharp.
cancel
Showing results for 
Search instead for 
Did you mean: 

Error in Simple Transformation code with embedded ABAP structure

johnm16
Participant
0 Kudos

Hi Folks,

another question regarding the code within a simple transformation, where I am transforming a deep ABAP structure into a JSON string.

The parent ABAP structure contains, as well as some string fields, an embedded flat structure:

ACCESS_TOKEN		Types	ZDE_ACCESS_TOKEN	STRING
USER_GSTIN		Types	ZDE_USER_GSTIN		STRING
DATA_SOURCE		Types	ZDE_DATA_SOURCE		STRING
TRANSACTION_DETAILS	Types	ZSTY_TRANS_DETAILS
The embedded "transaction_details" structure contains string fields:
SUPPLY_TYPE		Types	ZDE_SUPPLY_TYPE		STRING
CHARGE_TYPE		Types	ZDE_CHARGE_TYPE		STRING
This is what the critical part of my transformation code (in XSLT) looks like:
      <str name="data_source">
        <tt:value ref="einvoice_request.data_source"/>
      </str>
      <transaction_details>
        <object>
          <str name="supply_type">
            <tt:value ref="einvoice_request.transaction_details.supply_type"/>
          </str>
When debugging, as soon as the transformation hits the "transaction_details" element, it fails. Obviously the code is incorrect, but I don't know how to declare the "transaction_details" element as an embedded flat structure.
Could anyone give me a pointer on this? I can't find any JSON demo code that embeds a structure, only tables with the 'array' tag.

Thanks for reading,

JM

At the risk of sounding patronising (which I don't mean to be), I hope @sandra.rossi reads this.

11 REPLIES 11

Sandra_Rossi
Active Contributor
0 Kudos

EDIT : please forget my answer, it's only valid for XML but the question is about JSON.

Use tt:ref to change the current data node:

<transaction_details tt:ref="TRANSACTION_DETAILS"><br>

See ABAP documentation - ST - tt:ref, Current Node

NB: that's weird to have the XML with ABAP names in lower case, instead of camel case e.g., TransactionDetails...

0 Kudos

Hi Sandra,

I tried your suggestion, and it flags a syntax error.

However, I tried this:

<object name="transaction_details">
...
</object>

And it seems to work. At least, it doesn't fall over during debugging, although I haven't got as far as the resulting JSON string to be able to check, because...

...unfortunately, I now have a problem with an embedded table type:

      <array>
        <tt:loop ref="einvoice_request.item_list">
          <object>
            <num name="item_serial_number">
              <tt:value ref="$ref.item_serial_number"/>
            </num>
The root structure is "einvoice_request", and the embedded table field name is "item_list". I copied the loop format from DEMO_ST_JSON_TABLE, but although it activates OK (almost anything seems to activate in ST) my version falls over as soon as it hits the <object> element. In this case, I don't see that I can give a reference (or a name) to the object, as it's just a line of the "item_list" table. If I remove the <object> element, it falls over when it hits the element "item_serial_number" (the value passed to "item_serial_number" is "000010", BTW).Re. lower/camel case, I read somewhere that when doing a transform to JSON-XML, that's how it should be - there's a lot of misleading information out there. Lack of camel-case doesn't seem to affect it though.Any ideas on the table loop? Cheers,

John

0 Kudos

Sorry, forget my answer, I was way too fast, and replied on XML, although you said it was JSON.

0 Kudos

<array> alone is weird, probably it should contain a name="..."

but difficult to say, it depends on the exact data type of your input variable.

0 Kudos

And yet this is part of the only ABAP to JSON demo ST (DEMO_ST_JSON_TABLE) with a table loop:

    <array>
      <tt:loop ref=".CARRIERS">
        <object>
          <str name="Carrier-Id">
            <tt:value ref="$ref.carrid"/>
          </str>
Which is what I copied...My source data is a (deep) structure, with a table type field. The table type has a flat structure as the line type.I'll experiment with naming the array and report back.

0 Kudos

I know very well ST, so if you need help... (I'll try to better read your question, next time)

0 Kudos

Named the array, no difference.

Cannot fathom why it doesn't like the <object> line: there are a lot of ABAP to JSON examples which contain almost identical source code, certainly in terms of the relationship between the table array and the table line. I've got an old XML ST which is way more complex, with loads of nested tables and structures, and it works like a dream. Seems that the JSON STs are a whole lot trickier to write.

0 Kudos

Difficult to say, so I advise to convert your ABAP structure to JSON-XML, and compare it with what you have in your ST transformation.

Use this to get JSON-XML:

DATA(json_xml) = VALUE xstring( ).
PERFORM convert_dobj_to_json_xml USING 'DUMMY' your_abap_variable CHANGING json_xml.

FORM convert_dobj_to_json_xml USING rootname TYPE clike dobj TYPE any CHANGING json_xml TYPE xstring. " Convert first DOBJ to JSON DATA(writer) = cl_sxml_string_writer=>create( type = if_sxml=>co_xt_json ). DATA(srcbind_tab) = VALUE abap_trans_srcbind_tab( ( name = rootname value = REF #( dobj ) ) ). CALL TRANSFORMATION id SOURCE (srcbind_tab) RESULT XML writer. DATA(json) = writer->get_output( ). " Convert JSON to JSON-XML CALL TRANSFORMATION id SOURCE XML json RESULT XML json_xml OPTIONS xml_header = 'no'. ENDFORM.

For information, here's the result you would get with fixed data:

REPORT.
DATA: BEGIN OF lt_data OCCURS 0,
        carrierid TYPE s_carr_id,
        seats     TYPE STANDARD TABLE OF char10 WITH EMPTY KEY,
      END OF lt_data.

lt_data[] = VALUE #(
                   ( carrierid = '1' seats = VALUE #( ( '56' ) ( '67' ) ) )
                   ( carrierid = '2' seats = VALUE #( ( '32' ) ( '89' ) ) )
                 ).
DATA(json_xml) = VALUE xstring( ).
PERFORM convert_dobj_to_json_xml USING 'DATA' lt_data[] CHANGING json_xml.

ASSERT cl_abap_codepage=>convert_from( json_xml )
    = '<object><array name="DATA">'
    && '<object><str name="CARRIERID">1</str><array name="SEATS"><str>56</str><str>67</str></array></object>'
    && '<object><str name="CARRIERID">2</str><array name="SEATS"><str>32</str><str>89</str></array></object>'
    && '</array></object>'.

DATA(writer) = cl_sxml_string_writer=>create( type = if_sxml=>co_xt_json ).
CALL TRANSFORMATION id SOURCE XML json_xml RESULT XML writer.
DATA(json) = writer->get_output( ).
ASSERT cl_abap_codepage=>convert_from( json )
    = '{"DATA":[{"CARRIERID":"1","SEATS":["56","67"]},{"CARRIERID":"2","SEATS":["32","89"]}]}'.

johnm16
Participant

Hi Sandra,

that's a really neat piece of code, and it highlighted a difference between my ST and the resulting JSON-XML. Here's the result of your code:

<array name="ITEM_LIST">
	<object>
		<str name="ITEM_SERIAL_NUMBER">123 </str>
And here's my original ST for comparison:
      <array>
        <tt:loop ref="einvoice_request.item_list">
          <object>
            <num name="item_serial_number">
I thought maybe the clue was in the levels of indent: the JSON-XML only has two (array, object), whereas my ST has three (array, loop, object).I had already tried removing the <object> element, and that didn't work. Removing the <tt:loop> element prevents it from activating. So finally, I removed the <array> element. Which seems crazy, because every other ST I can find in SAP uses <array> for nested tables. Still, no matter. I changed the ST to look like this:
      <tt:loop ref="einvoice_request.item_list">
        <object name="item_list">
          <num name="item_serial_number">
            <tt:value ref="$ref.item_serial_number"/>
And the transformation ran without any errors. However, the item_list element isn't treated as an array, only as a single iteration - I was hoping for [ { :
	},
	"item_list": {
		"item_serial_number": 123,
So I substituted 'array' for 'object' like this:
      <tt:loop ref="einvoice_request.item_list">
        <array name="item_list">
          <num name="item_serial_number">
Now the ST throws an error: "Executing the 'OpenAttribute' operation leads to an invalid XML document". The error is triggered when executing the <num name="item_serial_number"> element. I tried changing the 'num' to 'str', but I get the same error. If I swapped around the <tt:loop> and <array>, I got the same error.So I went back to my "3 level" approach, but this time I reversed the <loop and <array elements:
      <tt:loop ref=".einvoice_request.item_list">
        <array name="item_list">
          <object>
            <str name="item_serial_number">
              <tt:value ref="$ref.item_serial_number"/>
And at last, it works. Here's the result:
	},
	"item_list": [
		{
			"item_serial_number": "000010",
So thank you Sandra for all your help: it was really appreciated, and it set me on the right track, plus I learned some really useful (and clever) ABAP. And it's odd that the DEMO_ST_JSON_TABLE ST I mentioned earlier has the <array> and <tt:loop ref> elements the opposite way round, but it didn't work for me.I hope this posting will be useful for some other lost soul.Best regards,John

0 Kudos

Thanks for the feedback.

I don't understand how you can say that <tt:loop> before <array> can work. If you have 2 items in the array/internal table, although I can't generalize, your code would fail (it depends on the exact context).

The normal order is:

<array ...
<tt:loop ...

If you have a "table of table", you might have this:

<array ...
<tt:loop ...
<array ...
<tt:loop ...

johnm16
Participant
0 Kudos

Hi Sandra,

my ST (above) was the only way I found to avoid an exception when calling the transformation. And the JSON output looked fine, but my source data only contained 1 row in the nested table...

After your last comment, I added a second row to the nested table (in the debugger), just to re-check the output.

And as you predicted, the output was incorrect. It produced 2 serialised entries for the item list table, but expressed (in the JSON string) as 2 separate tables, each with 1 row.

So, back to the beginning... this was my original ST code (at the beginning, I also tried with the first data element like <num name ="item_serial_number">)

      <array>
<tt:loop ref=".einvoice_request.item_list">
<object>
<str name="item_serial_number">
<tt:value ref="$ref.item_serial_number"/>
</str>

Every time, it triggered exception cx_st_match_element or exception cx_transformation_error after the <object> element.

So I reversed nearly all my changes, but retained the name of the array:

      <array name="item_list">
<tt:loop ref=".einvoice_request.item_list">
<object>
<str name="item_serial_number">
<tt:value ref="$ref.item_serial_number"/>
</str>
And this version works (!). The output is correct, at last. But the only difference is that the array has a name, so I'm still a bit surprised.Thanks again for all your help - I couldn't have done it without your advice.Best regards,John