1

一个 Excel 文件 ( .xlsx) 被上传到 UI5 Fiori 的前端。

文件内容通过 ODATA 以 XSTRING 格式到达 SAP ABAP 后端。

我需要将该 XSTRING 存储到内部表中,然后存储到 DDIC 表中。例如:假设 Excel 有 5 列,那么我想将 5 列的数据存储在 DDIC 表的相应列中。

我尝试过各种功能模块,例如:

  • SCMS_XSTRING_TO_BINARY
  • SCMS_BINARY_TO_STRING

以及以下类和方法

  • cl_bcs_convert=>raw_to_string
  • cl_soap_xml_helper=>xstring_to_string

但没有人能够将 XSTRING 转换为 STRING。

您能否建议可以使用哪个功能模块或类/方法来解决问题?

4

2 回答 2

2

为了获得最大的舒适度,请使用abap2xlsx

如果您不能或不想使用它,您也可以自己解析 Excel 文件。.xlsx 文件基本上是具有不同文件结尾的 .zip 文件。用于cl_abap_zip->load打开xstring您收到->get的文件并从 zip 中提取单个文件。之后,使用 XML 解析器cl_ixml或转换来解析文件的 XML 内容。

请注意,Excel 的 XML 是一种复杂的文件格式,由多个文件共同构成工作表。有关详细信息,请参阅 Microsoft 的Word、Excel 和 PowerPoint 文件格式参考。解释这一点并非易事,因此您通常会对 abap2xlsx 更满意。

于 2020-04-23T14:37:08.720 回答
0

abap2xlsx 是最强大和功能最丰富的方式,正如 Florian 所说,它支持样式、图表、复杂表格,但是由于系统限制、在系统中安装自定义包的限制或其他原因,它可能并不总是可用.

这是如何在不使用自定义框架的情况下使用纯标准来完成此任务的方法。

由于 Netweaver 7.02 SAP 原生支持 Open Microsoft 格式并提供处理它们的类:和CL_XLSX_DOCUMENT,abap2xlsx 也是在这些类中构建的,是的。因此,让我们开始重新发明轮子。CL_DOCX_DOCUMENTCL_PPTX_DOCUMENT

XLSX 文件是文件的 OpenXML 存档,其中最有趣的是:sheet1.xmlsharedStrings.xml. 让我们基于MARC表字段构建一个示例

在此处输入图像描述

现在您想将此表转移到具有相同结构的内部表。步骤是:

  1. 从 XLSX 存档中提取所需文件
  2. 读取工作表结构sheet1.xml
  3. 读取工作表值sharedStrings.xml
  4. 将它们映射在一起并将结果写入内部表

这是处理工作的示例类,我使用cl_openxml_helper小程序加载 XLSX,但您可以通过任何方式接收 XSTRINGed XLSX。

CLASS xlsx_reader DEFINITION.
  PUBLIC SECTION.

    TYPES: BEGIN OF ty_marc,
             matnr TYPE char20,
             werks TYPE char20,
             disls TYPE char20,
             ekgrp TYPE char20,
             dismm TYPE char20,
           END OF ty_marc,
           tt_marc TYPE STANDARD TABLE OF ty_marc WITH EMPTY KEY.

    METHODS: read RETURNING VALUE(tab) TYPE tt_marc,
             extract_xml IMPORTING index   TYPE i
                                   xstring TYPE xstring
             RETURNING VALUE(rv_xml_data)  TYPE xstring.
ENDCLASS.

CLASS xlsx_reader IMPLEMENTATION.
  METHOD read.
    TYPES: BEGIN OF ty_row,
                 value TYPE string,
                 index TYPE abap_bool,
               END OF ty_row,
               BEGIN OF ty_worksheet,
                 row_id TYPE i,
                 row    TYPE TABLE OF ty_row WITH EMPTY KEY,
               END OF ty_worksheet,
               BEGIN OF ty_si,
                 t TYPE string,
               END OF ty_si.

    DATA: data  TYPE TABLE OF ty_si,
          sheet TYPE TABLE OF ty_worksheet.

    TRY.
        DATA(xstring_xlsx)  = cl_openxml_helper=>load_local_file( 'C:\marc.xlsx' ).
      CATCH cx_openxml_not_found.
    ENDTRY.

    "Read the sheet XML
    DATA(xml_sheet) = extract_xml( EXPORTING xstring = xstring_xlsx iv_xml_index = 2 ).
    "Read the data XML
    DATA(xml_data)  = extract_xml( EXPORTING xstring = xstring_xlsx iv_xml_index = 3 ).

    TRY.
* transforming structure into ABAP
        CALL TRANSFORMATION zsheet
          SOURCE XML xml_sheet
          RESULT root = sheet.
* transforming data into ABAP
        CALL TRANSFORMATION zxlsx_data
          SOURCE XML xml_data
          RESULT root = data.

      CATCH cx_xslt_exception.
      CATCH cx_st_match_element.
      CATCH cx_st_ref_access.
    ENDTRY.
* mapping structure and data
    LOOP AT sheet ASSIGNING FIELD-SYMBOL(<fs_row>).
      APPEND INITIAL LINE TO tab ASSIGNING FIELD-SYMBOL(<line>).
      LOOP AT <fs_row>-row ASSIGNING FIELD-SYMBOL(<fs_cell>).
        ASSIGN COMPONENT sy-tabix OF STRUCTURE <line> TO FIELD-SYMBOL(<fs_field>).
        CHECK sy-subrc = 0.
        <fs_field> = COND #( WHEN <fs_cell>-index = abap_false THEN <fs_cell>-value ELSE VALUE #( data[ <fs_cell>-value + 1 ]-t OPTIONAL ) ).
      ENDLOOP.
    ENDLOOP.
  ENDMETHOD.

  METHOD extract_xml.
    TRY.
        DATA(lo_package) = cl_xlsx_document=>load_document( iv_data = xstring ).
        DATA(lo_parts)      = lo_package->get_parts( ).
        CHECK lo_parts IS BOUND AND lo_package IS BOUND.
        DATA(lv_uri) = lo_parts->get_part( 2 )->get_parts( )->get_part( index )->get_uri( )->get_uri( ).
        DATA(lo_xml_part)     = lo_package->get_part_by_uri( cl_openxml_parturi=>create_from_partname( lv_uri ) ).
        rv_xml_data     = lo_xml_part->get_data( ).
      CATCH cx_openxml_format cx_openxml_not_found.
    ENDTRY.
  ENDMETHOD.
ENDCLASS.

zsheet转换:

<?sap.transform simple?>
<tt:transform xmlns:tt="http://www.sap.com/transformation-templates" template="main">
  <tt:root name="root"/>
  <tt:template name="main">
    <worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:x14ac=
"http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac" xmlns:xr="http://schemas.microsoft.com/office/spreadsheetml/2014/revision" xmlns:xr2="http://schemas.microsoft.com/office/spreadsheetml/2015/revision2" xmlns:xr3=
"http://schemas.microsoft.com/office/spreadsheetml/2016/revision3">
      <tt:skip count="4"/>
      <sheetData>
        <tt:loop name="row" ref="root">
          <row>
            <tt:attribute name="r" value-ref="row_id"/>
            <tt:loop name="cells" ref="$row.ROW">
              <c>
                <tt:cond><tt:attribute name="t" value-ref="index"/><tt:assign to-ref="index" val="C('X')"/></tt:cond>
                <v><tt:value ref="value"/></v>
              </c>
            </tt:loop>
          </row>
        </tt:loop>
      </sheetData>
      <tt:skip count="2"/>
    </worksheet>
  </tt:template>
</tt:transform>

zxlsx _data转换

<?sap.transform simple?>
<tt:transform xmlns:tt="http://www.sap.com/transformation-templates" template="main">
  <tt:root name="ROOT"/>
  <tt:template name="main">
      <sst xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
        <tt:loop name="line" ref=".ROOT">
          <si>
            <t>
              <tt:value ref="t"/>
            </t>
          </si>
        </tt:loop>
      </sst>
  </tt:template>
</tt:transform>

以下是如何调用它:

START-OF-SELECTION.

  DATA(reader) = NEW xlsx_reader( ).
  DATA(marc)   = reader->read( ).

在此处输入图像描述

代码非常不言自明,但让我们做一些说明:

  • 文件在每个单元格中都sheet1.xml包含一个特殊属性t,该属性表示该值应被视为文字或对sharedStrings.xml
  • 我使用了两个简单的转换,但也可以使用 XSLT,可能允许您将所有 XML 内容简化为单个转换
  • 我故意使用泛型char20类型来处理标题。如果您想保留本机类型,则无法读取表头(跳过sheetLOOP 中的第一行),因为您将收到类型冲突并转储。如果您收到没有标题的表格,那么可以使用本机类型声明结构
  • 如果您不想使用转换,那么sXML是您的朋友。您也可以使用类解析 XML,但 ST 转换要快得多
  • 通过一些额外的努力,您可以使这个片段动态并解析具有任何结构的 XLSX

您可以在此文档中阅读有关此方法的更多信息。

于 2020-06-27T10:42:00.383 回答