2009 Oct 15 4:27 PM
Greetings!
I'm working on building xml data in ABAP report (46C) and I can build the data and send to the local PC via ws_download with no problem however I have a requirement to send the xml data to the application server via "open dataset" as we wish to run this in background via a job. The XML data is delivered however there are carriage returns at the end of lines and filler characters in the last row. Below is the code I'm using which needs help.
DATA: l_dom TYPE REF TO if_ixml_element,
m_document TYPE REF TO if_ixml_document,
g_ixml TYPE REF TO if_ixml,
w_string TYPE xstring,
w_size TYPE i,
w_result TYPE i,
w_line TYPE string,
it_xml TYPE dcxmllines,
s_xml LIKE LINE OF it_xml,
w_rc LIKE sy-subrc.
DATA: xml TYPE dcxmllines.
DATA: rc TYPE sy-subrc,
BEGIN OF xml_tab OCCURS 0,
d LIKE LINE OF xml,
END OF xml_tab.
DATA: wa_xmlrec LIKE LINE OF xml.
DATA v_serfile(250) TYPE c.
DATA: v_err1(40),
v_msg1(100),
v_strlen1 TYPE i.
*---> Convert Data to XML
CLASS cl_ixml DEFINITION LOAD.
g_ixml = cl_ixml=>create( ).
CHECK NOT g_ixml IS INITIAL.
m_document = g_ixml->create_document( ).
CHECK NOT m_document IS INITIAL.
WRITE: / 'Converting DATA TO DOM 1:'.
CALL FUNCTION 'SDIXML_DATA_TO_DOM'
EXPORTING
name = 'it_catalogs'
dataobject = it_catalogs[]
IMPORTING
data_as_dom = l_dom
CHANGING
document = m_document
EXCEPTIONS
illegal_name = 1
OTHERS = 2.
IF sy-subrc = 0.
WRITE 'Ok'.
ELSE.
WRITE: 'Err =',
sy-subrc.
ENDIF.
CHECK NOT l_dom IS INITIAL.
w_rc = m_document->append_child( new_child = l_dom ).
IF w_rc IS INITIAL.
WRITE 'Ok'.
ELSE.
WRITE: 'Err =',
w_rc.
ENDIF.
CALL FUNCTION 'SDIXML_DOM_TO_XML'
EXPORTING
document = m_document
IMPORTING
xml_as_string = w_string
size = w_size
TABLES
xml_as_table = it_xml
EXCEPTIONS
no_document = 1
OTHERS = 2.
IF sy-subrc = 0.
WRITE 'Ok'.
ELSE.
WRITE: 'Err =',
sy-subrc.
ENDIF.
LOOP AT it_xml INTO xml_tab-d.
APPEND xml_tab.
ENDLOOP.
*--> Send XML file
IF r_local = 'X'.
CALL FUNCTION 'WS_DOWNLOAD'
EXPORTING
bin_filesize = w_size
filename = p_ruta
filetype = 'BIN'
TABLES
data_tab = xml_tab
EXCEPTIONS
OTHERS = 10.
IF sy-subrc <> 0.
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ENDIF.
ELSEIF r_unix = 'X'.
v_serfile = p_upath.
OPEN DATASET v_serfile FOR OUTPUT IN TEXT MODE.
IF sy-subrc NE 0.
WRITE: / 'Invalide Open: ', v_serfile.
STOP.
ENDIF.
LOOP AT xml_tab.
wa_xmlrec = xml_tab-d.
v_strlen1 = strlen( wa_xmlrec ).
TRANSFER wa_xmlrec TO v_serfile LENGTH v_strlen1.
ENDLOOP.
CLOSE DATASET v_serfile.
ENDIF.
2009 Oct 15 10:39 PM
In 4.6, TRANSFER always adds a newline character when you open the dataset IN TEXT MODE.
As your XML variable is in a XSTRING, the easiest is to open the dataset IN BINARY MODE, and TRANSFER the xstring content (you may loop at XML_TAB without problem)
2009 Oct 15 10:39 PM
In 4.6, TRANSFER always adds a newline character when you open the dataset IN TEXT MODE.
As your XML variable is in a XSTRING, the easiest is to open the dataset IN BINARY MODE, and TRANSFER the xstring content (you may loop at XML_TAB without problem)
2009 Oct 16 2:28 PM
Thank you! Both of these suggestions pretty much solved 90% of my issue. The only thing that is left to solve is for some reason the xml file delivered to the application server contains a number of NULL characters at the end of the data. Depending on the length of the xml data appears to affect how many NULL characters are outputted, almost like it's filling the last 256 bytes of unused space with NULLs. Have you encountered this before?
Below is snippet of the code used.
types: begin of ty_xml_line,
data(256) type x,
end of ty_xml_line.
data: wa_xmlrec type ty_xml_line.
:.
open dataset v_serfile for output in binary mode.
loop at xml_tab into wa_xmlrec.
v_strlen = strlen( wa_xmlrec ).
transfer wa_xmlrec to v_serfile length v_strlen1.
endloop.
close dataset v_serfile.
2009 Oct 16 2:44 PM
When you use STRLEN (unicode check attribute unchecked) or XSTRLEN on X variables, it always give you the full length of the variable, it does not omit the trailing null bytes as they may be real bytes.
A solution to this is to use XSTRING variables, which are of variable length (unlike X variables which have a fixed length).
2009 Oct 16 3:12 PM
When I change the types from x to xstring in both the XML internal table and work area (below). I receive an error message on the ABAP syntax of the following.. I also had to remove the XSTRLEN statement as that was returning an unknown function error from the syntax check.
"L_XML_LINEX cannot be a table, a reference, a string or contain any of these objects
types: begin of xml_linex,
data type xstring,
end of xml_linex.
data: l_xml_linex type xml_linex.
data begin of xml_tab occurs 0,
d type xstring,
end of xml_tab.
:.
open dataset v_serfile for output in binary mode.
loop at xml_tab into l_xml_linex.
* v_strlen1 = xstrlen( l_xml_linex ).
transfer l_xml_linex to v_serfile.
endloop.
close dataset v_serfile.
2009 Oct 16 3:17 PM
Just do that:
types xml_linex type xstring.
data xml_tab type standard table of xml_linex with header line.
Here I indicate a header line because you maybe use it somewhere in the code, but they should not be used anymore.
2009 Oct 16 3:57 PM
Still the same result, numerous NULL characters at the end of the xml data in the delivered file. It appears to be still filling the balance of unused space with NULLs.
2009 Oct 16 4:50 PM
2009 Oct 16 5:00 PM
Sure not a problem...
types xml_linex type xstring.
data xml_tab type standard table of xml_linex with header line.
***************************************************************************
* XML Data processing
***************************************************************************
data: l_dom type ref to if_ixml_element,
m_document type ref to if_ixml_document,
g_ixml type ref to if_ixml,
w_string type xstring,
w_size type i,
w_result type i,
w_line type string,
it_xml type dcxmllines,
s_xml like line of it_xml,
w_rc like sy-subrc.
data: xml type dcxmllines.
data: rc type sy-subrc.
class cl_ixml definition load.
g_ixml = cl_ixml=>create( ).
check not g_ixml is initial.
m_document = g_ixml->create_document( ).
check not m_document is initial.
write: / 'Converting DATA TO DOM 1:'.
call function 'SDIXML_DATA_TO_DOM'
exporting
name = 'it_catalogs'
dataobject = it_catalogs[]
importing
data_as_dom = l_dom
changing
document = m_document
exceptions
illegal_name = 1
others = 2.
if sy-subrc = 0.
write 'Ok'.
else.
write: 'Err =',
sy-subrc.
endif.
check not l_dom is initial.
w_rc = m_document->append_child( new_child = l_dom ).
if w_rc is initial.
write 'Ok'.
else.
write: 'Err =',
w_rc.
endif.
call function 'SDIXML_DOM_TO_XML'
exporting
document = m_document
importing
xml_as_string = w_string
size = w_size
tables
xml_as_table = it_xml
exceptions
no_document = 1
others = 2.
if sy-subrc = 0.
write 'Ok'.
else.
write: 'Err =',
sy-subrc.
endif.
loop at it_xml into xml_tab.
append xml_tab.
endloop.
***********************************************************************************
open dataset v_serfile for output in binary mode.
loop at xml_tab.
transfer xml_tab to v_serfile.
endloop.
close dataset v_serfile.
2009 Oct 16 5:53 PM
In each loop at it_xml (table of X of 256 bytes), you transfer exactly 256 bytes to xml_tab (XSTRING, so each line of xml_tab is exactly 256 bytes, so you get incorrect length at the end.
SDIXML_DOM_TO_XML returns it_xml and w_string (type Xstring). I think w_string is the same content as it_xml it , but probably w_string is of the correct length, so just do that:
open dataset v_serfile for output in binary mode.
TRANSFER w_string TO v_serfile.
close dataset v_serfile.
2009 Oct 16 8:37 PM