This commit is contained in:
danrega
2024-01-29 12:28:58 +01:00
parent 2e33bbcdfb
commit c0b3b9d244
3 changed files with 312 additions and 6 deletions

View File

@@ -352,7 +352,7 @@ SELECT ds~col1, ds~col2, ds~col3
<p align="right"><a href="#top">⬆️ back to top</a></p>
**Reading data from a database table in another client** ([classic ABAP](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenclassic_abap_glosry.htm) only ). Note that there are several variants of the `USING ...` addition for switching the [implicit client handling (F1 docu for standard ABAP)](https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/index.htm?file=abenabap_sql_client_handling.htm) from the current client to other clients. See more information [here (F1 docu for standard ABAP)](https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/index.htm?file=abapselect_client.htm).
**Reading data from a database table in another client** ([classic ABAP](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenclassic_abap_glosry.htm) only). Note that there are several variants of the `USING ...` addition for switching the [implicit client handling (F1 docu for standard ABAP)](https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/index.htm?file=abenabap_sql_client_handling.htm) from the current client to other clients. See more information [here (F1 docu for standard ABAP)](https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/index.htm?file=abapselect_client.htm).
``` abap
"Some examples; not available in ABAP for Cloud Development
@@ -985,10 +985,10 @@ INTO @DATA(more_sql_expr).
How [window expressions](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenwindow_expression_glosry.htm "Glossary Entry") work:
- Defines a subset of the result set (i. e. the
- Define a subset of the result set (i. e. the
"[window](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenwindow_glosry.htm "Glossary Entry")")
of a database query that implements ABAP SQL
- Applies a [window
- Apply a [window
function](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenwindow_function_glosry.htm "Glossary Entry") -
which evaluates the rows of the window and which can, for example,
be an [aggregate
@@ -1147,7 +1147,7 @@ SELECT *
AND comp11 IS INITIAL
"Combination of logical expression using AND, OR and parentheses
AND ( comp12 = a AND comp13 < b ) OR ( comp14 > c AND comp15 <> d )
AND ( comp12 = a AND comp13 < b ) OR ( comp14 > c AND comp15 <> d )
INTO TABLE @DATA(itab_where).
```

View File

