1 2 3 48 Previous Next

ABAP Development

706 Posts

Hi,


Recently there were some questions about transport information functions.


The program attached Y_R_EITAN_TEST_26_02 is my attempt of using some of the transport functions .

 

Functions:

TR_READ_GLOBAL_INFO_OF_REQUEST
TR_LOG_OVERVIEW_REQUEST
STRF_OPEN_PROT
TRINT_READ_LOG
TRINT_DISPLAY_LOG
TRINT_READ_REQUEST_HEADER

 

The program goes through table E070 based on user selection .

For each E070 row the program call function TR_READ_GLOBAL_INFO_OF_REQUEST , The output from the function is used to create the final output table.


The final output table is presented using cl_salv_table .


Transport Logs and Action log is availble by hotspot .


Screens:

 

screenshot_01.png

 

screenshot_02.png


Enjoy.


Eitan.

 

 

 

 

 

 


Regards.

Hi Guys,

  

while working with own database tables (Z* tables) the SAP offers us a simple tool to add data or edit these tables. I am talking about the table maintenance views, that you can call via the transaction SM30. The problem is that only one user can edit such a table at once. For my application this was unsatisfying because several users worldwide couldn't consider waiting until one has finished his changings. I sersched the SCN and found serveral threads handling this issue. After implementing it myself i wanted to share my knowledge with you and carry the information together.


So at first you need the database table and you have to generate a table maintenance view.  While Generating this View choose two step maintenance type, because we want a list where several entries are not editable. In the overview screen no entry is editable in general, in detail screen it gets editable when opened with changing.

 

When you enter the table maintenance view via SM30 a table level lock is set. This lock has to be removed. The most easiest way to do that is a report that deletes the lock and calls the maintenance view. In detail this is done by reading all system locks. After that we have to delete the relevant lock by calling the function module  ENQUE_DELETE. Now you can call the table maintenance view via the function module   VIEW_MAINTENANCE_CALL.  It is recommendable to add a transaction to this report because it has to be processed to delete the locks. Otherwise if someone opens table maintenance view via SM30 this will not work any more and the lock is set again.

 

Code Example:

 

REPORT ztest.

 

DATA:

BEGIN OF seltab OCCURS 1.        

 

        INCLUDE STRUCTURE vimsellist.

DATA: END OF seltab,

 

BEGIN OF excl_cua_funct OCCURS 1.  

 

        INCLUDE STRUCTURE vimexclfun.

DATA: END OF excl_cua_funct.

 

DATA: lt_enq_del       TYPE STANDARD TABLE OF seqg3,

          lt_enq_read      TYPE STANDARD TABLE OF seqg7,

          lw_enq_read     TYPE seqg7,

          lw_enq_del       TYPE seqg3,

          lv_subrc           TYPE sy-subrc.

 

*Read all locks in system

 

CALL FUNCTION 'ENQUE_READ2'

  EXPORTING

    gclient = sy-mandt

    gname = ' '

    guname = '*'

  TABLES

    enq = lt_enq_read.

 

*We will search entry for table level lock for our table

LOOP AT lt_enq_read INTO lw_enq_read WHERE gname EQ 'RSTABLE'

AND  garg CS 'Z_OURTABLE.

 

  MOVE-CORRESPONDING lw_enq_read TO lw_enq_del.

  APPEND lw_enq_del TO lt_enq_del.

  1. ENDLOOP.

 

*Delete lock entry for our table

CALL FUNCTION 'ENQUE_DELETE'

  EXPORTING

    check_upd_requests = 1

  IMPORTING

    subrc              = lv_subrc

  TABLES

    enq                = lt_enq_del.

 

CALL FUNCTION 'VIEW_MAINTENANCE_CALL'

  EXPORTING

    action                               = 'U'

*   CORR_NUMBER                          = '          '

*   GENERATE_MAINT_TOOL_IF_MISSING       = ' '

*   SHOW_SELECTION_POPUP                 = ' '

    view_name                            =  'Z_OURTABLE'.

        

 

Now every entry we are editing has to be locked for other user. To achieve that we need a lock object configured for our table Z_OURTABLE. Everytime we enter the detail screen we check if this entry locked and if so, we set all fields not editable. For that the Screen logic of the dynpro has to be modified. You can add a module that calls the function module created by your locking object. Be careful , if you change your database table, the screens have to be generated new and also the PBO Module has to be added again.

 

Code example:

 

MODULE change_locking OUTPUT.

 

 

 

  CALL FUNCTION 'ENQUEUE_EZOURTABLELOCKOBJECT

 

     EXPORTING

      kunnr = zourtable-kunnr

     EXCEPTIONS

      foreign_lock   = 1

      system_failure = 2

      OTHERS         = 3.

  IF sy-subrc <> 0.

message 'Data locked by another user!' type 'S'.

* row is locked..

    LOOP AT SCREEN.

      screen-input = 0.

      MODIFY SCREEN.

    ENDLOOP.

  ENDIF.

  1. ENDMODULE. 

 

Everytime a user opens a single record this is locked by the locking object. If any user tries to open the same record all fields are enhanced grey.

 

 

I hope this is useful to someone.

 

kind regards Tobias

Hi all,

 

Today's blog is about something I’m thinking quite a while how to create it.

 

We, as ABAP-Developer , didn't have such a problem or better, not in the same way a lot of others programmers had to face it.

 

What I want to say, is when you have a look at a SAP-Transaction everybody of us know normally how to navigate. There are the well known Navigationbar, Execute and all the Standard-Buttons above an ALV.

