xmltransformationabapabap-st

Ref-Node Error when running Simple Transformation


I have a problem with using a simple transformation I can't figure out.

Running the code gives me the following error message (exception class CX_ST_REF_ACCESS) at the transformation line <tt:loop name="PurchaseOrder" ref="PurchaseOrder">:

Error during access to the ref node 'PURCHASEORDER'. The ref node is not defined or does not have the necessary type

The error occurs when I use CALL Transformation.

I tried to read the data from the XML using Simple Transformation.

This is my Simple-Transformation:

<?sap.transform simple?>
<tt:transform xmlns:tt="http://www.sap.com/transformation-templates">
  <tt:root name="PurchaseOrder"/>

  <!-- Root element: PurchaseOrder -->
  <tt:template>
    <tt:loop name="PurchaseOrder" ref="PurchaseOrder">
      <PurchaseOrder>

        <!-- Address Elements -->
        <Address>
          <tt:loop name="Adress" ref="PurchaseOrder.Address">
            <Name>
              <tt:value ref="Name"/>
            </Name>
            <Street>
              <tt:value ref="Street"/>
            </Street>
            <City>
              <tt:value ref="City"/>
            </City>
            <State>
              <tt:value ref="State"/>
            </State>
            <Zip>
              <tt:value ref="Zip"/>
            </Zip>
            <Country>
              <tt:value ref="Country"/>
            </Country>
          </tt:loop>
        </Address>


        <!-- DeliveryNotes Element -->
        <DeliveryNotes>
          <tt:value ref="PurchaseOrder"/>
        </DeliveryNotes>

        <!-- Items Section -->
        <Items>
          <tt:loop ref="PurchaseOrder">
            <Item>
              <ProductName>
                <tt:value ref="ProductName"/>
              </ProductName>
              <Quantity>
                <tt:value ref="Quantity"/>
              </Quantity>
              <USPrice>
                <tt:value ref="USPrice"/>
              </USPrice>
              <tt:cond>
                <Comment>
                  <tt:value ref="Comment"/>
                </Comment>
              </tt:cond>
              <tt:cond>
                <ShipDate>
                  <tt:value ref="ShipDate"/>
                </ShipDate>
              </tt:cond>
            </Item>
          </tt:loop>
        </Items>
      </PurchaseOrder>
    </tt:loop>
  </tt:template>
</tt:transform>

My ABAP code (stripped down to the relevant part):

TYPES: BEGIN OF ty_address,
         name    TYPE string,
         street  TYPE string,
         city    TYPE string,
         state   TYPE string,
         zip     TYPE string,
         country TYPE string,
       END OF ty_address.

TYPES: BEGIN OF ty_item,
         productname TYPE string,
         quantity    TYPE i,
         usprice     TYPE p DECIMALS 2,
         comment     TYPE string,   " Optionales Feld für Kommentar
         shipdate    TYPE d,        " Optionales Feld für ShipDate
       END OF ty_item.

DATA: BEGIN OF ty_purchase_order,
         addresses     TYPE TABLE OF ty_address, " Mehrere Address-Einträge
         deliverynotes TYPE string,
         items         TYPE TABLE OF ty_item,    " Tabelle mit Items
       END OF ty_purchase_order.

DATA: gv_file       TYPE string,              " Datei für den Upload
      lt_xml_table  TYPE TABLE OF string,     " Tabelle für XML-Zeilen
      gv_xml_string TYPE string.              " Für das gesamte XML als String

gv_file = p_file.
CALL METHOD cl_gui_frontend_services=>gui_upload
  EXPORTING
    filename                = gv_file
*   codepage                = '1252'
  CHANGING
    data_tab                = lt_xml_table
  EXCEPTIONS
    file_open_error         = 1
    file_read_error         = 2
    no_batch                = 3
    gui_refuse_filetransfer = 4
    invalid_type            = 5
    no_authority            = 6
    unknown_error           = 7
    bad_data_format         = 8
    header_not_allowed      = 9
    separator_not_allowed   = 10
    header_too_long         = 11
    unknown_dp_error        = 12
    access_denied           = 13
    dp_out_of_memory        = 14
    disk_full               = 15
    dp_timeout              = 16
    not_supported_by_gui    = 17
    error_no_gui            = 18
    OTHERS                  = 19.

