乐于分享
好东西不私藏

不用 OLE、不用前端 Word纯 ABAP 生成

不用 OLE、不用前端 Word纯 ABAP 生成

不用 OLE、不用前端 Word

纯 ABAP 生成 

 配套示例 ZDEMO_ABAP2DOCX

一、起因

做 SAP 每日巡检报告,最终交付物客户要 Word。

第一版的路子是:ABAP 导出 CSV → 人工/AI 转 Word。跑通了,但很快就发现不对劲:

· 多一道人工,没法进后台作业自动发;

· CSV 里没有的字段(Kernel 版本、Basis SP),转出来的 Word 就是空格子;

· 格式每次都得重调,不稳定。

于是回到根上:能不能让 ABAP 直接吐 Word?

二、几条路的取舍

方案

能用吗

问题

OLE 自动化(CALL METHOD OF)

前端必须装 Word;慢;后台作业彻底没戏

DOI(Desktop Office Integration)

同样依赖前端 Office,控件老旧

Smart Forms / Adobe Forms

只出 PDF,不是 Word

HTML 存成 .doc

最省事,但不是真 docx,Word 会弹「格式与扩展名不符」

OOXML + CL_ABAP_ZIP

纯后台,无依赖,产出真 .docx

最后一条是正解。理由很简单——后台作业跑不了任何前端东西。只要你想定时发邮件,OLE / DOI / GUI_DOWNLOAD 这些全部出局。

三、.docx 到底是什么

一句话:.docx 就是个 zip,里面装 XML。

把任意一个 .docx 改名成 .zip 解开,你会看到一堆文件。但最小可用的骨架只要三个:

[Content_Types].xml声明包里有哪些类型的部件

_rels/.rels包级关系:告诉 Word「主文档是谁」

word/document.xml正文(WordprocessingML)

真的只要三个。styles.xmlfontTable.xmltheme1.xml 全都可以不要——只要你把格式写成内联属性。

[Content_Types].xml

     <Default              </DefaultExtension=”rels”

ContentType=”application/vnd.openxmlformats-package.relationships+xml”/>

     <Default              </DefaultExtension=”xml” ContentType=”application/xml”/>

     <Override              </OverridePartName=”/word/document.xml”

ContentType=”application/vnd.openxmlformats-officedocument

.wordprocessingml.document.main+xml”/>

_rels/.rels

     <Relationship              </RelationshipId=”rId1″

Type=”http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument”

Target=”word/document.xml”/>

这两个文件是死的,照抄即可。所有活儿都在 document.xml

四、WordprocessingML 速成

只要记住四个标签,就能写 90% 的报告:

w:p段落(paragraph)

w:r文本块(run)—— 一个段落里格式相同的一截

w:t真正的文字(text)

w:tbl表格 → w:tr 行 → w:tc 单元格

嵌套关系是固定的:段落套 run,run 套 text

一个加粗深蓝、10.5pt 的段落:

     <w:rFonts              </w:rFontsw:ascii=”Microsoft YaHei” w:eastAsia=”Microsoft YaHei”/>

     <w:color              </w:colorw:val=”1F4E79″/>

     <w:sz              </w:szw:val=”21″/>

     <w:t              </w:txml:space=”preserve”>一、系统概览

一个带底纹的单元格:

     <w:tcW              </w:tcWw:w=”1400″ w:type=”dxa”/>

     <w:shd              </w:shdw:val=”clear” w:color=”auto” w:fill=”FFC7CE”/>

     <w:vAlign              </w:vAlignw:val=”center”/>

错误

单位速记

· twip:1 pt = 20 twip,1 cm ≈ 567 twip。表格宽度、页边距用它。

· 半磅:w:sz 用半磅。10.5pt 写 21,16pt 写 32。第一次用必踩。

· A4:纵向 w:w=”11906″ w:h=”16838″;横向把两个数对调,再加 w:orient=”landscape”。

五、四个坑(都是我真踩过的)

坑 1:w:tblGrid 不能省 ⚠

这个是最坑的。表格必须在之后声明列网格:

     <w:gridCol              </w:gridColw:w=”1200″/>

     <w:gridCol              </w:gridColw:w=”4000″/>

     <w:gridCol              </w:gridColw:w=”1400″/>

不写会怎样?我第一版就没写,Word 打开提示「文档需要修复」。用 python-docx 校验直接抛:

InvalidXmlError: requiredchild element not present

gridCol 的个数和宽度必须跟实际单元格对得上,否则列宽会乱。

坑 2:XML 转义,且 & 必须第一个换

巡检的「检查条件」里全是 > 和 <:CPU<80%=Normal;>90%=Error。不转义,Word 直接打不开。

REPLACE ALL OCCURRENCES OF ‘&’ IN rv WITH ‘&’.” 必须第一个

REPLACE ALL OCCURRENCES OF ‘<‘ IN rv WITH ‘<‘.

REPLACE ALL OCCURRENCES OF ‘>’ IN rv WITH ‘>’.

顺序反了的话,先换出来的 < 会被后面的 & 规则再转成 &lt;,页面上就显示成 < 了。

坑 3:中文字体要设 w:eastAsia

只设 w:ascii 中文不生效,会掉回默认宋体。三个都写上:

坑 4:必须 UTF-8

XML 声明写的是 encoding=”UTF-8″,那 xstring 就必须真的是 UTF-8,不能用系统默认代码页:

