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>
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:
<tt:loop name="PurchaseOrder" ref="PurchaseOrder">
refers (ref
) to the root name "PurchaseOrder
" which refers to the ABAP variable TY_PURCHASE_ORDER
which is a structure, so a loop is meaningless.Concerning the rest of your code, I see several confusions, please see below.
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
).
<tt:root name="PurchaseOrder"/>
and <tt:loop name="Adress" ref="PurchaseOrder.Address">
, better type:
<tt:root name="PURCHASEORDER"/>
<tt:template>
<PurchaseOrder tt:ref="PURCHASEORDER">
...
<tt:loop name="Adress" ref="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>
loop
or notNo 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>
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( ).