I think, you know what I’m talking about. So what is this blog for? I recognize that developing in ABAP make a huge change at the moment (ok, it is more a process and yes it's more a general thing). That’s why we face problems, we didn't know before and one is the Design-Styleguide.

 

I just want to collect some facts why all of us should have a Design-styleguide as an additional document to the coding-guidelines.

 

Everybody of us know the Coding-Guidelines and I’m pretty sure, I will not find one person around here saying it is not necessary to have a document like this. Of course, some are a bit over the top, but all in all it is a great instrument to lead all people into the same direction.

 

Now, when I would say that a Design-Styleguide is also necessary a lot people saying to me, that it’s not important.

 

Why do I get this reaction? I mean, of course years before, when just the dynpro was developed by SAP you just could choose between a hand full controls and a predefined icons to create your screen. That was awesome, because all of the programs had the same look and feel. I think that was one of the success-factors of SAP. Keep it simple and similar might be the thinking behind.

 

But developing has changed and of course the elements we can use today are a lot more. I don't know where here on SCN I have read the sentence “A 23 year old employee don't want to use a 20 year old software” and that is so true. Additional to that, I would say that also the rules of developing has changed and so today also we, the SAP developers may need more than just a coding-guidelines.

 

Now, how to start…what to do? This is how I want to start and hey, miss the counting in my blog? Me too

 

1st point Use existing style guides

 

This is a very important point. Before to start with the own one work through other styleguides. All the companies out there especially in the mobile sector have one and I’m pretty sure SAP also got one, so if anybody knows where it is located, I would love to have a link in the comments

 

2nd point Keep it short and simple

 

I read a lot of different blogs about this topic and I decided for me, that a good styleguide should not have more than 4 to 6 pages. In my opinion I’m pretty sure, that a lot of people saying that it is not necessary (as mentioned in the beginning) and out of that I’m pretty sure that it is a absolutely success factor that the guide is as simple as possible. Don't add tons of links, keep it simple, we all are creative people and I if something is not clear, make it easy to ask.

 

3rd point Example-package

 

Provide a package of examples that leads through the different designs. That’s a way you can make similar feeling and by the way after investing some money you can save it afterwards with a multiplier

 

 

 

 

4th point Easier to test (or 3.1)

 

What?  A styleguide should make my programs easier to test? Yes, it does. People will feel comfortable with the handling and so it will be easier to hand over some testing to another. Also keep in mind that the other worlds (UI5 / River / POWL) swap on our desk and it is not just a trend. It’s the future.

 

5th point Easier to develop and to prepare (or 3.2)

 

A styleguide also helps the responsible persons to prepare the documents for developing. All people in the chain got a similar expectation of the program from the first sentence in the whole process. This will take time in the beginning, but I’m pretty sure in the end it will result in lower bugs and lower maintenance cost on each side.

 

6th point Shared vocabulary (or 3.3)

 

This is a point, I humble sometimes over. I see 3 different programs with similar (custom)data in it and there are also three different data-elements used. I know, this won't be fixed in summary by an styleguide as well, but I’m pretty sure, that a active styleguide in an company leads to more sensitive searching before creating new elements.

 

7th point Invest time

 

That isn't just a phrase here. I’m pretty sure that it will take more than two meetings to complete the process. I think it needs a lot of time to walk through the company and ask a lot of people how they define it and collect just facts. Afterwards pin all facts at a whiteboard and go on to point number eight. Of course, it also will take a lot of time to create the sample packages (Webdynpro, BSP, UI5), but this is also a nice doing to get in touch with all the things.

 

8th point Onboard young employees

This document should be created by the young employees. They may add their points without having the company glasses on. No need to argue, but I think the “older” employees should have the second check on the document, so everybody has the chance to add something but in this case all voices are at the same level and if there are arguments, it will be early enough to add these to the document.

 

9th point Catch the feedback

 

In my opinion I think it need a period to have an “beta-test” on the document. After the examples (or during) are created it should have a group of people to try the handling, if possible people without any experience of programming. They will deliver clear voices if they think all the different examples give the feeling to be always on the same highway. I think you know what I mean.

 

10th point Love it or leave it

 

 

If you have worked through the other 9 points and ended here I just have to add, that I do not know anything other to add.  I know that this will end in a lot of discussions and it might not be easy to deliver such document. So I think you have to love the idea behind and see the necessity. And I hope I delivered that point with this blog

 

 

Conclusion:

 

Have a look around in your company and I’m pretty sure there are always people trying to put things in a row, let documents look the same and try to publish the brand in the same way. So this is exact the same what a styleguide tries. All we have to learn is that a styleguide today is normal and when I talk to people with other software in the back, it is usually a must have, except if I talk to SAP-guys.

 

I think it is time to leave the leaf or do I see things wrong and most of you got one available?

 

(Comic comes from here: xkcd: Donald Knuth http://xkcd.com/163/)

 

Thank you for reading to the end. Feel free to add something I missed or just to leave a comment.

 

Cheers

Florian

This article probably isn't required, as most of us here are already ABAP developers, but, I thought it would be good experience to share my thoughts what it actually felt like to switch to ABAP.

 

Unlike Java or C++ , ABAP isn't a language for development of applications on Windows or any other operating system for that matter. The purpose it actually serves  is to cater to the needs of Industries who are using SAP. So the major difference between working  ABAP and Java/C++ is you have to utilize most of your talents to study the functions already provided by SAP team, as generally it optimizes the program whereas it generally is vice-versa on other language as it increases dependency on Platform.

 

ABAP can be considered a more specific language in terms of application. By this I mean that while in other languages you have freedom to present end result of your program but in ABAP you have to optimally utilize SAP GUI to present results.

 

When working on Java I was really sick of long syntax's . To be honest it really felt more like article writing rather than coding(and by now u might  have  figured out how good I'm in article writing ). I would clearly like to state here I am not judging the capabilities of any programming language, it's just my perspective on things. When I switched from Java to ABAP , firstly I thought why do companies even require ABAP coders at first place(though I clearly understand now 'why').

The simplicity it offered at the beginning made me feel like as if they had designed a function for each and everything you wanted to do, thus rendering you useless again.

 

So it can be concluded that if you are good in any other Programming language , don't get scared to switch to ABAP. It simply is the simplest language you can find. So far, while working on ABAP , I felt like as if ABAP was designed to comfort the Developers (I really mean that). Coding on ABAP really is a piece of cake(some may disagree). You just have to understand the business scenarios a bit better than your fellow counterparts working on other technologies.

I am really glad that I made the switch to ABAP when I had chance.

I had an interesting last week and what looked easy at the outset did my head in for quite a while. I tried various methods and the below approach was able to give me a satisfactory solution.

 

Let's have a look at the high level requirement.

 

 

- Copy a standard SAP transaction and customise it . Below picture describes the requirement

Screen Shot 2014-08-16 at 7.28.17 pm.png

 

The transaction is started with only few fields of the complete selection screen as the selection screen has too many fields and may confuse the users.

 

 

2.PNG

 

The users need to navigate back and forth between different modes of output screen. At the first display of output screen ( let's call them as levels - so the output screen is at level 0 when initially displayed and if called again goes to level 1 and so on . Similarly when the user comes back from a higher level of screen, the level will decrease : from 1 to 0 ). And of course when the program navigates back from level 0 of selection screen, it should display the selection screen.

 

 

I prototyped using a simple program using flight model.

 

 

- Selection Screen : Contains all fields.

All fields.PNG

 

However, the transaction is always run with a variant which hides the last field.

 

Selection Screen.PNG

 

- Let's test with some data.

 

 

Selection Test.PNG

 

We get the level 0 output screen.

 

Level 0.PNG

 

Now click on filter ( search icon on top right )

 

Filter.PNG

 

and we get level 1 screen.

 

Level 1.PNG

 

Looks good so far. Now, let's try going back - going back to level 0 gives the screen as anticipated. However, when we go back and see that the selection screen parameters have gone back. The selection screen has gone blank !

 

Selection Screen.PNG

 

 

Let's see what's going on.

 

As we need to keep track of different levels of screen, if the level of screen is greater than 0.

.......

ELSEIF sy-ucomm = 'EXIT'.

    IF gv_list_level > 0.

      gv_list_level = gv_list_level - 1.

      gt_flight[] = gt_master_flight[].

      CALL SCREEN 100.

    ENDIF.

 

 

When we want to go back to selection screen from screen at level 0, we use below:

 

SUBMIT zsubmit_flight

            WITH report EQ 'ZTESTFLIGHT'

            WITH variant = 'ZFLIGHT_VAR'

            WITH SELECTION-TABLE gt_seltab .


zsubmit_flight is a standard SAP report used by the report and can't be changed by us.


SUBMIT (REPORT) WITH VARIANT  = VARIANT

                    USING SELECTION-SET VARIANT

                    VIA SELECTION-SCREEN

 

Workaround:

1) Store selected values by call of RS_REFRESH_FROM_SELECTOPTIONS 

 

2) Export the selection table before doing a program restart.

EXPORT gt_seltab TO MEMORY ID gc_sel_mem.

 

3)  Retrieve the selection table AT SELECTION-SCREEN OUTPUT.

 

RS_VARIANT_CONTENTS gives the parameters and select-options actually visible in the variant.

 

IMPORT gt_seltab FROM MEMORY ID gc_sel_mem.

 

  IF NOT gt_seltab[] IS INITIAL.

 

    CALL FUNCTION 'RS_VARIANT_CONTENTS'

      EXPORTING

        report              = 'ZTESTFLIGHT'

        variant              = 'ZFLIGHT_VAR'

      TABLES

        l_params            = lt_params

        l_selop              = lt_selops

        valutab              = lt_value

      EXCEPTIONS

        variant_non_existent = 1

        variant_obsolete    = 2

        OTHERS              = 3.

    IF sy-subrc <> 0.

clear: lt_value,

          lt_selops,

          lt_value.

    ENDIF.

 

* Update parameters values

 

    LOOP AT lt_params INTO lw_param.

      READ TABLE gt_seltab REFERENCE INTO lo_values WITH KEY selname = lw_param-name.

      IF sy-subrc = 0.

        lv_attr = lo_values->selname.

        TRANSLATE lv_attr TO UPPER CASE.

        ASSIGN (lv_attr) TO <fs_attr_val>.

        <fs_attr_val> = lo_values->low.

      ENDIF.

    ENDLOOP.

 

* Update select-option values

 

    LOOP AT lt_selops INTO lw_param.

      READ TABLE gt_seltab REFERENCE INTO lo_values WITH KEY selname = lw_param-name.

      IF sy-subrc = 0.

 

        CONCATENATE lo_values->selname 'SIGN' INTO lv_attr SEPARATED BY '-'.

        TRANSLATE lv_attr TO UPPER CASE.

        ASSIGN (lv_attr) TO <fs_attr_sign>.

        <fs_attr_sign> = lo_values->sign.

 

 

        CONCATENATE lo_values->selname 'OPTION' INTO lv_attr SEPARATED BY '-'.

        TRANSLATE lv_attr TO UPPER CASE.

        ASSIGN (lv_attr) TO <fs_attr_option>.

        <fs_attr_option> = lo_values->option.

 

        CONCATENATE lo_values->selname 'LOW' INTO lv_attr SEPARATED BY '-'.

        TRANSLATE lv_attr TO UPPER CASE.

        ASSIGN (lv_attr) TO <fs_attr_low>.

        <fs_attr_low> = lo_values->low.

 

        CONCATENATE lo_values->selname 'HIGH' INTO lv_attr SEPARATED BY '-'.

        TRANSLATE lv_attr TO UPPER CASE.

        ASSIGN (lv_attr) TO <fs_attr_high>.

        <fs_attr_high> = lo_values->high.

 

        lv_attr = lo_values->selname.

        TRANSLATE lv_attr TO UPPER CASE.

        ASSIGN (lv_attr) TO <fs_attr_main>.

 

        CONCATENATE lv_attr '[]' INTO lv_attr_tab.

        ASSIGN (lv_attr_tab) TO <fs_attr_tab>.

 

        IF lo_values->low IS NOT INITIAL OR lo_values->high IS NOT INITIAL.

          REFRESH <fs_attr_tab>.

          APPEND <fs_attr_main> TO <fs_attr_tab>.

        ENDIF.

      ENDIF.

    ENDLOOP.

 

  ENDIF.

 

REFRESH gt_seltab.

   EXPORT gt_seltab TO MEMORY ID gc_sel_mem.

 

- Create a transaction 'ZFLIGHT' with program ZTESTFLIGHT , variant ZFLIGHT_VAR.

 

 

The code can be referred here:

 

ZSUBMIT_FLIGHT

https://github.com/viksingh/ABAP_Demo/blob/master/ZSUBMIT_FLIGHT

 

Program ZTESTFLIGHT with issues:

https://github.com/viksingh/ABAP_Demo/blob/master/ZTESTFLIGHT_1

 

Program  ZTESTFLIGHT with corrections:

ABAP_Demo/ZTESTFLIGHT_2 at master · viksingh/ABAP_Demo · GitHub

 

The key here is function module RS_VARIANT_CONTENTS and the dynamic update of selection screen after restart of a transaction.

As with most OO related discussion (i.eWhy object oriented? Import parameters), the arguments get interesting really quick. In that blog, a fellow SCN user described her dislike for OO, and how it relates to procedural, as the following:

