Práce s XML v ABAPu - 3. část
Tímto článkem bych rád zakončil můj krátký seriál (1. část, 2. část) o programování XML v ABAPu. Závěrečná část se bude zabývat parsováním XML souborů s využitím iXML knihovny.
Jak na XML parser
Jak již bylo řečeno v předchozí části, ke XML dokumentu lze přistupovat dvojím způsobem:
- Přes rozhraní řízené událostmi
- Přes DOM model
Já bych se chtěl zaměřit na druhou variantu, tedy zpracovaní XML dokumentu, které využívá standard XML DOM 1.0.
iXML knihovnu umíme připojit už z minula, takže jen pro úplnost:
type-pools: ixml. class cl_ixml definition load.
Opět budeme muset vytvořit instance starých známých objektů iXML factory a stream factory. Dále je třeba načíst XML soubor do interní tabulky pomocí rutiny get_xml_table (podrobně si ji můžete prostudovat ve vzorovém programu), vytvořit proud g_istream reprezentující vstupní soubor a vytvořit DOM model dokumentu.
DATA: g_ixml TYPE REF TO if_ixml,
g_streamfactory TYPE REF TO if_ixml_stream_factory,
g_parser TYPE REF TO if_ixml_parser,
g_istream TYPE REF TO if_ixml_istream,
g_document TYPE REF TO if_ixml_document,
g_node TYPE REF TO if_ixml_node,
g_xmldata TYPE string,
g_error TYPE xfeld.
DATA: g_xml_table TYPE TABLE OF t_xml_line,
g_xml_line TYPE t_xml_line,
g_xml_table_size TYPE i.
* Creating a ixml factory
g_ixml = cl_ixml=>create( ).
* Creating the dom object model
g_document = g_ixml->create_document( ).
* Creating a stream factory
g_streamfactory = g_ixml->create_stream_factory( ).
* upload XML document from file
PERFORM get_xml_table CHANGING g_xml_table_size g_xml_table.
* wrap the table containing the file into a stream
g_istream = g_streamfactory->create_istream_itable(
table = g_xml_table
size = g_xml_table_size ).
* Creating a document
g_document = g_ixml->create_document( ).
A nýní se již dostáváme k samotnému parsování dokumentu pomocí rutiny parse_document:
* Parse document
PERFORM parse_document.
CHECK g_error = space.
*---------------------------------------------------------------------*
* FORM parse_document *
*---------------------------------------------------------------------*
FORM parse_document.
DATA: parseerror TYPE REF TO if_ixml_parse_error,
str TYPE string,
i TYPE i,
count TYPE i,
index TYPE i.
* Create a Parser
g_parser = g_ixml->create_parser( stream_factory = g_streamfactory
istream = g_istream
document = g_document ).
* Parse the stream
IF g_parser->parse( ) NE 0.
g_error = 'X'.
IF g_parser->num_errors( ) NE 0.
count = g_parser->num_errors( ).
ULINE.
WRITE: count, ' parse errors have occured:'.
index = 0.
WHILE index < count.
parseerror = g_parser->get_error( index = index ).
i = parseerror->get_line( ).
WRITE: 'line: ', i.
i = parseerror->get_column( ).
WRITE: 'column: ', i.
str = parseerror->get_reason( ).
WRITE: str.
index = index + 1.
ENDWHILE.
ENDIF.
ENDIF.
ENDFORM.
Na závěr vykonáme průchod výsledným DOM modelem a výpis XML stromu na obrazovku pomocí rutiny process_dom:
* Process the document
IF g_parser->is_dom_generating( ) EQ 'X'.
PERFORM process_dom USING g_document.
ENDIF.
*---------------------------------------------------------------------*
* FORM process_dom *
*---------------------------------------------------------------------*
FORM process_dom USING document TYPE REF TO if_ixml_document.
DATA: node TYPE REF TO if_ixml_node,
iterator TYPE REF TO if_ixml_node_iterator,
nodemap TYPE REF TO if_ixml_named_node_map,
attr TYPE REF TO if_ixml_node,
name TYPE string,
prefix TYPE string,
value TYPE string,
indent TYPE i,
count TYPE i,
index TYPE i.
node ?= document.
CHECK NOT node IS INITIAL.
ULINE.
WRITE: /.
WRITE: /' DOM-TREE'.
WRITE: /.
IF node IS INITIAL. EXIT. ENDIF.
* create a node iterator
iterator = node->create_iterator( ).
* get current node
node = iterator->get_next( ).
* loop over all nodes
WHILE NOT node IS INITIAL.
indent = node->get_height( ) * 2.
indent = indent + 20.
CASE node->get_type( ).
WHEN if_ixml_node=>co_node_element.
* element node
name = node->get_name( ).
nodemap = node->get_attributes( ).
WRITE: / 'ELEMENT :'.
WRITE: AT indent name COLOR COL_POSITIVE INVERSE.
IF NOT nodemap IS INITIAL.
* attributes
count = nodemap->get_length( ).
DO count TIMES.
index = sy-index - 1.
attr = nodemap->get_item( index ).
name = attr->get_name( ).
* prefix = attr->get_namespace_prefix( ).
value = attr->get_value( ).
WRITE: / 'ATTRIBUTE:'.
WRITE: AT indent name COLOR COL_HEADING INVERSE, '=',
value COLOR COL_TOTAL INVERSE.
ENDDO.
ENDIF.
WHEN if_ixml_node=>co_node_text OR
if_ixml_node=>co_node_cdata_section.
* text node
value = node->get_value( ).
WRITE: / 'VALUE :'.
WRITE: AT indent value COLOR COL_GROUP INVERSE.
ENDCASE.
* advance to next node
node = iterator->get_next( ).
ENDWHILE.
ENDFORM.
Vzorový program si můžete prohlédnout zde.

