So far we have dealt with how to create a DOM representation of an XML document. Now that we have such a representation - a DOM tree - you will usually want to do something with this tree. You obviously need a way to "walk" the tree, to traverse it. This section describes the basic means to access nodes in the DOM tree, the next section will cover iterators and filters, a more high-level approach to traversing the tree.
As you have seen in the previous sections, a cl_ixml_documentinstance always holds the complete DOM tree. One of the immediate child nodes of the cl_ixml_document is the root element of the XML document. The following call will give you access to this node:
data: element type ref to if_ixml_element.
element = document->get_root_element( ).
Now you have a good starting point to look at the rest of the document content.
There are two ways to traverse the child nodes of a node, e.g. the cl_ixml_elementnodes of an cl_ixml_element node. One is to first navigate to the first child node and then ask this node to return the next (sibling) node. This approach looks like that:
data: child type ref to if_ixml_node.
child = element->get_first_child( ).
while not child is initial.
* do something with the node
child = child->get_next( ).
endwhile.
The W3C DOM also defined a method to return a list of nodes, a cl_ixml_node_listinstance providing index-based access to the child nodes of a node:
data: nodes type ref to if_ixml_node_list,
child type ref to if_ixml_node,
index type i.
nodes = element->get_children( ).
while i < nodes->get_length( ).
child = nodes->get_item( index ).
* do something with the node
index = index + 1.
endwhile.
Even though index-based access is guaranteed to perform in constant time (O(1)) for sequential indizes (e.g. 1,2,3,..,n or n,..,3,2,1), using cl_ixml_node_list for random-access will usually degrade to linear lookup (O(n)).
Recursively using one of the two approaches above will of course allow you to traverse the whole DOM tree.
cl_ixml_attribute nodes are not part of the DOM tree that can be accessed with the above methods. Attributes are stored only with cl_ixml_element nodes and can be retrieved this way:
data: attributes type ref to if_ixml_named_node_map,
attribute type ref to if_ixml_attribute,
child type ref to if_ixml_node,
index type i.
attributes = element->get_attributes( ).
if not attributes is initial.
while i < attributes->get_length( ).
child = attributes->get_item( index ).
* cast the child down to an attribute!!
attribute ?= child->query_interface( ixml_iid_attribute ).
* do something with the attribute
index = index + 1.
endwhile.
endif.
If you want to find an attribute by name and not index, cl_ixml_named_node_mapallows you to do so as the following example will show:
data: attributes type ref to if_ixml_named_node_map,
attribute type ref to if_ixml_attribute,
child type ref to if_ixml_node.
attributes = element->get_attributes( ).
if not attributes is initial.
child = attributes->get_named_item( name = 'status' ).
attribute = child->query_interface( ixml_iid_attribute ).
endif.
Since this is something you will do quite often, there is a convenient shortcut method of the if_ixml_element interface:
data: attribute type ref to if_ixml_attribute.
attribute = element->get_attribute_node( name = 'status' ).
or if you want to get the string value of an attribute:
data: str type string.
str = element->get_attribute( name = 'status' ).
Sometimes you'll know there is exactly one element with a given tag name in the whole document or a sub-tree of the document. The easiest way to find that one (or the first occurrence of this) node can be done using the following statement:
data: node type ref to if_ixml_node.
node = document->find_from_name( name = 'person' ).
It is possible to restrict the search depth in the tree; the following example would search up to two levels below the given element:
data: node type ref to if_ixml_node.
node = element->find_from_name( name = 'firstname' depth = 2 ).
It might happen that you have an XML document and want to get easy access to all elements with a particular tag-name, e.g. all item elements in a salesorder document.
One way of getting easy access to these elements is asking for a collection containing references to those elements that match a specified name:
data: items type ref to if_ixml_node_collection.
items = document->get_elements_by_tag_name( name = 'item' ).
As with if_ixml_element::find_from_name() it is possible to apply the function to a sub-tree of the document and to restrict the depth of search:
data: items type ref to if_ixml_node_collection.
items = document->get_elements_by_tag_name( name = 'item' depth = 2 ).
In the next section about iterators we'll take a look at a slightly better approach than creating an intermediate collection of interface references.