The funny thing is that this aspect I dislike most about FM's is their greatest parallel to OO concepts. Basically you can say that a function group is something similar to an object, with the FM's being its methods. Fortunately, most of the time the FM's are independent and provide a well-defined functionality that only depends on the parameters you are providing at run-time.

The point the user is making is that class attributes are a lot like global variables, which are more annoying to debug since it's harder to find out where they were actually set. I really get where he is coming from. As always, it's a matter of design and following OOP guidelines.

 

What you should do:

  • Public atributes should be set in the constructor;
  • Private attributes should be set in specific getter/setter methods (or the constructor).

 

What you shouldn't do:

  • Change an attribute directly outside of the constructor and getter/setter methods.
  • Create attributes for temporary variables that are not related to the object itself;
  • Create attributes with obscure naming like WERKS, use Plant instead. Use _ if you have to, the attribute name should always be self descriptive.

 

The rule of thumb is: If the attribute is not worthy of public or a getter/setter then it is temporary method variable and shouldn't be an attribute at all.


This explains why they aren't so bad if used well, but doesn't explain why you should use them. I think the most immediate way to summarize their power (in the context of SAP WM, and TO confirmation) is this:


lo_to->confirm( ).


Why is this powerful? Because import parameters are messy, and the more "the merrier" (joking). Translation, the more parameters, the more mistakes you can make and the more information you need to use them correctly.

This is the exact opposite of the FM with zero state, where all information must be provided by IMPORTING parameters. Lets picture the scenario where you need to confirm a TO (from SAP WM) without using OO attributes. SAP provides a FM for that:


    call function 'L_TO_CONFIRM'
      exporting
        i_lgnum                        = lv_lgnum
        i_tanum                        = lv_tanum
        i_squit                           = lv_squit
        i_komim                        = lv_komim
        i_tbeli                            = lv_tbeli
        i_update_task                  = 'X'
      tables
        t_ltap_conf                    = lt_ltap_conf[]
        t_ltap_conf_hu              = lt_ltap_hu[]




 

This is not an extreme example there are way more complicated FM interfaces. There are two main problems with this:

  • Filling lt_ltap_conf and lt_ltap_hu is far from trivial;
  • The FM call is completely coupled to the calling program (more on that in an instant).

 

I've used this function in RF programs which are a pain (if you ever touched one, you will know it...), and have persistency requirements: a warehouse worker can't lose his work if Wi-Fi goes down, so every item picked gets saved to the database. Now let's assume that an error is thrown at TO confirmation, and you need to find out why.

 

If you used the traditional procedural way, you would need to run the calling RF program, get to the place where you make the TO confirmation and debug (with the extra annoyance that RF is system-guided, so getting that specific TO means superuser specific code). Either that, or you could SE37 the FM and fill by hand all the parameters of the FM (remember the counterexample is a FM with not state).

 

With OO, it's as simple as SE24, create instance, insert number of TO (and warehouse number), and then press "CONFIRM". Two parameters and you are ready to debug. I cannot stress how important this decoupling becomes when you are debugging errors or making unit tests, this separation between caller and callee means you can focus on particular behaviors.

 

This is a specific situation with persistence where OO gives you a really advantage. I've found over the years that dealing with persistence is one of the greater advantages of OO since most of the data is already available. In a more general situation the CONFIRM call would be preceded by calls to ADD_ITEM, but even that is simpler than manually filling the lt_ltap_conf with absolutely no rules (check Why object oriented? Import parameters for my argumentation on that subject).

 

All this could be made using Function Groups, since this blog more about Object Oriented Programming then Classes/Methods.

HI mates!

 

Actually this is my first blog in my 5+ years SAP career so don't judge me strictly.

 

So I have chosen really intersting topic: probably something that everyone thought about. I'm sure someone even tried to implement this feature by own efforts.

 

This is a proposal search feature. This is so obvious that if we type the beginning of the search term or even mask we want to see the results instantly. But not in SAP GUI. All the times we had to press F4 or at least click at search button by mouse.

 

But this morning while creating a new search help I suddenly noticed an  interesting new block in SE11 transaction.

 

pic1.PNG

 

According to F4 search help I found the following note:

 

http://service.sap.com/sap/support/notes/1861491

 

The requirements for that feature is quite high: These functions are available as of SAP NetWeaver for ABAP 7.4 SP03 and SAP GUI for Windows 7.30 patch level 5 or higher. But happily we have SP04 so I decided to go further and to try it.

 

I have selected search helps from DD30L table by AUTOSUGGEST = 'X' field. Hopefully there were results and I have chosen SDSH_SPFLI as an example to try.

From the where-used list of the following search help i found SDSH_S_SPFLI structure and created a tiny program following the instructions from the mentioned above note:

 

report ztest_autosuggest.
parameters:
  p_carrid TYPE SDSH_S_SPFLI-carrier_id.
at selection-screen output.
  loop at screen.
    if screen-input eq 1.
      cl_dsh_dynpro_properties=>enable_type_ahead(
        exporting
          fields    = value #( ( |{ screen-name }| ) )
          overwrite = abap_false ).
    endif.
  endloop.

The result on the screen made me really enjoyed. Now we have it as a standard feature:

 

pic2.png

 

As I understood only since SP06 this feature is going to be activated automatically. So this cl_dsh_dynpro_properties should be called manually in lower versions.

 

Also I would mention that it's possible only search by code. The full text fuzzy search is available only for special databases like SAP HANA as well,

But in anyway that's something interesting!

 

So thanks for reading!

 

Enjoy!


Just would like to share with you how I struggle with a bug recently. These days I am supporting a customer project which would go live very soon. We find a severe performance problem in a scenario. After fighting it for sometime, we locate the possible cause into the FM call below.


clipboard1.png

This is a RFC call from CRM to ERP system with expectation that at maximum 15 records are returned.

 

Much to our surprise, far more than 15 records are returned, finally leads to the performance issue.

clipboard2.png

Then I go to the responsible colleague for FM SLS_LORD_GET_VALUES_SAREA saying "Hey man, there is something wrong with the max entry filtering logic in your FM. Customer will go live soon and could you please help as soon as possible". My colleague soon replied to me "just checked from my side, this FM works pretty good".

 

Then I have to look into this issue once again. When debugging inside this FM, I found the importing parameter is not 15, but becomes a big number 3473457, so the max record filter logic absolutely does not work in such case.

clip_image002.jpg


I checked the signature of this FM, and found out we should pass into it with a integer, not a char ( '15' in this example ) .

clipboard4.png

Where does this magic number '3473457' come from

 

I write a small report to explore it. I deliberately pass char value ( from 1 to 15 ) to an importing parameter with INT type. 

 

DATA: lv_num_c TYPE char2.

START-OF-SELECTION.

DO 15 TIMES.

  lv_num_c = sy-index.

  TRY.

    CALL FUNCTION 'ZTEST'

      EXPORTING

         iv_in_rfc = abap_false

         iv_num = lv_num_c.

  CATCH cx_root INTO DATA(cx_root).

     WRITE: / cx_root->get_text( ).

     EXIT.

  ENDTRY.

ENDDO.

DO 15 TIMES.

  lv_num_c = sy-index.

  CALL FUNCTION 'ZTEST' DESTINATION 'NONE'

    EXPORTING

        iv_in_rfc = abap_true

        iv_num = lv_num_c.

ENDDO.

The FM ZTEST just insert what has passed in to a DB table:

 

 

FUNCTION ZTEST.

ls_rfc-in_rfc = iv_in_rfc.

ls_rfc-num = iv_num.

INSERT zrfc_Test FROM ls_rfc.

ENDFUNCTION.

 

 

Execute result:

 

The first normal FM call failed with exception:

 

The function call of ZTEST failed; a field may have been assigned to the parameter IV_NUM whose type is not compatible with this parameter

 

The second round RFC call does succeed, and check what has been written into the DB:

clipboard5.png

why we passed a '1' into the FM and it has been interpreted as 2097201??

 

in our report, we have passed '1' ( an variable with type CHAR2 ), whose Hex value is 31002000. And when it is passed into this remote-enabled FM, since the importing parameter is defined as INT in signature, the framework tries to interpret this Hex value back to an Integer, which is 2097201, since this Integer has the very Hex value 31002000.

clipboard6.png


This operation could simply be simulated to the lines below:

clipboard7.png

Summary

 

 

In normal function call, the ABAP runtime environment could help us identify some misuse on FM call, for example the non-compatible parameter type just as the first example in this blog. However when dealing with remote function call, such misuse would not lead to runtime exception, the application could keep running but not in accordance with what we expect, and sometimes it is difficult to identify in which step the deviation occurs. So we must strictly adhere to the development guideline to avoid such implicit conversion.

Jörg Wulf

Do you know your SE16N?

Posted by Jörg Wulf Aug 8, 2014

Probably, this does not exactly belong here, but i found no better place for it.

 

Several people i know(me included) like to use TA SE16N for a quick glance at table data or as a means of preselection e.g.  for personnel data.

Something like a query but without the hassle of building one.

 

It's really great, as long as you only need data from a single table AND all selection criteria are AND related. (Or so I thought)

 

One problem, I frequently ran into, is when you want to evaluate  a "nested" table. That is a table that has multiple  fields in its structure, basically for the same data, representing a limited table in maintenance view.

 

For example infotype tables in HR are often built like that and the problem is always, that you do not know, in which field (nnnn01, nnnn02, …) to look for a certain value.

 