DATA lo TYPE REF TO cl_abap_conv_out_ce.

lo = cl_abap_conv_out_ce=>create( encoding = ‘UTF-8’ ).

lo->convert( EXPORTING data = iv IMPORTING buffer = rv ).

另外每个至少要有一个

,空单元格也得给个空段落,否则同样报「需要修复」。

六、打包:CL_ABAP_ZIP

到这一步就没难度了:

DATA lo_zip TYPE REF TO cl_abap_zip.

CREATE OBJECT lo_zip.

lo_zip->add( name = ‘[Content_Types].xml’ content = s2x( lv_ct) ).

lo_zip->add( name = ‘_rels/.rels’content = s2x( lv_rel ) ).

lo_zip->add( name = ‘word/document.xml’content = s2x( lv_doc ) ).

rv_x = lo_zip->save( ).” → xstring,这就是 .docx 了

拿到 xstring 之后,三种出口随便挑:

” 出口 1:前台下载

CALL FUNCTION ‘SCMS_XSTRING_TO_BINARY’

EXPORTINGbuffer=lv_x

IMPORTINGoutput_length= lv_len

TABLESbinary_tab=lt_bin.

cl_gui_frontend_services=>gui_download(

EXPORTINGbin_filesize = lv_len filename = lv_path filetype = ‘BIN’

CHANGINGdata_tab=lt_bin ).

” 出口 2:邮件附件(后台作业走这条)

lo_doc->add_attachment( i_attachment_type= ‘BIN’

i_attachment_subject= ‘巡检报告’

i_att_content_hex=lt_bin

i_attachment_header=lt_head” &SO_FILENAME=xxx.docx

i_attachment_size=lv_size ).

” 出口 3:存服务器

OPEN DATASET lv_srv FOR OUTPUT IN BINARY MODE.

TRANSFER lv_x TO lv_srv.

CLOSE DATASET lv_srv.

关键点:整条链路没有一处碰前端。所以 SM36 排个定时作业,每天早上自动生成 Word 发邮件,完全没问题。

七、封装成类

实战里别裸拼 XML,封一层就好用了:

CLASS lcl_docx DEFINITION.

PUBLICSECTION.

METHODSparaIMPORTING iv_txt TYPE string iv_sz TYPE i DEFAULT 21

iv_boldTYPE abap_bool DEFAULT abap_false

iv_colorTYPE string DEFAULT ‘000000’.

METHODStbl_begin IMPORTING it_w TYPE tt_i.” 传列宽 → 自动生成 tblGrid

METHODSrow_begin.

METHODScellIMPORTING iv_txt TYPE string iv_w TYPE i

iv_fillTYPE string DEFAULT ‘FFFFFF’

iv_boldTYPE abap_bool DEFAULT abap_false.

METHODSrow_end.

METHODStbl_end.

METHODSsaveRETURNING VALUE(rv_x) TYPE xstring.

PRIVATESECTION.

DATAmv_body TYPE string.” 只是个字符串缓冲

METHODSesc IMPORTING iv TYPE string RETURNING VALUE(rv) TYPE string.

METHODSs2x IMPORTING iv TYPE string RETURNING VALUE(rv) TYPE xstring.

ENDCLASS.

调用起来就跟写文档一样自然:

lo->para( iv_txt = ‘ABAP 直接生成 Word 演示’ iv_sz = 36

iv_bold= abap_true iv_color = ‘1F4E79’ ).

lo->tbl_begin( lt_w ).

lo->row_begin( ).

lo->cell( iv_txt = ‘ST22’ iv_w = 1200 ).

lo->cell( iv_txt = ‘ABAP Dump 检查’ iv_w = 4000 ).

lo->cell( iv_txt = ‘警告’ iv_w = 1400 iv_fill = ‘FFEB9C’ iv_bold = abap_true ).

lo->row_end( ).

lo->tbl_end( ).

lv_x = lo->save( ).

注意:mv_body 用 && 拼,不要用 CONCATENATE——CONCATENATE 的操作数不允许写方法调用,&& 可以。这个我也踩过,报的还是个很误导的错(「cannot be created as FOR TESTING」,其实是符号解析不到)。

八、怎么验证

别等到 Word 里才发现「文档需要修复」。两个笨办法很管用:

1. 改名成 .zip 解开,看三个文件在不在、XML 是否 well-formed;

2. 拿 python-docx 打开一遍——它比 Word 严格得多,Word 会容错自动修复的东西(比如缺 tblGrid),python-docx 会直接抛异常。我那个 tblGrid 的坑就是这么揪出来的:

import docx

d = docx.Document(‘demo.docx’)

print([p.text for p in d.paragraphs])

for t in d.tables:

print(len(t.rows),‘x’, len(t.columns))

能过 python-docx,Word 基本就稳了。

九、小结

· .docx = zip + XML,三个文件起步,CL_ABAP_ZIP 一把梭;

· 记住 w:p / w:r / w:t / w:tbl,单位是 twip 和半磅;

· 四个坑:tblGrid 必须有、& 先转义、中文设 eastAsia、必须 UTF-8;

· 最大价值:全程不碰前端,后台作业能自动生成+发邮件,这是 OLE/DOI 给不了的。

配套示例见 ZDEMO_ABAP2DOCX,一百多行、可直接激活运行,生成一份带标题、表格、状态底纹的 Word。

zdemo_abap2docx