1, 简介
本文介绍一下如何读取SAP application server上的excel文件,并将读取到的excel二进制流转换到SAP内表中。
主要步骤如下:
1,通过open dataset以二进制流方式读取SAP服务器上的excel文件
2,将二进制流转换为excel中的XML格式
3,通过xslt_tool将XML转换为内表
2, SAP代码
代码实现将服务器上test.xlsx中的内容读取到内表中,test.xlsx中含4列。
详细可以参见代码中的注释。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
REPORT ytest_open_dataset. DATA: gv_file(150) TYPE c. DATA: gs_upload TYPE xstring. DATA:lo_package TYPE REF TO cl_openxml_package, lo_parts TYPE REF TO cl_openxml_partcollection, lo_xml_part TYPE REF TO cl_openxml_part, lo_xml_part_uri TYPE REF TO cl_openxml_parturi. DATA:lv_uri TYPE string, lv_sheet_xstr TYPE xstring, lv_shared_str_xml TYPE xstring, lv_share_xstr TYPE xstring. DATA:lo_shared_str_dom TYPE REF TO if_ixml_document. DATA:lo_shared_str_nodeset TYPE REF TO if_ixml_node. TYPES:BEGIN OF gty_it, vbeln TYPE vbak-vbeln, vkorg TYPE vbak-vkorg, ernam TYPE vbak-ernam, vtweg TYPE vbak-vtweg, END OF gty_it. DATA:lt_vbak TYPE STANDARD TABLE OF gty_it WITH HEADER LINE. gv_file = '/tmp/test.xlsx'. "SAP application server 路径 * 使用binary 方式打开excel文件 OPEN DATASET gv_file FOR INPUT IN BINARY MODE. * 将excel文件读到xstring中,也就是二进制流 READ DATASET gv_file INTO gs_upload. IF sy-subrc = 0. TRY. lo_package = cl_xlsx_document=>load_document( iv_data = gs_upload ). CATCH cx_openxml_format cx_openxml_not_found. ENDTRY. TRY. lo_parts = lo_package->get_parts( ). CATCH cx_openxml_format cx_openxml_not_found. ENDTRY. TRY. * 读取sheet的xml lv_uri = lo_parts->get_part( 2 )->get_parts( )->get_part( 2 )->get_uri( )->get_uri( ). lo_xml_part_uri = cl_openxml_parturi=>create_from_partname( lv_uri ). lo_xml_part = lo_package->get_part_by_uri( lo_xml_part_uri ). lv_sheet_xstr = lo_xml_part->get_data( ). CATCH cx_openxml_format cx_openxml_not_found. ENDTRY. TRY. * 读取share的xml lv_uri = lo_parts->get_part( 2 )->get_parts( )->get_part( 3 )->get_uri( )->get_uri( ). lo_xml_part_uri = cl_openxml_parturi=>create_from_partname( lv_uri ). lo_xml_part = lo_package->get_part_by_uri( lo_xml_part_uri ). lv_share_xstr = lo_xml_part->get_data( ). CATCH cx_openxml_format cx_openxml_not_found. ENDTRY. ENDIF. * 将share xml中的name space删除 CALL TRANSFORMATION zxml_it_ipc SOURCE XML lv_share_xstr RESULT XML lv_shared_str_xml. * 转换成DOM CALL FUNCTION 'SDIXML_XML_TO_DOM' EXPORTING xml = lv_shared_str_xml IMPORTING document = lo_shared_str_dom EXCEPTIONS invalid_input = 1 OTHERS = 2. IF sy-subrc = 0. * 得到nodeset lo_shared_str_nodeset = lo_shared_str_dom->clone( ). ENDIF. DATA: gt_item TYPE TABLE OF zipcdata. * 使用xlst_tool转换工具将Excel xml转换到内表中 CALL TRANSFORMATION yxml_it_ipc_xls PARAMETERS p_shared_string = lo_shared_str_nodeset " OPTIONS value_handling = 'accept_data_loss' SOURCE XML lv_sheet_xstr RESULT lt_data = lt_vbak[]. CLOSE DATASET gv_file. * 输出转换后内表内容 LOOP AT lt_vbak. WRITE:/ lt_vbak-vbeln, lt_vbak-vkorg,lt_vbak-ernam,lt_vbak-vtweg. ENDLOOP. |
代码注释中的sheet xml 和share xml到底是什么,其实是可以直观看到的,将excel文件的扩展名改成压缩文件格式.zip,然后就可以在压缩文件夹中看到具体的sheet xml和share xml。
.zip中的文件夹结构如下,
在xl中可以看到share xml,
然后在worksheets中可以Excel文件中找到所有的sheet页,本例子中只有一个sheet,叫sheet1.
sharestrings.xml中保存的是excel xml节点值,也就是excel中每个cell的值
sheet1.xml中保存的是每个cell的索引值,如下 ,
1,r = “1” 标识第一行
2,spans = “1:4” 标识 总共4列
3,r = “A1” 标识第一行A单元格
4,<v>0</v> 标识index
3, XSLT_TOOL转换
程序里用到两个转换, zxml_it_ipc和 yxml_it_ipc_xls,这两个都是xslt程序的转换
zxml_it_ipc:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ss="http://schemas.openxmlformats.org/spreadsheetml/2006/main" version="1.1"> <xsl:strip-space elements="*"/> <xsl:output encoding="utf-8" indent="yes" method="xml" omit-xmldeclaration="yes"/> <xsl:template match="/"> <xsl:element name="sst" namespace=""> <xsl:for-each select="ss:sst/ss:si"> <xsl:element name="si" namespace=""> <xsl:element name="t" namespace=""> <xsl:value-of select="ss:t"/> </xsl:element> </xsl:element> </xsl:for-each> </xsl:element> </xsl:template> </xsl:stylesheet> |
转换后,删除namespace的xml如下,可以与之前截图比一下,删除的目的是为了 SDIXML_XML_TO_DOM。
yxml_it_ipc_xls:
注意:标签<VBELN><VKORG><ERNAM><VTWEG>要和内表中定义的对应的字段名字相同。
xsl:if test="position() > 1" :表示要从excel的第二行解析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ss="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:sap="http://www.sap.com/sapxsl" xmlns:asx="http://www.sap.com/abapxml" exclude-result-prefixes="c" version="1.0"> <xsl:param name="P_SHARED_STRING" select=""/> <xsl:strip-space elements="*"/> <xsl:output encoding="utf-8" indent="yes" omit-xml-declaration="yes"/> <xsl:variable name="V_SHARED_STRING"> <xsl:if test="$P_SHARED_STRING"> <xsl:copy-of select="$P_SHARED_STRING"/> </xsl:if> </xsl:variable> <xsl:template match="/"> <asx:abap version="1.0"> <asx:values> <LT_DATA> <xsl:for-each select="ss:worksheet/ss:sheetData/ss:row"> <xsl:if test="position() > 1"> <item> <VBELN> <xsl:variable name="cell_id" select="concat('A', position())"/> <xsl:variable name="v_index" select="ss:c[@r=$cell_id][@t='s']/ss:v"/> <xsl:if test="$v_index"> <xsl:value-of select="$V_SHARED_STRING/sst/si[$v_index + 1]/t"/> </xsl:if> <xsl:if test="not($v_index)"> <xsl:value-of select="ss:c[@r=$cell_id]/ss:v"/> </xsl:if> </VBELN> <VKORG> <xsl:variable name="cell_id" select="concat('B', position())"/> <xsl:variable name="v_index" select="ss:c[@r=$cell_id][@t='s']/ss:v"/> <xsl:if test="$v_index"> <xsl:value-of select="$V_SHARED_STRING/sst/si[$v_index + 1]/t"/> </xsl:if> <xsl:if test="not($v_index)"> <xsl:value-of select="ss:c[@r=$cell_id]/ss:v"/> </xsl:if> </VKORG> <ERNAM> <xsl:variable name="cell_id" select="concat('C', position())"/> <xsl:variable name="v_index" select="ss:c[@r=$cell_id][@t='s']/ss:v"/> <xsl:if test="$v_index"> <xsl:value-of select="$V_SHARED_STRING/sst/si[$v_index + 1]/t"/> </xsl:if> <xsl:if test="not($v_index)"> <xsl:value-of select="ss:c[@r=$cell_id]/ss:v"/> </xsl:if> </ERNAM> <VTWEG> <xsl:variable name="cell_id" select="concat('D', position())"/> <xsl:variable name="v_index" select="ss:c[@r=$cell_id][@t='s']/ss:v"/> <xsl:if test="$v_index"> <xsl:value-of select="$V_SHARED_STRING/sst/si[$v_index + 1]/t"/> </xsl:if> <xsl:if test="not($v_index)"> <xsl:value-of select="ss:c[@r=$cell_id]/ss:v"/> </xsl:if> </VTWEG> </item> </xsl:if> </xsl:for-each> </LT_DATA> </asx:values> </asx:abap> </xsl:template> </xsl:transform> |
4, 程序运行结果
以上。
发表评论