Now quite I recently figured out, that SE16N can do that and I found it worth sharing.

 

Let's assume, you  need to know all employee, that have a certain date type (say 18) in infotype 41, in a specific time interval, but you have no idea, in which date type column (DAR01, DAR02,…)  it is to be found.

 

In the past, I would have run several selections, each one with a different DARxx targeted to my date type and then would have assembled the results in Excel.

 

This is how to do it now

 

 

  1. Call TA Se16N with table PA0041
  2. Fill in the first set of selection criteria (DAR01 / DAT01)
  3. Change to Technical View On (SHIFT+F11 or right-click for context menu)Technical View ON.png
  4. Select Multiple entry (Cntrl+F9 or right-click for context menu or More button in the top)
    Multiple Entry.png
    Youwill be rewarded with an additional, empty selection screen
  5. Fill in your selection criteria and then press Next Entry (F5 Or Right Arrow in the bottom)More First.png
    You get a new empty selection screen. Note the number shown in the top line, it will increase as you circle through your  value sets.More Second.png
  6. Repeat
  7. When you're through with typing in your values in every possible column, press F8 to get back to your starting selection.
    The only hint, that there are additional select criteria, is the more button in the top, now showing the filled Icon.

SE16n Final.png

 

The difference is  in the result. After executing  your selection, you will now receive all entries, that match either of your value sets. They are each linked by OR-relation.

Of course, the use of this feature is in no way limited to HR Infotype tables. It's just the most common use for me.

Wherever you need OR-related  sets of values for a SE16N Selection , this feature comes in handy.

 

Hope you'll enjoy it.







Hi,

 

Recently there was a question about sending a chart by mail from pavan kumar Mallipeddi

 

CL_GUI_CHART_ENGINE Graph As Email in Background

 

Using a hint from Jānis B I was able to generate a chart and to add it in the body of the message and also as attachment .

 

Program Y_R_EITAN_TEST_10_06 attached use cl_document_bcs and cl_igs_chart_engine .

 

cl_igs_chart_engine recieve XML documents as input so cl_ixml used .

 

In order to display the image in the body of the message cl_gbt_multirelated_service is used this allow the use of <img src="cid:<image name>"> tag .

 

FORM do_igs_chart is reponsible to return the image as xstring .

 

The program is also send a smart form as attachment. (A bonus.....)

 

screenshot_01.png

 

 

 

 

screenshot_02.png

 

screenshot_03.png

 

screenshot_04.png

 

 

2014/08/28 Increase the picture size to 600X800

 

attachment chart.PNG

When I joined SAP Labs India in 2007 , this book was gifted to me ( as well as every ABAP developer) in the team by the manager. Initially we thought what we would do with the book ( use it as weight for exercising was also an option given the volume of the book). So it found a corner space in the book shelf and rested their comfortably. But as I moved into typical developments,  I realized the importance of the book. The book is pretty expansive in content and would touch upon mostly everything if not in detailed. The emphasis of the book as the name suggests is on ABAP Objects and the authors have done a wonderful work in that regards. Before I go into details of the book please understand This is not a book its a bible. You have to read it every day to soak in the learning.


The book has following thirteen topics

  • Introduction
  • A practical introduction to ABAP
  • Basic Principles to ABAP
  • Classes and Objects
  • Basic ABAP Language Elements
  • Advanced Concepts in ABAP Objects
  • Classic ABAP- Events and Procedures
  • Error Handling
  • GUI Programming with ABAP
  • Working with Persistent Data
  • Dynamic Programming
  • External Interfaces
  • Testing and Analysis Tools


So if you see the content, you would agree with my previous statement that the content is expansive. If you are new to ABAP objects this book is a treatise on everything on ABAP objects and explains every concept in detail with examples. I have gone back and read this stuff so many times that some of the examples are always in my mind. Since I was into developing frameworks there were some topics such as Events in ABAP , Dynamic Programming  ( Field Symbols and Dynamic Method calls) , Testing and Analysis Tools , Shared Memory and XML were very beneficial to me. This book also has a very robust section on Error Handling which is often ignored by consultants. It is imperative that exceptions are caught in the UI and they should be raised in the frameworks and the context information be provided in exception objects.


Most of the us have learned ABAP through on job learning and in that case we know the practical usage but the theoretical knowledge of concepts is lagging. This book exposes us to those smaller things. Also sometimes in the project when we have to deal with topics such as RFCs and External Interfaces of which we have no clue. A formal knowledge on the subject would not prepare to do things on previous mentioned topics but give us a logical edge to think in the right direction.

 

If you are into any sort of ABAP development especially ABAP Objects , this book is a must have.


In the end I would summarize - this book has been my companion for more than 7 years and now when I flip the pages to read a topic which I don't use in my daily life , I am still amazed at the depth of knowledge of authors Horst Keller & Sascha Krüger and that spurs me to raise my standards.

Hi everybody, this is about how i got an SM30 maintenance tableview, to accept changes from multiple users at the same time.

It's my first ever blog, so don't expect too much.

 

Maybe I should start with the admittance that DDIC related development is not my field of experience – but nevertheless, I'd like to share the following, because a reasonably thorough search on SCN didn't bring any satisfying result.

 

Tableview V_T001B_COFI is a maintenace view that allows users, to assign timeslots for accepting posts, depending on various key values. The view features a subset of the table entries of table T001B.

 

V_T001B_COFI_Change View _Posting Periods_ Specify Time Intervals__ Overview.png

 

 

When the request was brought to me, that the maintenance of posting periods in tableview V_T001B_COFI should be enabled for multiple users at the same time, I started to search SCN for similar threads. That's where I came across this one.

 

The outcome however, was not satisfactory, since any number of users could have made concurrent changes, leaving the lastone to press 'SAVE'  as the winner.

 

So I started to reanalyse the problem.

 

I would need to create key specified locks.

 

My first impulse was, to create a new maintenance dialog, complete with an enqueueing object, specifically taylored to my needs – that is, locking entries keyspecific.

The maintenance dialog would then have to ensure, that no two users could maintain the same entries. Thatwas the easy part, as far as the maintenance in my own dialog would go.

 

In addition it was necessary, that any maintenance started by using the standard view (V_T001B_COFI) would still prevent any other user from editing any entry - whilst on the other hand, the key specific  lock would have to prevent the standard maintenance as well.

 

I knew that I could achieve that, by cleverly combining the use of the FMs to be generated by the enqueueing object, together with FM 'ENQUE_READ'. But still it felt clumsy.

 

So I started to reanalyse the problem.

 

I didn't need to have control over every single tableline to be locked seperately – a subset, in this case by tablefield BUKRS would be completely sufficient.

 

And there it was – the keyword subset. I remembered coming across in DDIC, when building a maintenance tableview.

 

So my new aproach started by copying tableview V_T001B_COFI to Z_T001B_COFI, with the only difference , setting the maintenance attribut (RDONLY) for viewfield BUKRS to 'S'.

Z_T001B_COFI-PERFORMANCE_ASSISTANT.png

Z_T001B_COFI_Dictionary_ Display View.png

Following that, I created a maintenance dialog without any fancy stuff.

 

When I started the tableview Z_T001B_COFI, a popup dialog prompted me to provide the variant(BUKRS) and the next thing was a maintenance screen with only those entries, matching the variant.

Z_T001B_COFI Change View _Posting Periods_ Specify Time Intervals__ Overview.png

A quick glance on the enqueued object showed the difference. Where the standard View had produced an entry, specified only by tablename, client and record type, there was now the variant as additional discriminator.

T001B_ENQUEUE ARGUMENT.png

A little bit of testing revealed, that all my preliminary enqueueing requirements where fully met. Without any additional enqueueing object or  modification, the request was fullfilled.

  Mission accomplished

 

Sometimes, it pays to think twice before starting to code and for me, it signalled that I should get myself a bit more into DDIC.

Quite a while ago I read Uncle Bob's Clean Code: A Handbook of Agile Software Craftsmanship and learned a little bit about FitNesse.

 

"It's a Collaboration Tool"

"It's a Test Tool"

"It's Open"

 

I'm not going to go in to why you should use FitNesse. You can read a bit about it at www.fitnesse.org. What I am going to talk about today is the work I've done on ABAPSlim and how you can go about setting up your own FitNesse wiki to run tests against SAP.

 

If you want to jump straight to the code you can head over to the ABAPSlim GitHub page.

 

Slim is the protocol that FitNesse uses to talk to your SUT (System Under Test). So far I'd say ABAPSlim is about 1/3rd done. It's easy to see this since I've copied FitNesse's standard set of tests for Slim and adapted them slightly for my implementation of ABAPSlim. When the following tests are all green then we will be able to use all the features of FitNesse.

 

Working tests.PNG

 

Right now, only the basic functionality is working. You can instantiate a class (zcl_fixture_division), you can call setter methods to set up data in your test fixture (numerator and denominator) and you can call getter methods and make assertions based on the result (quotient?). It's not shown here, but you can also pass in arguments to the constructor by adding columns in the first line where the class name is...

a test.PNG

 

The class zcl_fixture_division is included in the Saplink Nugget file on the ABAPSlim github page but here's what it looks like in case you're curious. Note that the columns without question marks (numerator, denominator) are setters so in the fixture class they need to be called setnumerator and setdenominator. The method with the question mark (quotient?) doesn't need the set in front of it but it does need to have a returning parameter.