LOOP AT lt_xml_table INTO DATA(lv_line).
  CONCATENATE gv_xml_string lv_line INTO gv_xml_string.
ENDLOOP.

CALL TRANSFORMATION ZJB_TRAN0
SOURCE XML gv_xml_string
RESULT PurchaseOrder = ty_purchase_order.

And finally the XML-File i'd like to process:

<PurchaseOrder>
<Address>
<Name>Ellen Adams</Name>
<Street>123 Maple Street</Street>
<City>Mill Valley</City>
<State>CA</State>
<Zip>10999</Zip>
<Country>USA</Country>
</Address>
<Address>
<Name>Tai Yee</Name>
<Street>8 Oak Avenue</Street>
<City>Old Town</City>
<State>PA</State>
<Zip>95819</Zip>
<Country>USA</Country>
</Address>
<DeliveryNotes>Please leave packages in shed by driveway.</DeliveryNotes>
<Items>
<Item>
<ProductName>Lawnmower</ProductName>
<Quantity>1</Quantity>
<USPrice>148.95</USPrice>
<Comment>Confirm this is electric</Comment>
</Item>
<Item>
<ProductName>Baby Monitor</ProductName>
<Quantity>2</Quantity>
<USPrice>39.98</USPrice>
<ShipDate>1999-05-21</ShipDate>
</Item>
</Items>
</PurchaseOrder>

Solution

  • In a transformation, you should NEVER loop before the top XML node (<PurchaseOrder>) because a top XML node is unique.

    The error CX_ST_REF_ACCESS happens:

    Concerning the rest of your code, I see several confusions, please see below.

    ABAP names/ref

    To avoid confusion, I suggest indicating the ABAP names in your transformation (ref) in all upper case to avoid confusion with XML names. You will see that you are indicating ABAP names which don't exist in your ABAP code (ADDRESS instead of ADDRESSES).

    Note that ref can be expressed in several flavors as you can see in <PurchaseOrder tt:ref="PURCHASEORDER"> and <tt:loop name="Adress" ref="ADDRESSES">, they both have the same meaning (to set the current ABAP node pointer), the difference is that the prefix tt: is needed when the XML element is not an ST command.

    loop

    You should loop before <Address>, not after, because <Address> has multiple occurrences in the XML file.

    <tt:loop ref="ADDRESSES">
      <address>
      ...
      </address>
    </tt:loop>
    

    Name in loop or not

    No need to indicate a name if you don't refer to it. A name is useful if you have two or more nested loops, e.g. to refer to the ABAP content from an inner loop (second level for instance) to refer to an outer loop (first level for instance).

    <tt:loop name="table1" ref="TABLE1">
      <tt:loop ref="TABLE2">
        <element tt:ref="$table1.COMP_OF_TABLE1"/>
        <element2 tt:ref="COMP_OF_TABLE2"/>
      </tt:loop>
    </tt:loop>
    

    ABAP TYPES referring to a table type

    Concerning the ABAP code, I guess you made ty_purchase_order a variable (DATA) because you had a syntax error when trying to make it a type (TYPES), due to addresses TYPE TABLE OF ty_address (also items), because an internal table inside a complex type must be "complete" i.e. specify the table category and the key, e.g. one solution could be:

    TYPES: BEGIN OF ty_purchase_order,
             addresses     TYPE STANDARD TABLE OF ty_address WITH EMPTY KEY,
             deliverynotes TYPE string,
             items         TYPE STANDARD TABLE OF ty_item WITH EMPTY KEY,
           END OF ty_purchase_order.
    
    DATA(ls_purchase_order) = VALUE ty_purchase_order( ).