@@ -28,6 +28,8 @@
- [More String Functions](#more-string-functions)
- [Checking the Similarity of Strings](#checking-the-similarity-of-strings)
- [Repeating Strings](#repeating-strings)
- [Returning the Smallest/Biggest of a Set of Character-Like Arguments](#returning-the-smallestbiggest-of-a-set-of-character-like-arguments)
- [Escaping Special Characters](#escaping-special-characters)
- [Executable Example](#executable-example)
@@ -364,7 +366,7 @@ s1 = |{ utc XSD = YES }|. "2024-01-01T13:51:38.57088Z
"STYLE: Defining the style of decimal floating point numbers;
"see the details in the ABAP Keyword Documentation.
DATA(dcfl34) = CONV decfloat34( '-123.45600' ).
s1 = |{ dcfl34 }|. "-123.456out->write( s1 ).
s1 = |{ dcfl34 }|. "-123.456
"Creates the predefined format
s1 = |{ dcfl34 STYLE = SIMPLE }|. "-123.456
"+/- added to the right, removes trailing zeros
@@ -1791,6 +1793,58 @@ ENDTRY.
<p align="right"><a href="#top">⬆️ back to top</a></p>
### Returning the Smallest/Biggest of a Set of Character-Like Arguments
- [`cmin/cmax`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abencmax_cmin_functions.htm) returns a string that contains the content of the smallest or biggest of a set of character-like arguments
- 'Set' means at least two arguments and a maximum of nine argeuments are passed (`valn` operators) for comparison.
- The comparison is made from left to right, and the first different character found determines the smaller or bigger argument.
```abap
DATA(min) = cmin( val1 = `zzzzzzz`
val2 = `zzazzzzzzzz` "smallest argument
val3 = `zzzzabc` ).
DATA(max) = cmax( val1 = `abcdef` "biggest argument
val2 = `aaghij`
val3 = `aaaaklmn`
val4 = `aaaaaaopqrs`
val5 = `aaaaaaaaaatuvwxy`
val6 = `aaaaaaaaaaaaaz` ).
```
<p align="right"><a href="#top">⬆️ back to top</a></p>
### Escaping Special Characters
- [`escape`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenescape_functions.htm) returns a string that is provided for the `val` parameter by escaping special characters according to the specification in the `format` parameter.
- Suitable values for the `format` parameter (which expects a data object of type `i`) are available in the `CL_ABAP_FORMAT` class (the constants starting with `E_`).
- Special rules apply to different contexts, such as URLS and JSON. Also note the prevention of Cross Site Scripting (XSS) attacks on web applications. For more information, refer to the [documentation](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenescape_functions.htm).
```abap
"Context: URLs
DATA(esc1) = escape( val = '...test: 5@8...'
format = cl_abap_format=>e_url_full ).
"...test%3A%205%408...
"Context: JSON
DATA(esc2) = escape( val = 'some "test" json \ with backslash and double quotes'
format = cl_abap_format=>e_json_string ).
"some \"test\" json \\ with backslash and double quotes
"Context: String templates
DATA(esc3) = escape( val = 'Special characters in string templates: |, \, {, }'
format = cl_abap_format=>e_string_tpl ).
"Special characters in string templates: \|, \\, \{, \}
"Invalid value for the format parameter
TRY.
DATA(esc4) = escape( val = 'This will raise an exception due to an invalid format value.'
format = 123 ).
CATCH cx_sy_strg_par_val.
ENDTRY.
```
<p align="right"><a href="#top">⬆️ back to top</a></p>
## Executable Example
[zcl_demo_abap_string_proc](./src/zcl_demo_abap_string_proc.clas.abap)

View File

@@ -26,6 +26,7 @@
- [Application Log](#application-log)
- [Running Code in the Background](#running-code-in-the-background)
- [Locking](#locking)
- [Calling Services](#calling-services)
This ABAP cheat sheet contains a selection of available ABAP classes, serving as a quick introduction, along with code snippets to explore the functionality in action.
@@ -603,7 +604,7 @@ DATA(str_no_blanks) = CONV string( chars ).
</td>
</tr>
<tr>
<td> <code>CL_ABAP_CONV_CODEPAGE</code> </td>
<td> <code>CL_ABAP_CONV_CODEPAGE</code><br><code>XCO_CP</code> </td>
<td>
For handling code pages, converting strings to the binary representation of different code pages and vice versa.
<br><br>
@@ -2010,4 +2011,255 @@ ENDTRY.
</tr>
</table>
<p align="right"><a href="#top">⬆️ back to top</a></p>
## Calling Services
<table>
<tr>
<td> Class </td> <td> Details/Code Snippet </td>
</tr>
<tr>
<td> <code>CL_WEB_HTTP_CLIENT_MANAGER</code><br><code>CL_HTTP_DESTINATION_PROVIDER</code> </td>
<td>
<ul>
<li>For creating a client object using an HTTP destination. The HTTP destination is provided based on an HTTP destination object.
The latter can be created, among others, based on a communication arrangement or a plain URL. </li>
<li>For more information, refer to the class documentation and the topic <a href="https://help.sap.com/docs/btp/sap-business-technology-platform/integration-and-connectivity">Integration and Connectivity</a>.</li>
<li>⚠️ Notes on the example</li>
<ul>
<li>The following self-contained and oversimplified example is not a representative best practice example, nor does it cover a meaningful use case.
It only explores method calls and is intended to give a rough idea of the functionality.</li>
<li>The example uses the <code>create_by_url</code> method, which is only suitable for public services or testing purposes. No authentication is required for the APIs used.</li>
<li>Note the <a href="README.md#%EF%B8%8F-disclaimer">Disclaimer</a>.</li>
<li>For more information, more meaningful examples, and tutorials that deal with the classes and methods, see the following links:</li>
<ul>
<li><a href="https://developers.sap.com/tutorials/abap-environment-external-api.html">Call an External API and Parse the Response in SAP BTP ABAP Environment</a></li>
<li><a href="https://community.sap.com/t5/technology-blogs-by-sap/how-to-call-a-remote-odata-service-from-the-trial-version-of-sap-cloud/ba-p/13411535">How to call a remote OData service from the trial version of SAP Cloud Platform ABAP environment</a></li>
</ul>
<li>The example is generally about calling external APIs and parsing the HTTP responses. It retrieves most of the code snippets contained in the ABAP cheat sheet markdown files of the ABAP cheat sheet GitHub repository. However, the focus is on the service calls, not on the actual output. More details:</li>
<ul>
<li>At various points in the code, the methods of the classes are used to create client objects. In all cases, an HTTP destination is created using a plain URL.</li>
<li>In all cases, public GitHub URLs/APIs are used that do not require an authentication (note the GitHub documentation links further down).</li>
<li>First, after creating a client object using a destination object that is based on a URL, an HTTP GET request is sent. The response is a string containing all file names that are contained in the ABAP cheat sheet GitHub repository. The file names are needed to construct URLs so as to retrieve the markdown content of the files. The file names are extracted and stored in an internal table.</li>
<li>Second, the internal table containing the file names is looped over. A URL is constructed for each markdown file. New client objects are created using destination objects that are based on the constructed URLs. Markdown content is retrieved by sending an HTTP GET request. To better process the retrieved content, it is stored in a string table. In the loop, all content from the markdown that is not part of a code snippet (indicated by the triple backticks) is deleted.</li>
<li>Third, a public API provided by GitHub is used to render markdown text to HTML. This is done by creating another client object. HTTP POST requests are sent, and the responses are retrieved. The responses should contain the code snippets converted to HTML in a string. The code snippets are added to HTML expandable sections.</li>
<li>Finally, the expandable sections containing the code snippets per cheat sheet are added to a simple HTML page. The code of the assembled HTML page is displayed in the ADT console.</li>
<li>For example and for demonstration purposes, if the HTML code is displayed in the ADT console, you can create a file named <em>ABAP_cheat_sheet_code.html</em> on your local machine. Open the file in an editor, copy and paste the entire ADT console content (it is recommended that you clear the ADT console before running the class to avoid copying and pasting unwanted output), and save the local file. Open the saved file in a web browser. You will now have several code snippets from the cheat sheets available offline.
In fact, the output (plain html with a lot of code) of this example is not a meaningful reference artifact and may not be of much use.
Nevertheless, the example may give you an idea of how to use the ABAP classes, GET and POST requests, and so on (and you may also be interested in the various options for string processing as used in the example and described in the respective cheat sheet). Follow the links for more information. </li>
<li>Before using the GitHub APIs, make sure that you have consulted the following documentation: <a href="https://docs.github.com/en">GitHub Docs</a>, <a href="https://docs.github.com/en/enterprise-cloud@latest/rest/markdown/markdown?apiVersion=2022-11-28#render-a-markdown-document">Render a Markdown document</a>, <a href="https://docs.github.com/en/rest/using-the-rest-api/rate-limits-for-the-rest-api?apiVersion=2022-11-28">Rate limits for the REST API</a> </li>
</ul>
</ul>
</ul>
<br>
``` abap
CLASS zcl_some_class DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
PRIVATE SECTION.
CONSTANTS url_cs TYPE string VALUE `https://api.github.com/repos/SAP-samples/abap-cheat-sheets/git/trees/main`.
CONSTANTS url_gh TYPE string VALUE `https://raw.githubusercontent.com/SAP-samples/abap-cheat-sheets/main/`.
CONSTANTS url_api TYPE string VALUE `https://api.github.com/markdown`.
DATA url TYPE string.
TYPES: BEGIN OF s,
file_name TYPE string,
title TYPE string,
code_snippets TYPE string_table,
error TYPE abap_bool,
END OF s.
DATA tab TYPE TABLE OF s WITH EMPTY KEY.
DATA snippets TYPE string_table.
DATA html TYPE string.
ENDCLASS.
CLASS zcl_some_class IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
TRY.
"Creating a client object using a destination
"In the example, the HTTP destination is created using a plain URL.
"Here, a GitHub API is used to retrieve file names of the ABAP cheat sheet repository.
DATA(http_client) = cl_web_http_client_manager=>create_by_http_destination( i_destination = cl_http_destination_provider=>create_by_url( i_url = url_cs ) ).
"Sending an HTTP GET request and returning the response
"In the example, the HTTP body is retrieved as string data.
DATA(response) = http_client->execute( if_web_http_client=>get )->get_text( ).
CATCH cx_root INTO DATA(err).
out->write( err->get_text( ) ).
ENDTRY.
IF err IS INITIAL.
"Markdown file names are contained in the returned string in a specific
"pattern. In the following code, the markdown file names are extracted
"using a regular expression (pattern: "path":"04_ABAP_Object_Orientation.md")
"After '"path":"' (not including this part, indivated by \K), two
"digits must follow. Then, the further file name is captured with a
"non-greedy capturing up to '.md'.
FIND ALL OCCURRENCES OF PCRE `("path":")\K\d\d.*?\.md` IN response
RESULTS DATA(results)
IGNORING CASE.
"The 'results' internal table contains all findings and includes their
"offset and length information.
"Using a loop, the actual file names are extracted from the 'response'
"string and added to an internal table that is to receive more information
"in the code below.
LOOP AT results REFERENCE INTO DATA(md).
tab = VALUE #( BASE tab ( file_name = substring( val = response off = md->offset len = md->length ) ) ).
ENDLOOP.
SORT tab BY file_name ASCENDING.
"In the following loop, the raw markdown content is retrieved using an HTTP GET request, also
"by creating a client object and using a destination (another plain URL). The URL is constructed
"using the constant value plus the markdown file that was retreived before.
LOOP AT tab REFERENCE INTO DATA(cs).
url = url_gh && cs->file_name.
TRY.
http_client = cl_web_http_client_manager=>create_by_http_destination( i_destination = cl_http_destination_provider=>create_by_url( i_url = url ) ).
DATA(raw_md) = http_client->execute( if_web_http_client=>get )->get_text( ).
"Putting the long string that was retrieved in an internal table of type string
"for further processing (extracting the code snippets).
SPLIT raw_md AT |\n| INTO TABLE snippets.
DATA(flag) = ''.
"In the loop, all content from the markdown that is not part of a code
"snippet (indicated by the triple ```) is deleted.
"The replacements with dummy content in the loop are only done so that
"the POST request further down can work with the provided content
"(i.e. avoiding issues characters such as "; they are inserted later again).
LOOP AT snippets REFERENCE INTO DATA(line).
DATA(tabix) = sy-tabix.
FIND PCRE '^\s*```' IN line->*.
IF sy-subrc = 0 AND flag = ''.
line->* = `%%%--START--%%%%`.
flag = 'X'.
ELSEIF sy-subrc = 0 AND flag = 'X'.
line->* = `%%%--END--%%%%`.
flag = ''.
ELSEIF flag <> 'X'.
DELETE snippets INDEX tabix.
ELSE.
FIND PCRE `^\s*"` IN line->*.
IF sy-subrc = 0.
DATA(comment1) = 'X'.
ENDIF.
FIND PCRE `^\*` IN line->*.
IF sy-subrc = 0.
DATA(comment2) = 'X'.
ENDIF.
FIND `***********************************************************************`
IN line->*.
IF sy-subrc = 0.
DATA(divider) = 'X'.
ENDIF.
IF comment1 = 'X' OR comment2 = 'X' OR divider = 'X'.
DELETE snippets INDEX tabix.
CLEAR: comment1, comment2, divider.
ELSE.
REPLACE ALL OCCURRENCES OF `"` IN line->* WITH `§§§§§`.
REPLACE ALL OCCURRENCES OF `\` IN line->* WITH `%%%%%`.
ENDIF.
ENDIF.
ENDLOOP.
"Adding the code snippets to the information table
cs->code_snippets = snippets.
CLEAR snippets.
CATCH cx_root INTO err.
cs->error = abap_true.
ENDTRY.
DELETE ADJACENT DUPLICATES FROM cs->code_snippets COMPARING table_line.
ENDLOOP.
"Creating the final html to be displayed
LOOP AT tab REFERENCE INTO cs WHERE code_snippets IS NOT INITIAL AND error = abap_false.
LOOP AT cs->code_snippets REFERENCE INTO DATA(code).
tabix = sy-tabix.
IF code->* = `%%%--START--%%%%`.
code->* = |```|.
ENDIF.
IF code->* = `%%%--END--%%%%`.
code->* = |```|.
INSERT `*****************` && |\\n|
INTO cs->code_snippets INDEX tabix + 1.
ENDIF.
code->* = code->* && |\\n|.
ENDLOOP.
"For the POST request, concatenating the string table to a single string.
DATA(code_string) = concat_lines_of( table = cs->code_snippets ).
TRY.
"Another creation of a client object using a destination
"This example deals with a POST request.
http_client = cl_web_http_client_manager=>create_by_http_destination( i_destination = cl_http_destination_provider=>create_by_url( i_url = url_api ) ).
DATA(request) = http_client->get_http_request( ).
request->set_text( `{"text":"` && code_string && `"}` ).
request->set_header_fields( VALUE #( ( name = 'Accept' value = 'application/vnd.github+json' ) ) ).
DATA(post) = http_client->execute( if_web_http_client=>post ).
DATA(status) = post->get_status( ).
IF status-code <> 200.
cs->error = abap_true.
DATA(status_error) = |Post request error: { status-code } / { status-reason }|.
ELSE.
"Retrieving the created html code
DATA(html_code) = post->get_text( ).
REPLACE ALL OCCURRENCES OF `§§§§§` IN html_code WITH `"`.
REPLACE ALL OCCURRENCES OF `%%%%%` IN html_code WITH `\`.
REPLACE ALL OCCURRENCES OF PCRE `(<code>)(\w.*)` IN html_code WITH `$1 $2`.
ENDIF.
CATCH cx_root INTO DATA(error).
cs->error = abap_true.
ENDTRY.
"Preparing the title for expandable sections
DATA(title) = cs->file_name.
REPLACE ALL OCCURRENCES OF `_` IN title WITH ` `.
REPLACE PCRE `^..` IN title WITH ``.
REPLACE `.md` IN title WITH ``.
"Assembling expandable sections
html = html &&
`<br><details>` &&
` <summary>` && title && `</summary>` &&
COND #( WHEN cs->error = abap_false THEN html_code ELSE COND #( WHEN error IS INITIAL THEN status_error ELSE error->get_text( ) ) ) &&
`</details>`.
ENDLOOP.
"Providing the html skeleton and inserting the assembled expandable sections from above
DATA(final_html) =
`<!DOCTYPE html>` &&
`<html>` &&
`<head>` &&
`<title>ABAP Cheat Sheet Code Snippets</title>` &&
`<style>` &&
` body {background-color: #F8F8F8;}` &&
` h1 {color: blue; font-family: verdana;}` &&
` pre {background: #f4f4f4;border: 1px solid #ddd;border-left: 3px solid #0070f2;color: #36454F;` &&
` page-break-inside: avoid;font-size: 14px;line-height: 1.3;max-width: 100%;overflow: auto;padding: 1em 1.5em;` &&
` display: block;word-wrap: break-word;} ` &&
`</style>` &&
`</head>` &&
`<body>` &&
`<h1>ABAP Cheat Sheet Code Snippets</h1>` &&
`<a href="https://github.com/SAP-samples/abap-cheat-sheets">https://github.com/SAP-samples/abap-cheat-sheets</a><br><br>` &&
html &&
`<script>` &&
` const snippets = document.querySelectorAll("code");` &&
` snippets.forEach(elem => {` &&
` var abap = elem.innerHTML;` &&
` abap = abap.replace(/(\b[A-Z]{2,}\b)/g, "<strong>$1</strong>");` &&
` elem.innerHTML = abap;` &&
` });` &&
`</script>` &&
`</body>` &&
`</html>`.
"Displaying the html result in the ADT console
"Note: Before running the class, clear the ADT console.
"When the html code is displayed in the ADT console, you can, for example,
"create a file named ABAP_cheat_sheet_code.html on your local machine.
"Open the file in an editor, copy & paste the entire ADT console content and
"save the local file. In doing so, you have various code snippets at your
"disposal offline.
out->write( final_html ).
ENDIF.
ENDMETHOD.
ENDCLASS.
```
</td>
</tr>
</table>
<p align="right"><a href="#top">⬆️ back to top</a></p>