CLASS zcl_fixture_division DEFINITION

PUBLIC

FINAL

CREATE PUBLIC .

 

PUBLIC SECTION.

   METHODS: setnumerator IMPORTING num TYPE S_PRICE,

                        setdenominator IMPORTING den TYPE S_PRICE,

                        quotient RETURNING VALUE(quotient) TYPE S_PRICE.

 

 

PRIVATE SECTION.

   DATA: _numerator TYPE S_PRICE,

                  _denominator TYPE S_PRICE.

ENDCLASS.

 

CLASS ZCL_FIXTURE_DIVISION IMPLEMENTATION.

  method QUOTIENT.

      quotient = _numerator / _denominator.

  endmethod.

 

  method SETDENOMINATOR.

      me->_denominator = den.

  endmethod.

 

  method SETNUMERATOR.

      me->_numerator = num.

  endmethod.

ENDCLASS.

 

So how can you get this set up and play with it yourself?

 

1. Head over to the ABAPSlim GitHub page and download everything.

2. Install the NUGG_ZSLIM.nugg Nugget using Saplink

3. Extract the Fitnesse folder to your C: drive

4. Edit the file NSP.jcoDestination and put in your own SAP system details and credentials

5. Rename the file NSP.jcoDestination and replace NSP with your SAP instance SID

6. Run fitnesse-standalone.jar (you can run it from a command line with "java -jar fitnesse-standalone.jar")

7. Browse to http://localhost and you should see the following:

 

fitnesse.PNG

 

8. The last step will be to go to the AbapSlim test suite (http://localhost/AbapSlim) and modify the Slim parameters:

abapslim.PNG

Click edit on the AbapSlim Page and edit the variables defined so they point to wherever you put the FitNesse folder and replace NSP at the end of the COMMAND_PATTERN with your SAP instance SID. Now you can run the test suite by clicking the Suite button.

 

When you create your own test suite you'll need to include the same variables in the suite page so that it knows to use ABAPSlim instead of the default Java Slim implementation:

!define TEST_SYSTEM {slim}

!define TEST_RUNNER {C:\Fitnesse\ABAPSlim.jar}

!path C:\Fitnesse\

!define COMMAND_PATTERN {java -Djava.library.path=C:\Fitnesse\ABAPSlim_lib\ -jar C:\Fitnesse\ABAPSlim.jar -sap NSP}

 

Thanks for reading and I hope you find this useful!

 

Lucas Tétreault

 

 

 

P.S.

If you're not using Windows on x64 64bit then you'll need to download the SAP JCO 3.0 for your OS + architecture from Service Marketplace and put the files in C:\Fitnesse\ABAPSlim_lib

The idea behind this trivial solution is the possibility to export text data from an SAP system into PowerPoint format using a given template. In my experience, multinational companies usually have a default PowerPoint template for presentations, which includes: the big company logo, strict rules for what should the header and the footer include, and so on. These are particularly important for status update presentations in different areas.

Although I had this requirement in the PPM sector, that is, Portfolio and Project Management, I chose to post this in ABAP development as it might be used in other areas as well.

template.png

As a prerequisite, this solution only works beginning with Office 2007 as it requires Office Open XML. Therefore, the iXML Library must be available on the SAP Application Server.

 

The following steps need to be performed in order to achieve a first test:

1. Create a demo template.

It is mandatory to set a custom property for each of the slides in the presentation, with:

name = "&&slide*&&"

type = "text"

value = "slide*"

(where * represents the slide number)

Advanced Properties.png

2. Create an ABAP/4 class with the following source-code or use the one attached bellow:

 

class ZCL_PPTX definition
  public
  create public .

public section.
*"* public components of class ZCL_PPTX
*"* do not include other source files here!!!

  constants MC_SCHEMA type STRING value 'http://schemas.openxmlformats.org/drawingml/2006/main'. "#EC NOTEXT

  methods CONSTRUCTOR
    importing
      !IM_V_CONTENT type XSTRING
    raising
      ZCX_PPTX .
  methods GENERATE
    importing
      !IM_T_TEXTS type ZXFILE_T_NAME_VALUE_PAIR
    returning
      value(RE_V_FILE) type XSTRING .
protected section.
*"* protected components of class ZCL_PPTX
*"* do not include other source files here!!!

  data MO_ZIP type ref to CL_ABAP_ZIP .
  data MO_IXML type ref to IF_IXML .
  data MO_IXML_DOCPROPS_CUSTOM type ref to IF_IXML_DOCUMENT .

  methods GET_FILE
    importing
      !IM_V_FILEPATH type STRING
    returning
      value(RE_O_DOCUMENT) type ref to IF_IXML_DOCUMENT .
  methods UPDATE_FILE
    importing
      !IM_V_FILEPATH type STRING
      !IM_O_DOCUMENT type ref to IF_IXML_DOCUMENT .
  methods ADD_FILE
    importing
      !IM_V_FILEPATH type STRING
      !IM_O_DOCUMENT type ref to IF_IXML_DOCUMENT .
  methods UPDATE_TEXTS
    importing
      !IM_T_TEXTS type ZXFILE_T_NAME_VALUE_PAIR
      !IM_O_IXML_NODE type ref to IF_IXML_NODE .
  methods GET_INDICATORS
    returning
      value(RE_T_INDICATORS) type ZXFILE_T_NAME_VALUE_PAIR .
private section.
*"* private components of class ZCL_PPTX
*"* do not include other source files here!!!
ENDCLASS.



CLASS ZCL_PPTX IMPLEMENTATION.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Protected Method ZCL_PPTX->ADD_FILE
* +-------------------------------------------------------------------------------------------------+
* | [--->] IM_V_FILEPATH                  TYPE        STRING
* | [--->] IM_O_DOCUMENT                  TYPE REF TO IF_IXML_DOCUMENT
* +--------------------------------------------------------------------------------------</SIGNATURE>
METHOD ADD_FILE.

  DATA :
    lo_ostream  TYPE REF TO if_ixml_ostream,
    lv_content  TYPE xstring.

* create output stream
  lo_ostream = mo_ixml->create_stream_factory( )->create_ostream_xstring( string = lv_content ).

* set encoding to UTF-8 (Unicode Transformation Format)
* 8-bit variable-width encoding maximizes compatibility with ASCII
  lo_ostream->set_encoding( encoding = mo_ixml->create_encoding( character_set = 'UTF-8' byte_order = 0 ) ).

* Set Pretty Print
  lo_ostream->set_pretty_print( abap_true ).

* render document
  mo_ixml->create_renderer( ostream = lo_ostream document = im_o_document )->render( ).

* add file
  mo_zip->add( name = im_v_filepath content = lv_content ).

ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method ZCL_PPTX->CONSTRUCTOR
* +-------------------------------------------------------------------------------------------------+
* | [--->] IM_V_CONTENT                  TYPE        XSTRING
* | [!CX!] ZCX_PPTX
* +--------------------------------------------------------------------------------------</SIGNATURE>
METHOD constructor.

  IF im_v_content IS INITIAL.
    TRY.
      RAISE EXCEPTION TYPE zcx_pptx.
    ENDTRY.
  ENDIF.

* get iXML library instance
  mo_ixml = cl_ixml=>create( ).

* load OpenXML document
  CREATE OBJECT mo_zip.
  mo_zip->load(
    EXPORTING
      zip            = im_v_content
    EXCEPTIONS
      zip_parse_error = 1
      OTHERS          = 2 ).

  IF NOT sy-subrc IS INITIAL.
    MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
              WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
  ENDIF.

  mo_ixml_docprops_custom = get_file( im_v_filepath = 'docProps/custom.xml' ).

ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method ZCL_PPTX->GENERATE
* +-------------------------------------------------------------------------------------------------+
* | [--->] IM_T_TEXTS                    TYPE        ZXFILE_T_NAME_VALUE_PAIR
* | [<-()] RE_V_FILE                      TYPE        XSTRING
* +--------------------------------------------------------------------------------------</SIGNATURE>
METHOD generate.

  CLEAR : re_v_file.

  DATA :
    lo_ixml_document      TYPE REF TO if_ixml_document,
    lo_ixml_document_rels TYPE REF TO if_ixml_document,
    lt_indicators        TYPE zxfile_t_name_value_pair,
    lt_files              TYPE cl_abap_zip=>t_files,
    lv_dummy              TYPE string,                      "#EC NEEDED
    lv_slide              TYPE string,
    lv_value              TYPE string,
    lv_filename          TYPE string,
    lv_filename_rels      TYPE string.

  lt_indicators[] = get_indicators( ).
  lt_files[]      = mo_zip->files[].

  FIELD-SYMBOLS : <fs_file> TYPE cl_abap_zip=>t_file.
  LOOP AT lt_files[] ASSIGNING <fs_file>
                    WHERE name CP 'ppt/slides/slide*.xml'.
    CLEAR:
      lv_dummy,
      lv_slide,
      lv_value,
      lv_filename,
      lv_filename_rels.

    SPLIT <fs_file>-name AT 'ppt/slides/' INTO lv_dummy lv_slide.
    SPLIT lv_slide      AT '.'          INTO lv_value lv_dummy.

    FIELD-SYMBOLS : <fs_indicator> TYPE zxfile_s_name_value_pair.
    READ TABLE lt_indicators[] ASSIGNING <fs_indicator>
                              WITH KEY value = lv_value.
    IF NOT sy-subrc IS INITIAL.
*    file not relevant, process next
      CONTINUE.
    ENDIF.

*  get .xml file
    lo_ixml_document = get_file( im_v_filepath = <fs_file>-name ).

*  get .rels file
    CONCATENATE 'ppt/slides/_rels/' lv_value '.xml.rels' INTO lv_filename_rels.
    lo_ixml_document_rels = get_file( im_v_filepath = lv_filename_rels ).

*  check indicators
    IF NOT <fs_indicator>-name IS INITIAL.
      update_texts( EXPORTING im_t_texts    = im_t_texts[]
                              im_o_ixml_node = lo_ixml_document ).

    ENDIF.

*  trigger update
    lv_filename = <fs_file>-name.
    update_file( im_v_filepath = lv_filename      im_o_document = lo_ixml_document ).
    update_file( im_v_filepath = lv_filename_rels im_o_document = lo_ixml_document_rels ).
  ENDLOOP.

  re_v_file = mo_zip->save( ).

ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Protected Method ZCL_PPTX->GET_FILE
* +-------------------------------------------------------------------------------------------------+
* | [--->] IM_V_FILEPATH                  TYPE        STRING
* | [<-()] RE_O_DOCUMENT                  TYPE REF TO IF_IXML_DOCUMENT
* +--------------------------------------------------------------------------------------</SIGNATURE>
METHOD get_file.

  DATA :
    lo_stream_factory TYPE REF TO if_ixml_stream_factory,
    lo_istream        TYPE REF TO if_ixml_istream,
    lv_content        TYPE xstring.

  mo_zip->get( EXPORTING  name                    = im_v_filepath
              IMPORTING  content                = lv_content
              EXCEPTIONS zip_index_error        = 1
                          zip_decompression_error = 2
                          OTHERS                  = 3 ).

  IF NOT sy-subrc IS INITIAL.
    RETURN.
  ENDIF.

* create the document
  re_o_document = mo_ixml->create_document( ).

* create the stream factory
  lo_stream_factory = mo_ixml->create_stream_factory( ).

* create the input stream
  lo_istream = lo_stream_factory->create_istream_xstring( lv_content ).

* parse document
  IF NOT mo_ixml->create_parser( document      = re_o_document
                                istream        = lo_istream
                                stream_factory = lo_stream_factory )->parse( ) is INITIAL.
    CLEAR : re_o_document.
  ENDIF.

ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Protected Method ZCL_PPTX->GET_INDICATORS
* +-------------------------------------------------------------------------------------------------+
* | [<-()] RE_T_INDICATORS                TYPE        ZXFILE_T_NAME_VALUE_PAIR
* +--------------------------------------------------------------------------------------</SIGNATURE>
METHOD GET_INDICATORS.

  REFRESH : re_t_indicators[].

  DATA :
    lo_ixml_iterator  TYPE REF TO if_ixml_node_iterator,
    lo_ixml_element    TYPE REF TO if_ixml_element,
    ls_indicator      TYPE zxfile_s_name_value_pair.

* get the corresponding entries in the custom .xml to control the generation
  lo_ixml_iterator  = mo_ixml_docprops_custom->get_elements_by_tag_name( name = 'property' )->create_iterator( ).

* get the first element
  lo_ixml_element ?= lo_ixml_iterator->get_next( ).
  WHILE lo_ixml_element IS BOUND.
    CLEAR ls_indicator.
*  get name
    ls_indicator-name = condense( lo_ixml_element->get_attribute( name = 'name' ) ).

    IF ls_indicator-name CP '&&*&&'.
*    get value
      lo_ixml_element    = lo_ixml_element->find_from_name( name = 'lpwstr' namespace = 'vt' ).
      ls_indicator-value = condense( val = lo_ixml_element->get_value( ) ).

*    insert indicator
      INSERT ls_indicator INTO TABLE re_t_indicators[].
    ENDIF.

*  get next element
    lo_ixml_element ?= lo_ixml_iterator->get_next( ).
  ENDWHILE.

ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Protected Method ZCL_PPTX->UPDATE_FILE
* +-------------------------------------------------------------------------------------------------+
* | [--->] IM_V_FILEPATH                  TYPE        STRING
* | [--->] IM_O_DOCUMENT                  TYPE REF TO IF_IXML_DOCUMENT
* +--------------------------------------------------------------------------------------</SIGNATURE>
METHOD UPDATE_FILE.

  mo_zip->delete( EXPORTING  name            = im_v_filepath
                  EXCEPTIONS zip_index_error = 1
                            OTHERS          = 2 ).

  IF NOT sy-subrc IS INITIAL.
    MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
              WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
  ENDIF.

  IF im_o_document IS BOUND.
    add_file( im_v_filepath = im_v_filepath im_o_document = im_o_document ).
  ENDIF.

ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Protected Method ZCL_PPTX->UPDATE_TEXTS
* +-------------------------------------------------------------------------------------------------+
* | [--->] IM_T_TEXTS                    TYPE        ZXFILE_T_NAME_VALUE_PAIR
* | [--->] IM_O_IXML_NODE                TYPE REF TO IF_IXML_NODE
* +--------------------------------------------------------------------------------------</SIGNATURE>
METHOD UPDATE_TEXTS.

  DATA :
    lo_classdescr    TYPE REF TO cl_abap_classdescr,
    lo_exception    TYPE REF TO cx_sy_ref_is_initial,
    lo_ixml_texts    TYPE REF TO if_ixml_node_collection,
    lo_ixml_iterator TYPE REF TO if_ixml_node_iterator,
    lo_ixml_document TYPE REF TO if_ixml_document,
    lo_ixml_element  TYPE REF TO if_ixml_element,
    lo_ixml_node    TYPE REF TO if_ixml_node,
    lv_message      TYPE string,
    lv_text          TYPE string,
    lv_result        TYPE string.

  TRY.
*    determine all texts of the corresponding node
      lo_classdescr ?= cl_abap_classdescr=>describe_by_object_ref( im_o_ixml_node ).
      READ TABLE lo_classdescr->interfaces WITH KEY name = 'IF_IXML_DOCUMENT'
                                          TRANSPORTING NO FIELDS.
      IF sy-subrc IS INITIAL.
*      document
        lo_ixml_document ?= im_o_ixml_node.
        lo_ixml_texts    = lo_ixml_document->get_elements_by_tag_name_ns(
                              name = 't'
                              uri  = mc_schema ).

      ELSE.
        READ TABLE lo_classdescr->interfaces WITH KEY name = 'IF_IXML_ELEMENT'
                                            TRANSPORTING NO FIELDS.
        IF sy-subrc IS INITIAL.
*        element
          lo_ixml_element ?= im_o_ixml_node.
          lo_ixml_texts    = lo_ixml_element->get_elements_by_tag_name_ns(
                              name = 't'
                              uri  = mc_schema ).
        ELSE.
*        current object not supported
          RETURN.
        ENDIF.
      ENDIF.

*    get iterator
      lo_ixml_iterator = lo_ixml_texts->create_iterator( ).

*    get first node
      lo_ixml_node = lo_ixml_iterator->get_next( ).

      WHILE lo_ixml_node IS BOUND.
*      update slide
        lv_text = lo_ixml_node->get_value( ).

*      replace the corresponding text
        FIELD-SYMBOLS : <fs_text> TYPE zxfile_s_name_value_pair.
        LOOP AT im_t_texts[] ASSIGNING <fs_text>.
*        update component
          CONCATENATE '&&' <fs_text>-name '&&' INTO lv_result.
          REPLACE lv_result IN lv_text WITH <fs_text>-value.
        ENDLOOP.

*      set updated text
        lo_ixml_node->set_value( lv_text ).

*      get next node
        lo_ixml_node = lo_ixml_iterator->get_next( ).
      ENDWHILE.
    CATCH cx_sy_ref_is_initial INTO lo_exception.
      IF lo_exception->is_resumable EQ abap_false.
        lv_message = lo_exception->get_text( ).
        MESSAGE lv_message TYPE 'X'.
      ENDIF.
  ENDTRY.

ENDMETHOD.
ENDCLASS.

 

3. Create a demo report with the following source-code or use the one attached bellow:

 

REPORT zdemo_pptx.

DATA :
  gv_data TYPE xstring.

PARAMETERS :
  p_file TYPE localfile.

AT SELECTION-SCREEN ON VALUE-REQUEST FOR p_file.
  PERFORM open.

START-OF-SELECTION.
  PERFORM upload.
  PERFORM generate.
  PERFORM download.
END-OF-SELECTION.

FORM upload.
  DATA :
    lt_file      TYPE solix_tab,
    lv_filename  TYPE string,
    lv_filelength TYPE i.

  lv_filename = p_file.

  CALL METHOD cl_gui_frontend_services=>gui_upload
    EXPORTING
      filename                = lv_filename
      filetype                = 'BIN'
    IMPORTING
      filelength              = lv_filelength
    CHANGING
      data_tab                = lt_file
    EXCEPTIONS
      file_open_error        = 1
      file_read_error        = 2
      no_batch                = 3
      gui_refuse_filetransfer = 4
      invalid_type            = 5
      no_authority            = 6
      unknown_error          = 7
      bad_data_format        = 8
      header_not_allowed      = 9
      separator_not_allowed  = 10
      header_too_long        = 11
      unknown_dp_error        = 12
      access_denied          = 13
      dp_out_of_memory        = 14
      disk_full              = 15
      dp_timeout              = 16
      not_supported_by_gui    = 17
      error_no_gui            = 18
      OTHERS                  = 19.

  IF NOT sy-subrc IS INITIAL.
    MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
              WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
  ENDIF.

  CALL FUNCTION 'SCMS_BINARY_TO_XSTRING'
    EXPORTING
      input_length = lv_filelength
    IMPORTING
      buffer      = gv_data
    TABLES
      binary_tab  = lt_file
    EXCEPTIONS
      failed      = 1
      OTHERS      = 2.

  IF NOT sy-subrc IS INITIAL.
    MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
              WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
  ENDIF.
ENDFORM.

FORM generate.
  DATA :
    lo_pptx  TYPE REF TO zcl_pptx,
    lt_texts TYPE zxfile_t_name_value_pair,
    ls_text  TYPE zxfile_s_name_value_pair.

  TRY.
      CREATE OBJECT lo_pptx
        EXPORTING
          im_v_content = gv_data.
    CATCH zcx_pptx.
      MESSAGE text-001 TYPE 'E'.
  ENDTRY.

  ls_text-name  = 'TITLE'.
  ls_text-value = 'Automatically generated
PowerPoint'.
  APPEND ls_text TO lt_texts. CLEAR ls_text.

  ls_text-name  = '
SUBTITLE'.
  ls_text-value = '
using very little coding'.
  APPEND ls_text TO lt_texts. CLEAR ls_text.

  ls_text-name  = 'NAME'.
  ls_text-value = '
Your name (Ex. John Dr. Smith)'.
  APPEND ls_text TO lt_texts. CLEAR ls_text.

  ls_text-name  = 'DEPARTMENT'.
  ls_text-value = '
Your department name or abbreviation'.
  APPEND ls_text TO lt_texts. CLEAR ls_text.

  ls_text-name  = 'DATE'.
  ls_text-value =
sy-datum.
  APPEND ls_text TO lt_texts. CLEAR ls_text.


  CLEAR gv_data.
  gv_data = lo_pptx->generate( lt_texts ).
ENDFORM.

FORM download.
  DATA :
    lt_file      TYPE solix_tab,
    lv_filelength TYPE i,
    lv_filename  TYPE string,
    lv_fullpath  TYPE string,
    lv_path      TYPE string.

  CALL FUNCTION 'SCMS_XSTRING_TO_BINARY'
    EXPORTING
      buffer        = gv_data
    IMPORTING
      output_length = lv_filelength
    TABLES
      binary_tab    = lt_file.

  CALL METHOD cl_gui_frontend_services=>file_save_dialog
    CHANGING
      filename                  = lv_filename
      path                      = lv_path
      fullpath                  = lv_fullpath
    EXCEPTIONS
      cntl_error                = 1
      error_no_gui              = 2
      not_supported_by_gui      = 3
      invalid_default_file_name = 4
      OTHERS                    = 5.

  IF NOT sy-subrc IS INITIAL.
    MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
              WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
  ENDIF.

  TRANSLATE lv_fullpath TO UPPER CASE.
  IF lv_fullpath NS '.PPTX'.
    CONCATENATE lv_fullpath '.PPTX' INTO lv_fullpath.
  ENDIF.

  CALL METHOD cl_gui_frontend_services=>gui_download
    EXPORTING
      bin_filesize            = lv_filelength
      filename                = lv_fullpath
      filetype                = 'BIN'
    CHANGING
      data_tab                = lt_file
    EXCEPTIONS
      file_write_error        = 1
      no_batch                = 2
      gui_refuse_filetransfer = 3
      invalid_type            = 4
      no_authority            = 5
      unknown_error          = 6
      header_not_allowed      = 7
      separator_not_allowed  = 8
      filesize_not_allowed    = 9
      header_too_long        = 10
      dp_error_create        = 11
      dp_error_send          = 12
      dp_error_write          = 13
      unknown_dp_error        = 14
      access_denied          = 15
      dp_out_of_memory        = 16
      disk_full              = 17
      dp_timeout              = 18
      file_not_found          = 19
      dataprovider_exception  = 20
      control_flush_error    = 21
      not_supported_by_gui    = 22
      error_no_gui            = 23
      OTHERS                  = 24.

  IF NOT sy-subrc IS INITIAL.
    MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
              WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
  ENDIF.
ENDFORM.

FORM open.
  CALL FUNCTION 'F4_FILENAME'
    EXPORTING
      program_name  = syst-cprog
      dynpro_number = syst-dynnr
      field_name    = space
    IMPORTING
      file_name    = p_file.
ENDFORM.

In the future, based on new requirements, I plan to extend this class to also include tables, new slides, and images. But if you get ahead of me, please feel free to add your code on SCN and give me a hint!

 

Tudor

I'm not entirely sure if a similar solution exists; I've tried searching through blog posts in the ABAP Development space and couldn't find any match (although there are over 1000 results for "abap xml").

 

Basically, more out of boredom and willing to learn more about the capabilities of the iXML Library, I made an ABAP/4 class that can transform any data (simple data, structure, table type) at any depth into XML format and vice versa. Even though, bringing XML to ABAP/4 only matches elements with the same name, ignoring extra data.

 

class.png

 

For example:

Given the following nested-structured local transparent table:

 

DATA :
  BEGIN OF ls_data.
        INCLUDE STRUCTURE spfli.
DATA :
      scarr   TYPE scarr,
      sflight TYPE sflight_tab1,
    END OF ls_data,
  lt_data LIKE TABLE OF ls_data.

 

Filled with test data:

 

SELECT *
       UP TO 10 ROWS
       FROM spfli
       INTO CORRESPONDING FIELDS OF TABLE lt_data.

FIELD-SYMBOLS : <fs_data> LIKE LINE OF lt_data.
LOOP AT lt_data ASSIGNING <fs_data>.
  SELECT SINGLE *
                FROM scarr
                INTO CORRESPONDING FIELDS OF <fs_data>-scarr
                WHERE carrid = <fs_data>-carrid.

  SELECT *
         FROM sflight
         INTO CORRESPONDING FIELDS OF TABLE <fs_data>-sflight
         WHERE carrid = <fs_data>-carrid
           AND connid = <fs_data>-connid.
ENDLOOP.

 

The result is:

data.png

The class looks as follows (I will also attach it as text at the bottom together with the demo report):

 

class ZCL_XML_UTIL definition
  public
  create public .

public section.
*"* public components of class ZCL_XML_UTIL
*"* do not include other source files here!!!

  methods CONSTRUCTOR .
  methods ABAP_TO_XML
    importing
      !IM_DATA type ANY
    exporting
      !EX_CONTENT type XSTRING
    raising
      ZCX_TYPE_NOT_SUPPORTED .
  methods XML_TO_ABAP
    importing
      !IM_CONTENT type XSTRING
    exporting
      !EX_DATA type ANY
    raising
      ZCX_TYPE_NOT_SUPPORTED .
protected section.
*"* protected components of class ZCL_XML_UTIL
*"* do not include other source files here!!!

  data MO_IXML type ref to IF_IXML .
  data MO_DOCUMENT type ref to IF_IXML_DOCUMENT .
private section.
*"* private components of class ZCL_XML_UTIL
*"* do not include other source files here!!!

  methods PROCESS
    importing
      !IM_NODE type ref to IF_IXML_NODE
      !IM_NAME type STRING
      !IM_DATA type ANY
    raising
      ZCX_TYPE_NOT_SUPPORTED .
  methods CREATE_ELEMENT
    importing
      !IM_NAME type STRING
      !IM_VALUE type STRING optional
    returning
      value(RE_ELEMENT) type ref to IF_IXML_ELEMENT .
  methods TRAVERSE
    importing
      !IM_CURRENT_NODE type ref to IF_IXML_NODE
    changing
      !CH_DATA type ANY
    raising
      ZCX_TYPE_NOT_SUPPORTED .
  class-methods AS_STRING
    importing
      !IM_DATA type ANY
    returning
      value(RE_DATA_STRING) type STRING .
ENDCLASS.



CLASS ZCL_XML_UTIL IMPLEMENTATION.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method ZCL_XML_UTIL->ABAP_TO_XML
* +-------------------------------------------------------------------------------------------------+
* | [--->] IM_DATA                        TYPE        ANY
* | [<---] EX_CONTENT                     TYPE        XSTRING
* | [!CX!] ZCX_TYPE_NOT_SUPPORTED
* +--------------------------------------------------------------------------------------</SIGNATURE>
METHOD abap_to_xml.

  CLEAR : ex_content.

* create .xml document
  mo_document = mo_ixml->create_document( ).

* set encoding to UTF-8 (Unicode Transformation Format)
* 8-bit variable-width encoding maximizes compatibility with ASCII
  mo_document->set_encoding( mo_ixml->create_encoding(
      byte_order    = 0
      character_set = 'UTF-8' ) ).

  IF NOT im_data IS INITIAL.
*   use mo_document as root
    process( im_node = mo_document
             im_name = 'data'
             im_data = im_data ).
  ENDIF.

* render .xml document with output stream
  mo_document->render(
    ostream = mo_ixml->create_stream_factory( )->create_ostream_xstring(
      string = ex_content ) ).
  FREE : mo_document.

ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Private Method ZCL_XML_UTIL=>AS_STRING
* +-------------------------------------------------------------------------------------------------+
* | [--->] IM_DATA                        TYPE        ANY
* | [<-()] RE_DATA_STRING                 TYPE        STRING
* +--------------------------------------------------------------------------------------</SIGNATURE>
METHOD as_string.

  MOVE im_data TO re_data_string.

ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method ZCL_XML_UTIL->CONSTRUCTOR
* +-------------------------------------------------------------------------------------------------+
* +--------------------------------------------------------------------------------------</SIGNATURE>
METHOD CONSTRUCTOR.

* get iXML library instance
  mo_ixml = cl_ixml=>create( ).

ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Private Method ZCL_XML_UTIL->CREATE_ELEMENT
* +-------------------------------------------------------------------------------------------------+
* | [--->] IM_NAME                        TYPE        STRING
* | [--->] IM_VALUE                       TYPE        STRING(optional)
* | [<-()] RE_ELEMENT                     TYPE REF TO IF_IXML_ELEMENT
* +--------------------------------------------------------------------------------------</SIGNATURE>
METHOD CREATE_ELEMENT.

  DATA :
    lv_name TYPE string VALUE IS INITIAL.

* element names look cooler in lower case
  lv_name = to_lower( im_name ).

* create element with given name
  re_element = mo_document->create_element( name = lv_name ).

* if element is leaf, set corresponding value
  IF im_value IS SUPPLIED.
    re_element->set_value( im_value ).
  ENDIF.

ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Private Method ZCL_XML_UTIL->PROCESS
* +-------------------------------------------------------------------------------------------------+
* | [--->] IM_NODE                        TYPE REF TO IF_IXML_NODE
* | [--->] IM_NAME                        TYPE        STRING
* | [--->] IM_DATA                        TYPE        ANY
* | [!CX!] ZCX_TYPE_NOT_SUPPORTED
* +--------------------------------------------------------------------------------------</SIGNATURE>
METHOD process.

  DATA :
    lo_type    TYPE REF TO cl_abap_typedescr,
    lo_struct  TYPE REF TO cl_abap_structdescr,
    lo_table   TYPE REF TO cl_abap_tabledescr,
    lo_data    TYPE REF TO data,
    lo_element TYPE REF TO if_ixml_element,
    lv_name    TYPE string VALUE IS INITIAL.

  FIELD-SYMBOLS :
    <ft_data>      TYPE STANDARD TABLE,
    <fs_component> TYPE abap_compdescr,
    <fs_data>      TYPE any,
    <fv_value>     TYPE any.

* determine ABAP/4 data type, support only:
* - simple type
* - structure
* - table type
  lo_type = cl_abap_typedescr=>describe_by_data( im_data ).

  CASE lo_type->kind.
    WHEN cl_abap_typedescr=>kind_elem.
*     create element
      lo_element = create_element(
          im_name  = im_name
          im_value = as_string( im_data ) ).

    WHEN cl_abap_typedescr=>kind_struct.
*     create parent element
      lo_element = create_element( im_name = im_name ).

*     process each structure component independently
      lo_struct ?= cl_abap_structdescr=>describe_by_data( im_data ).
      LOOP AT lo_struct->components ASSIGNING <fs_component>.
        ASSIGN COMPONENT <fs_component>-name OF STRUCTURE im_data TO <fv_value>.
        CHECK sy-subrc IS INITIAL.

        lv_name = <fs_component>-name.

        process( im_node = lo_element
                 im_name = lv_name
                 im_data = <fv_value> ).
      ENDLOOP.

    WHEN cl_abap_typedescr=>kind_table.
      lo_table ?= cl_abap_tabledescr=>describe_by_data( im_data ).
      CREATE DATA lo_data TYPE HANDLE lo_table.
      ASSIGN lo_data->* TO <ft_data>.
      <ft_data> = im_data.

*     create parent element
      lo_element = create_element( im_name = im_name ).

*     process each table line independently
      LOOP AT <ft_data> ASSIGNING <fs_data>.
       
process( im_node = lo_element
                 im_name = im_name
                 im_data = <fs_data> ).
     
ENDLOOP.

    WHEN OTHERS.
      TRY.
        RAISE EXCEPTION TYPE zcx_type_not_supported.
      ENDTRY.
  ENDCASE.

  IF lo_element IS BOUND.
    im_node->append_child( lo_element ).
  ENDIF.

ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Private Method ZCL_XML_UTIL->TRAVERSE
* +-------------------------------------------------------------------------------------------------+
* | [--->] IM_CURRENT_NODE                TYPE REF TO IF_IXML_NODE
* | [<-->] CH_DATA                        TYPE        ANY
* | [!CX!] ZCX_TYPE_NOT_SUPPORTED
* +--------------------------------------------------------------------------------------</SIGNATURE>
METHOD traverse.

  DATA :
    lo_type      TYPE REF TO cl_abap_typedescr,
    lo_struct    TYPE REF TO cl_abap_structdescr,
    lo_table     TYPE REF TO cl_abap_tabledescr,
    lo_data      TYPE REF TO data,
    lo_iterator  TYPE REF TO if_ixml_node_iterator,
    lo_node_list TYPE REF TO if_ixml_node_list,
    lo_node      TYPE REF TO if_ixml_node,
    lv_node_name TYPE string VALUE IS INITIAL,
    lv_match     TYPE boolean.

  FIELD-SYMBOLS :
    <ft_data>      TYPE STANDARD TABLE,
    <fs_component> TYPE abap_compdescr,
    <fs_data>      TYPE any,
    <fv_value>     TYPE any.

* determine ABAP/4 data type, support only:
* - simple type
* - structure
* - table type
  lo_type = cl_abap_typedescr=>describe_by_data( ch_data ).

  CASE lo_type->kind.
    WHEN cl_abap_typedescr=>kind_elem.
      ch_data = im_current_node->get_value( ).

    WHEN cl_abap_typedescr=>kind_struct.
      lo_node_list = im_current_node->get_children( ).

*     process each structure component independently
      lo_struct ?= cl_abap_structdescr=>describe_by_data( ch_data ).
      LOOP AT lo_struct->components ASSIGNING <fs_component>.
        ASSIGN COMPONENT <fs_component>-name OF STRUCTURE ch_data TO <fv_value>.
        CHECK sy-subrc IS INITIAL.

*       create new iterator with each step
        lo_iterator = lo_node_list->create_iterator( ).
        lo_node = lo_iterator->get_next( ).

        WHILE lo_node  IS BOUND
           OR lv_match EQ abap_true.

*         xml element names can contain lower case characters
          lv_node_name = to_upper( lo_node->get_name( ) ).

          IF lv_node_name EQ <fs_component>-name.
            lv_match = abap_true.
            EXIT.
          ENDIF.

          lo_node = lo_iterator->get_next( ).
        ENDWHILE.

        CHECK lv_match EQ abap_true.
        traverse( EXPORTING im_current_node = lo_node
                  CHANGING  ch_data         = <fv_value> ).
        CLEAR : lv_match.
      ENDLOOP.

    WHEN cl_abap_typedescr=>kind_table.
      lo_table ?= cl_abap_tabledescr=>describe_by_data( ch_data ).

      CREATE DATA lo_data TYPE HANDLE lo_table.
      ASSIGN lo_data->* TO <ft_data>.

      lo_node_list = im_current_node->get_children( ).
      lo_iterator = lo_node_list->create_iterator( ).
      lo_node = lo_iterator->get_next( ).

      WHILE lo_node IS BOUND.
        APPEND INITIAL LINE TO <ft_data> ASSIGNING <fs_data>.

        traverse( EXPORTING im_current_node = lo_node
                  CHANGING  ch_data         = <fs_data> ).

        lo_node = lo_iterator->get_next( ).
      ENDWHILE.

      IF NOT <ft_data> IS INITIAL.
        ch_data = <ft_data>.
      ENDIF.

    WHEN OTHERS.
      TRY.
        RAISE EXCEPTION TYPE zcx_type_not_supported.
      ENDTRY.
  ENDCASE.

ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method ZCL_XML_UTIL->XML_TO_ABAP
* +-------------------------------------------------------------------------------------------------+
* | [--->] IM_CONTENT                     TYPE        XSTRING
* | [<---] EX_DATA                        TYPE        ANY
* | [!CX!] ZCX_TYPE_NOT_SUPPORTED
* +--------------------------------------------------------------------------------------</SIGNATURE>
METHOD xml_to_abap.

  CLEAR : ex_data.

  DATA :
    lo_istream        TYPE REF TO if_ixml_istream,
    lo_stream_factory TYPE REF TO if_ixml_stream_factory,
    lo_iterator       TYPE REF TO if_ixml_node_iterator.

  ASSERT NOT im_content IS INITIAL.

  IF NOT ex_data IS REQUESTED.
    RETURN.
  ENDIF.

* create .xml document
  mo_document = mo_ixml->create_document( ).

  lo_stream_factory = mo_ixml->create_stream_factory( ).
  lo_istream = lo_stream_factory->create_istream_xstring( im_content ).

* parse .xml document with given input stream
  IF mo_ixml->create_parser(
      document       = mo_document
      istream        = lo_istream
      stream_factory = lo_stream_factory )->parse( ) IS INITIAL.

*   create iterator
    lo_iterator = mo_document->create_iterator( 0 ).

*   skip #document element
    lo_iterator->get_next( ).

*   start with root
    traverse( EXPORTING im_current_node = lo_iterator->get_next( )
              CHANGING  ch_data         = ex_data ).
  ENDIF.
  FREE : mo_document.

ENDMETHOD.
ENDCLASS.

 

Feedback is most welcomed!

 

Tudor

Actions

Filter Blog

By author:
By date:
By tag: