我在从事 SAP document builder 开发时,曾经遇到一个客户需求,将 word control 里的 word 文档,设置成 read-only,也就是说,浏览器里 word 界面的工具栏上的所有按钮,状态应该设置为 disabled
实现这个需求的关键在于这个叫做 enableReadWrite
的 checkbox:
如果上传的文档是只读的,那么工具栏肯定会被禁用。所以这个需求就变成了,如何在上传过程中将文档标记为只读。
自 Word 2007 起,MS Office 的格式遵循所谓的 open office 协议。Open Office 协议指的是一系列开放办公室软件领域的协议和标准,这些协议和标准的制定旨在促进不同办公软件之间的互操作性和数据交换。这样的努力旨在打破不同厂商之间的软件壁垒,使用户能够在不同的办公软件中无缝地共享和编辑文档、电子表格、演示文稿等办公文件。
Open Office 协议通常关注文件格式和数据交换的规范,以确保各种办公软件之间能够正确理解和处理文件。
从 Word 2013 开始,微软的 Word 文档也加入了 Open Office 的大家庭。
如果将文件类型扩展名从.docx更改为.zip并用WinRAR打开它,会发现该文档实际上是多个单个文件的捆绑包(SAP内部称为文档部分)。
可编辑性在文件 settings.xml 中控制。
现在任务非常简单,只需将必要的 xml 标签添加到文档源代码中即可。
不需要手动解析文档源代码,因为 SAP 已经完成了这项工作。
可以重复使用标准类 CL_DOCX_DOCUMENT。
由于我需要在 settings
节点中插入文档保护节点,因此为此编写了一个简单的转换。
问题的突破口在于第 18 行和第 21 行之间。
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:sl="http://schemas.openxmlformats.org/schemaLibrary/2006/main" mc:Ignorable="w14" version="1.0"> <xsl:output encoding="UTF-8" indent="no" method="xml" omit-xml-declaration="no" version="1.0"/> <!-- Match everything all nodes and attributes --> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <xsl:template match="w:settings"> <xsl:element name="w:settings"> <xsl:for-each select="@*"> <xsl:copy/> </xsl:for-each> <xsl:element name="w:documentProtection"> <xsl:attribute name="w:edit">readOnly</xsl:attribute> <xsl:attribute name="w:enforcement">1</xsl:attribute> </xsl:element> <xsl:copy-of select="./*"/> </xsl:element> </xsl:template> </xsl:stylesheet>
寻找一个合适的地方来调用 ABAP transformation:
DATA: lr_element TYPE REF TO if_wd_context_element, lv_file_data TYPE xstring, lv_ret TYPE i, lx_temp TYPE xstring, lv_msg TYPE string, lt_parms TYPE /ipro/tt_key_value_pair, ls_parm LIKE LINE OF lt_parms. lr_element = me->wd_context->get_element( ). CHECK lr_element IS NOT INITIAL. lr_element->get_attribute( EXPORTING name = 'BINARY' IMPORTING value = lv_file_data ). DATA(lo_docx) = cl_docx_document=>load_document( lv_file_data ). DATA(lo_main_part) = lo_docx->get_maindocumentpart( ). DATA(lo_docx_settings) = lo_main_part->get_documentsettingspart( ). DATA(lx_settings) = lo_docx_settings->get_data( ). /ipro/cl_docx_utilities=>transform( EXPORTING iv_input_xstring = lx_settings iv_transform_name = '/IPRO/DOCXCC_PROTECT' it_parameters = lt_parms IMPORTING ev_result = lx_temp ev_ret = lv_ret ev_message = lv_msg ). lo_docx_settings->feed_data( lx_temp ). DATA(lx_docx_package) = lo_docx->get_package_data( ). lr_element->set_attribute( EXPORTING name = 'BINARY' value = lx_docx_package ).
上面的代码执行完毕之后,就能在 settings.xml
里看见 flag 了:
下面是实现好的效果。在 word 文档上传之前,word control 里工具栏所有的按钮,都是可用状态:
上传之后,我们之前介绍的 ABAP 代码生效了,文档变为了 readonly 状态: