Show TOC Anfang des Inhaltsbereichs

Hintergrunddokumentation Casting up and down the inheritance hierarchy  Dokument im Navigationsbaum lokalisieren

I would like to take a short detour on casting references with the iXML implementation here, because whatever you do with the DOM, you somehow stumble over this issue. People usually give me a call then and I have to admit that this deserves some explanation... So here are the facts:

Why casting?

The place where you will most likely run into this problem is the DOM tree. The DOM consists of about a dozen interfaces that are somehow related by inheritance - or better - by containment. Here's an example: the "base" interface in the DOM is the if_ixml_node interface which provides access to the base functionality offered by all DOM nodes; the if_ixml_elementinterface is derived from this interface (in ABAP Objects terminology: it contains this interface) and adds a few Element specific methods.

Now, a lot of methods in the DOM return references to the base interface if_ixml_node since they provide generic or polymorphic functionality. A typical example is the method if_ixml_node~get_next() which returns the next sibling node: this node could be anything from an Element over Text to Comment node.

Being generic is nice for some methods or functions, but you have to be more concrete in a lot of cases. Therefore a if_ixml_nodeinterface may be insufficient for you, since you might have to call a method that is only defined on the if_ixml_elementinterface. A prerequisite is - of course - that the underlying DOM node is an element, not a comment or something else.

This is where casting comes in handy. Let's assume you have a reference to if_ixml_node, know there is an element behind that interface and you want to get the corresponding if_ixml_element interface. Here's the code to accomplish this:

data: node    type ref to if_ixml_node,

      element type ref to if_ixml_element.

...

element ?= node->query_interface ( ixml_iid_element ).

For each interface in the iXML library there is one constant ixml_iid_... that can be used with query_interface(). Be aware to use the dynamic cast operator ?=, using = is not sufficient.

Checking whether a cast has succeeded

If you cast using query_interface() you might want to check for succeess if you can't be completely sure that the object supports the interface you were asking for. In order to do this you might use the following code to do the cast:

data: node    type ref to if_ixml_node,

      element type ref to if_ixml_element.

...

element ?= node->query_interface ( ixml_iid_element ).

if element is initial.

* error: uh-oh! node does not suppport the element interface!!

endif.

As you can see, query_interface() returns a null reference if the requested interface is not supported by the object.

Casting down the inheritance hierarchy

Casting down the inheritance hierarchy means getting a reference to a more specialized interface from a reference to a more generic one, e.g. casting an if_ixml_node down to an if_ixml_elementinterface.

You have to use the query_interface() method to do so as described in the previous paragraph.

Casting up the inheritance hierarchy

Casting up the inheritance hierarchy means getting a reference to a more generic interface from a reference to a more specialized one, e.g. casting an if_ixml_element up to an if_ixml_nodeinterface.

You can - but don't have to - use the query_interface()method to do so as described in the previous paragraph. In fact, casting up the inheritance hierarchy does not require any explicit casts which means that you can pass a if_ixml_element reference whenever a if_ixml_node reference is actually required.

You may now ask yourself why this works only when casting up and why you have to explicitly cast your way down the inheritance hierarchy? Well, this again is due to the fact how the iXML ABAP Objects wrappers interact with their C++ counterparts in the kernel. Believe me, there is no efficient way around this problem, except if the ABAP Objects language would be extended to allow operator overloading; I could then overload the cast (?=) operator to call query_interface() internally. But this is unlikely to happen.

But for now, let's get back on track with the interesting stuff...



Ende des Inhaltsbereichs