You are on page 1of 8

SAP CRM: Webclient UI - Framework: BPath.

Lesson 02: About the interpreter, integration,


structures and filtering

Posted by Juergen Gatter Apr 14, 2011


<< Lesson 01: What is BPath? Lesson 03: Functions and Assignments >>

Welcome back to our course on BPath. As you may remember from the first lesson (BPath. Lesson 01: What is
BPath?) we introduced BPath and we discovered the first easy BPath statements.

Now we face the question, how our BPath statements are included into our ABAP environment. The following
code example coding should illustrate the ways to access BOL with BPath.

At first we need a Business Collection where we start from:


DATA lv_compset type CRMT_GENIL_APPL.
DATA lv_bol_core TYPE REF TO CL_CRM_BOL_CORE.
DATA lv_dyn_query TYPE REF TO CL_CRM_BOL_DQUERY_SERVICE.
DATA lv_result type ref to IF_BOL_ENTITY_COL.

lv_compset = 'UIF'.
lv_bol_core = cl_crm_bol_core=>get_instance( ).
lv_bol_core->start_up( lv_compset ).
lv_dyn_query = cl_crm_bol_dquery_service=>get_instance(
'UIFAdvSearchFlight' ).
lv_dyn_query->set_property(
iv_attr_name = 'MAX_HITS' iv_value = '5' ).
lv_result = lv_dyn_query->get_query_result( ).

At the end of this code fragment, we have a Business Collection which should contain 5 query result objects.
Unfortunately BPath does not work on Business Collection directly, so we have to convert it to a Business
Collection of uniform type first:

DATA lv_result2 type ref to CL_CRM_BOL_ENTITY_COL_UT.


lv_result2 ?= CL_CRM_BOL_ENTITY_COL_UT=>Convert( lv_result ).

Above statement constructs the required Business Collection with uniform type. To fetch a data result with a
BPATH query from it, the following syntax has to be used:

Data lv_bpath_result type ref to data.


Data lv_sourcecode type string.

Generated by Jive on 2016-07-14Z


1
SAP CRM: Webclient UI - Framework: BPath. Lesson 02: About the interpreter, integration, structures and
filtering

lv_sourcecode = 'SearchResFlightRel/FlightBookRel/*$'.
lv_bpath_result = lv_result2->GET_PROPERTIES_BY_BPATH(
IV_BPATH_STATEMENT = lv_sourcecode ).

If you want to execute the BPath query on a single object, the syntax is similar:

DATA: lv_element type ref to CL_CRM_BOL_ENTITY.


lv_element = lv_result->GET_LAST( ).
lv_bpath_result = lv_element->GET_PROPERTIES_BY_BPATH(
IV_BPATH_STATEMENT = lv_sourcecode ).

Before we get back to some more examples, some words on the Interpreter. BPath statements are directly
translated into action (so it's no compiled language). At the very beginning, it was implemented as top-down
parser using recursive descent. But after the first enhancements, it turned out that this approach is hardly
maintainable and not extendable. So the parser was migrated to a stack machine.

The parser is implemented in the CL_WCF_BPATH_PARSER class. At first the scanner (method
SCAN_NEXT) comes into picture which scans the input token by token. The scanner works context free, in
means the result only depends on the currently processed characters and nothing else.The parser itself works
in two passes. The first pass parses only the syntax without knowing anything about the semantics (it even
does not know whether a specified relation or attribute name is valid), the second pass does the action. The
parser uses two control tables which are built up at the beginning. The first holds all identifiers, identifiers
are a level above tokens, not completely matching. The second table holds the possible status transistions
controlling the parsing. In theory all parsing is done table controlled and only the action is done "coded". But I
guess in practise things are not that clean, but I haven't checked now.
The parsing includes a lot of going forward and backward as for each entity the corresponding BPath fragment
has to be evaluated again. To avoid too much operations for scanning, the first pass stores the intermediate
results in a table also. There are mechanisms to avoid the assembly of the internal tables in case the data is
already available.

As the recursive information is no more hold implecitely within the calling hierarchy, it has to be held explicitely.
To do so a new stack class called CL_WCF_BPATH_STACK is used, implementing the stack with some pretty
uncommon inventions. BPath actually uses quite a lot of stacks during processing.

The language itself does not differentiate between upper and lower case except where the underlying layer
requires it (e.g. BOL is using case sensitive relation names). All elements must succeed directly after each
other, it is not allowed to use blanks or carriage returns for separation.

~CRMS_BOL_UIF_TRAVEL_BOOK_KEY/SearchResFlightRel/FlightBookRel/*$

Code Example 7, ~STRUC, normal structures

Generated by Jive on 2016-07-14Z


2
SAP CRM: Webclient UI - Framework: BPath. Lesson 02: About the interpreter, integration, structures and
filtering

In the examples of the last lesson the structure of the returned entity is set implicitly. It refers simply to the
attribute structure of the corresponding object. Sometimes this is not required or wanted. So it is possible to set
the structure explicitly as above.

The example uses the key structure which consists of 4 fields. The data is always filled with a move-
corresponding statement (also when structures match). It is responsibility of the caller that the structures
match, i.e. that the move-corresponding does not try to copy data to fields with the same name but of different
type.

It is recommended to place the structure definition directly at the beginning, even though the syntax allows
otherwise. With the first access to the structure, it has to be defined of course.

SearchResFlightRel/FlightBookRel[2]/*$
Code Example 8, [2] (basic filtering)

The [ ] clasps the filtering. The further evaluation is only done if the filtering can be done successfully. In our
example we exclude all entries which are not the second entry within the FlightBookRel collection.

The filtering always relates to the most current relation. If we use the above source code on a collection the
statement would return the second booking for every flight of the collection.

You may filter on every relation you specify. Syntactically it is correct to put several filters on one relation,
eventough the result will be the same as if you use a corresponding conditional filter.

SearchResFlightRel/FlightBookRel[@CLASS="C"]/*$

Code Example 9, [@CLASS="C"] basic conditional filtering, string literals

There are two ways to filter, the first is operation on the index as in the previous chapter, the second is using
boolean operations. If the statement is evaluated to true we proceed. Otherwise we check the next entry.

Please note, that string laterals are built using double quotes. It is possible to mask a double quote by stating
two double quotes after each other.
Of course, the filtering is not restricted to simple comparisons with the equal operator. Let us check the next
example:

SearchResFlightRel/FlightBookRel[(@CLASS<>"C")&(@FORCURKEY=@LOCCURKEY)]/*$

Code Example 10, [(@CLASS<>"C") &(@ FORCURKEY=@LOCCURKEY)], Comparisons and Bool-OPs

As you see it is also possible to use other comparison operators ( more exactly <, >, <=, >=, <>, = ). And it is
possible to use the boolean functions and (with the & symbol) and or (using | ).

SearchResFlightRel/FlightBookRel[(@SMOKER+@INVOICE)="X"]/*$

Code Example 11, [(@SMOKER+@INVOICE)="X"], basic arithmetic operations

Generated by Jive on 2016-07-14Z


3
SAP CRM: Webclient UI - Framework: BPath. Lesson 02: About the interpreter, integration, structures and
filtering

This example uses arithmetic operators, in this case as string concatenation operator. Both fields used are
either "X" or empty so the expression basically evaluates to true if exactly one of the flags is set.
Please note that all operations are only working with 2 operands. An 'or' with three operands has to be
expressed using appropriate brackets.
Beside above noted boolean and comparison operators the standard operators + (addition), - (substraction), *
(multiplication) and % (division) are supported. The full operation table will be provided in the next lesson.
In general BPath operates with 4 data types: Strings, Dates, Numerics and Booleans. Within an intermediate
value of an expression any of the above types may be used, but on the highest level of a filter it has to be
either a boolean or a numeric value. For a numeric value an implicit check against the index is done. Note that
negative value may be used also, as -1 represents the last entity of the collection (-2 consequently the second
last, and so on).

With the next lesson we do something completely different. Assignments.

4205 Views

praveen kumar
Mar 19, 2015 12:49 AM
nice information. really very useful. Thanks Juergen Gatter

Juergen Gatter in response to Santosh Kotra on page 4


Mar 17, 2015 2:13 PM
Hello Santosh,

as far as I remember we did never work on the possibility to bypass the buffer on working with BPath. So
unfortunately I guess it is not possible.

Best Regards, Juergen

Santosh Kotra
Mar 11, 2015 10:29 AM
Hello Juergen,

This is me again, I wanted to bypass buffer using get_related_entites_by_bpath. Is that possible, I don't see
any parameters for that.

Please help.

Regards,
Santosh

Santosh Kotra in response to Juergen Gatter on page 5


Mar 5, 2015 8:27 AM
Hello Juergen,

Sorry for the delayed reply. Thank you.

Generated by Jive on 2016-07-14Z


4
SAP CRM: Webclient UI - Framework: BPath. Lesson 02: About the interpreter, integration, structures and
filtering

Regards,
Santosh

Juergen Gatter in response to Santosh Kotra on page 5


Feb 12, 2015 7:05 PM
Hello Santosh,

actually BPath is only working hardcoded, there is no automatic replacement of variables implemented. In case
you want to use BPath based on user input you have to do the string replacements on your own.

Ok?

Best Regards, Juergen

Santosh Kotra
Feb 10, 2015 3:18 PM
Hello Juergen,

I was trying to use the filtering option with a variable lv_filter as below.
lv_filter = 'MAT1'.
get_related_entities_by_bpath( 'BTOrderHeader/BTHeaderItemsExt/
BTOrderItemAll[@ORDERED_PROD="{ lv_filter }"]/*$' ).
The above code doesn't return any results but when I hardcode it as below, it works.
get_related_entities_by_bpath( 'BTOrderHeader/BTHeaderItemsExt/
BTOrderItemAll[@ORDERED_PROD="MAT1"]/*$' ).

I would like to filter dynamically based on the input.

Please could you check if I am doing it wrong. Thank you.

Best Regards,
Santosh

Pallavi A.N in response to Juergen Gatter on page 5


Feb 9, 2015 7:51 PM
Hi Juergen,

Thanks for the reply. {!ADDRESS_KEY=@ADDRESS_GUID} this works. It returns Address key with GUIDs.

Regards,
Pallavi

Juergen Gatter in response to Pallavi A.N on page 6


Feb 9, 2015 10:39 AM
Hi Pallavi,

Generated by Jive on 2016-07-14Z


5
SAP CRM: Webclient UI - Framework: BPath. Lesson 02: About the interpreter, integration, structures and
filtering

as far as I can see, the relation returns CRMT_BUPA_IL_ADDRESS structure, in which there is a field
ADDRESS_GUID which is char32 whereas CRMT_OST_BUPA_ADDRESS_KEY has a field ADDRESS_KEY
which is raw16.

I am a bit unsure whether BPATH is able to do the conversion from char32 to raw16, but as the * operator is
doing a move-corresponding operation, it can not match ADDRESS_KEY to ADDRESS_GUID as there are
different names used. You might try a

{!ADDRESS_KEY=@ADDRESS_GUID} assignment block (see next chapter for syntax).

Hmm, I just realized that some of the examples in lesson 3 seems to be broken. I will check this.

Best regards, Juergen

Pallavi A.N
Feb 8, 2015 6:35 PM
Hello Jurgen,

Thanks for the blog.

I tried BPath with DQuery 'BuilHeaderAdvancedSearch'.

I want to retrieve key structure of address relation. So I used below source code.

'~CRMT_OST_BUPA_ADDRESS_KEY/BuilAddressRel/*$'

But it returns result with all zeros in address key. Previously I tried '/BuilAddressRel/*$' . It worked fine and
retrieved 10 address details. Could you please correct me if I am using the wrong source code?

Thanks,
Pallavi

Holger Trompeter
Jan 29, 2014 1:34 PM
Hi Jürgen,

thank you for this excellent blog, it helped me a lot!

Regards,

Holger

Juergen Gatter in response to P R Raghu on page 7


May 25, 2011 8:11 AM
Hi Raghu,

Thanks for your feedback. The first five lessons are already out, I suppose there will be four more to come on
this release over the next weeks.

Generated by Jive on 2016-07-14Z


6
SAP CRM: Webclient UI - Framework: BPath. Lesson 02: About the interpreter, integration, structures and
filtering

The next release will be interesting, because then it becomes ... complex ;-) But there's a little time till it is
released.

Regards, Juergen

P R Raghu
May 25, 2011 7:41 AM
Hi Juergen,

Very interesting blog.Looking forward for more blogs on this.

Luís Pérez Grau in response to Juergen Gatter on page 7


Apr 18, 2011 3:05 AM
Hi Juergen,

Thanks for the answer, I think BPath is pretty cool, as long the development stays in the "keep it simple"
philosophy :-) I hope I can use it soon.

Regards,

Luis

Juergen Gatter in response to Luís Pérez Grau on page 7


Apr 18, 2011 2:50 AM
Hi Luis
Performance is always an important topic, so thank you for your interest and the question.

Well, main directions of BPath are to be generic and to be of easy usage. As a generic implementation based
on ABAP can hardly be faster then a well-done implementation in ABAP, goal is that the performance is
not worse than a naive implementation plus a certain overhead. We did some investigations a year ago
and according to these the overhead caused by BPath can be expected to be around 10% (but of course
depending on the statement complexity), that's a pretty good result I would say.

Now is the question whether the naive implementation is always the best one.

Actually I have to add that the filters above already contains a performance fix, which I didn't state in the text
above. Originally a filter was implemented as a check against the current index, leading to the effect, that
all entries of the collection had to be checked harming performance drastically with big collection sizes. This
was changed and a Rel[17] really means that only the 17.th element is processed. This works for all static
filters returning a number (these are basically all, except those which need information from the object itself for
calculation).

There is another performance improvement which is actually not there. When you have a two 1:n relation
hierachy rel1/rel2 the second relation is always read for every intermediate object. Reading all at once can be
faster (depending on the application implementation), but only in case all entities are processed. As it can not
be decided which way is better, an heuristic would have be an idea, but this is a future project.

In general I would conclude that performance is quite fine as for the targeted adoptions the mentioned
drawbacks are hardly important.

Best regards, Juergen

Luís Pérez Grau

Generated by Jive on 2016-07-14Z


7
SAP CRM: Webclient UI - Framework: BPath. Lesson 02: About the interpreter, integration, structures and
filtering

Apr 14, 2011 1:29 PM


Fantastic! God way to simplify the code, it's too tedious declare the same patterns each time, but what about
the performance?

Regards,

Luis

Generated by Jive on 2016-07-14Z


8

You might also like