Application Development Blog Posts
Learn and share on deeper, cross technology development topics such as integration and connectivity, automation, cloud extensibility, developing at scale, and security.
cancel
Showing results for 
Search instead for 
Did you mean: 

Here is an example of creating  word documents from templates stored in web repository (SMW0) using wordprocessingml.

A very simple form can be done in around an hour of time.

USE CASE

    Prepare the template that needs to be filled with data.

Write the program that will fill the document.

  data: LO_FORM type ref to Z_MWL_FORM.

   data: L_TEMPLATE type STRING value 'block'.

   data: L_INDEX type I value 1.

   data: L_NUM type I.

   create object LO_FORM

     exporting

       I_TEMPLATE = 'Z_TEST'.

   LO_FORM->REPLICATE(

    I_TEMPLATE_ID = L_TEMPLATE

    I_COPY_NUM = 2

   ).

   LO_FORM->PREP_SEQ_ACCESS( ).

   if LO_FORM->FIND_VARIABLE( 'name' ) eq ABAP_TRUE.

     LO_FORM->SET_VALUE( 'Zhambyl').

   endif.

   if LO_FORM->FIND_VARIABLE( 'age' ) eq ABAP_TRUE.

     LO_FORM->SET_VALUE( '25' ).

   endif.

   if LO_FORM->FIND_VARIABLE( 'gender' ) eq ABAP_TRUE.

     LO_FORM->SET_VALUE( 'male' ).

   endif.

   do 2 times.

     if LO_FORM->FIND_BLOCK( L_INDEX ) eq ABAP_TRUE.

       if LO_FORM->FIND_VARIABLE( 'var1' ) eq ABAP_TRUE.

         LO_FORM->SET_VALUE( '1' ).

       endif.

       if LO_FORM->FIND_VARIABLE( 'var2' ) eq ABAP_TRUE.

         LO_FORM->SET_VALUE( '2' ).

       endif.

       if LO_FORM->FIND_VARIABLE( 'var3' ) eq ABAP_TRUE.

         LO_FORM->SET_VALUE( '3' ).

       endif.

     endif.

     add 1 to L_INDEX.

   enddo.

   LO_FORM->FINISH_SEQ_ACCESS( ).

   LO_FORM->CLEAN(  ).

   LO_FORM->DISPLAY( ).

Open the filled document on client machine.

Implemantaion details

class Z_MWL_FILE definition

  public

   create public .

  public section.

     data EXTENSION type STRING .

     data TEMPDIR type STRING .

     data BSTRING type XSTRING.

     methods: DOWNLOAD " download file from web repository

       importing

         VALUE(I_TEMPLATE) type STRING

          returning

         VALUE(R_SUBRC) like SY-SUBRC.

     methods GET_BSTRING " returns xstring representation of file

       returning

         VALUE(R_STRING) type XSTRING.

     methods GET_TEMP_DIR " chose file storage location

       returning

         VALUE(R_PATH) type string.

     methods SAVE_ON_FRONTEND " upload file to client

       importing

         VALUE(I_STRING) type XSTRING

       returning

         VALUE(R_SUBRC) like SY-SUBRC.

   protected section.

   private section.

ENDCLASS.

CLASS Z_MWL_FILE IMPLEMENTATION.

   method DOWNLOAD.

     data: LS_KEY type WWWDATATAB.

     data: LS_MIME type W3MIME.

     data: LT_MIME type standard table of W3MIME.

     field-symbols <LFS_DATA> type ANY.

     LS_KEY-RELID = 'MI'.

     LS_KEY-OBJID = I_TEMPLATE.

     call function 'WWWDATA_IMPORT'

       exporting

         KEY               = LS_KEY

       tables

         MIME              = LT_MIME

       exceptions

         WRONG_OBJECT_TYPE = 1

         IMPORT_ERROR      = 2

         others            = 3.

     if SY-SUBRC eq 0.

       loop at LT_MIME into LS_MIME.

         assign LS_MIME to <LFS_DATA> casting type ('X').

         if <LFS_DATA> is assigned.

           concatenate BSTRING <LFS_DATA> into BSTRING in byte mode.

           unassign <LFS_DATA>.

         endif.

       endloop.

     else.

       R_SUBRC =  SY-SUBRC.

     endif.

   endmethod.                    "DOWNLOAD

   method GET_BSTRING.

     R_STRING = BSTRING.

   endmethod.                    "GET_BSTRING

  method GET_TEMP_DIR.


     data: L_WTITLE type STRING.

     data: L_NAME type STRING.

     data: L_FPATH type STRING.

     L_WTITLE = 'CHOSE FILE STORAGE LOCATION'.

     CL_GUI_FRONTEND_SERVICES=>FILE_SAVE_DIALOG(

           exporting

             WINDOW_TITLE = L_WTITLE

             DEFAULT_EXTENSION = 'docx'

             FILE_FILTER = 'docx'

           changing

             FILENAME = L_NAME

             PATH = TEMPDIR

             FULLPATH = L_FPATH ).

     CL_GUI_CFW=>FLUSH( ).

     R_PATH = L_FPATH.

   endmethod.                    "GET_TEMP_DIR

  method SAVE_ON_FRONTEND.

     data: LV_FILE_TAB     type standard table of SOLISTI1,

           LV_BYTECOUNT    type I.

     data: L_FPATH type STRING.

     call function 'SCMS_XSTRING_TO_BINARY'

       exporting

         BUFFER        = I_STRING

       importing

         OUTPUT_LENGTH = LV_BYTECOUNT

       tables

         BINARY_TAB    = LV_FILE_TAB.

     "Save the file

     L_FPATH = GET_TEMP_DIR( ).

     if L_FPATH is not initial.

       CL_GUI_FRONTEND_SERVICES=>GUI_DOWNLOAD(

         exporting

           BIN_FILESIZE = LV_BYTECOUNT

           FILENAME     = L_FPATH

           FILETYPE     = 'BIN'

         changing

           DATA_TAB     = LV_FILE_TAB

       ).

       if SY-SUBRC ne 0.

         R_SUBRC = SY-SUBRC.

       endif.

     else.

       R_SUBRC = 2.

     endif.

  endmethod.                    "SAVE_ON_FRONTEND

ENDCLASS.


Secondly we create main class that is used to manipulate the word document.

This class relies on classes found in packages: S_OOXML_CORE, SXML and XSLT transformations.

class Z_MWL_FORM definition

   public

   create public .

   public section.

     data: MAIN_PART type XSTRING .

     data: DOCUMENT type XSTRING .

     data: INTRM_PART type XSTRING .

     data: FINAL_DOC type XSTRING.

     methods CONSTRUCTOR importing I_TEMPLATE type STRING. " Finds the main part of word document from zip pakcage container and

                                                                                                    " stores it. I_TEMPLATE is the logical name of the file in smw0

    methods DISPLAY.                     " This method packages updated main part and uploads it to front-end. Dont mind the name.

     methods REPLICATE                  " Replicates marked block of text using transformations and substitues standard markups for custom ones

      importing I_TEMPLATE_ID type STRING

                I_COPY_NUM type I.

     methods: FIND_VARIABLE  " Finds tag named variable using sxml. I_var is a value for name attribute of this tag.

               importing I_VAR type STRING

              returning VALUE(RV_FOUND) type ABAP_BOOL.

     methods: FIND_BLOCK importing I_BLOCK type           " Finds tag named block using sxml. I_block is a value for number attribute of this tag.

              returning VALUE(RV_FOUND) type ABAP_BOOL.     " Block contains several variables that can be copyed with different block numbers

    methods: SET_VALUE importing I_VAL type STRING.      " Replaces value of placeholder variable

     methods: PREP_SEQ_ACCESS.    " Converts xstring to Xml objects and prepares them for sequencial access

     methods: FINISH_SEQ_ACCESS.  " Converts from sXML back to xstring representation

     methods CLEAN.                           " Clear's all the custom mark up from main part of word document

   protected section.

     data: O_FILE               type ref to ZCL_ZK_MWL_FILE.

     data: O_DOC               type ref to CL_DOCX_DOCUMENT.

     data: O_DOCUMENTPART       type ref to CL_DOCX_MAINDOCUMENTPART.

     data: O_SREADER type ref to IF_SXML_READER.

     data: O_SWRITER type ref to IF_SXML_WRITER.

     data: O_SNODE  type ref to IF_SXML_NODE.

     data: O_SVALUE_NODE  type ref to IF_SXML_VALUE_NODE.

   private section.

ENDCLASS.

CLASS Z_MWL_FORM IMPLEMENTATION.

   method CLEAN.

     if INTRM_PART is not initial.

       call transformation Z_CLEAN

       source xml INTRM_PART

       result xml FINAL_DOC.

     endif.

   endmethod.                    "CLEAN

   method CONSTRUCTOR.

     create object O_FILE.

     O_FILE->DOWNLOAD( I_TEMPLATE ).

     DOCUMENT = O_FILE->GET_BSTRING( ).

     try.

         O_DOC = CL_DOCX_DOCUMENT=>LOAD_DOCUMENT( IV_DATA = DOCUMENT ).

* get the maindocument part

         O_DOCUMENTPART = O_DOC->GET_MAINDOCUMENTPART( ).

         MAIN_PART = O_DOCUMENTPART->GET_DATA( ).

       catch CX_OPENXML_FORMAT.

       catch CX_OPENXML_NOT_ALLOWED.

       catch CX_OPENXML_NOT_FOUND.

       catch CX_TRANSFORMATION_ERROR.

     endtry.

   endmethod.                    "constructor

   method DISPLAY.

     if FINAL_DOC is not initial.

       O_DOCUMENTPART->FEED_DATA( FINAL_DOC ).

     elseif MAIN_PART is not initial.

       O_DOCUMENTPART->FEED_DATA( MAIN_PART ).

     endif.

     FINAL_DOC = O_DOC->GET_PACKAGE_DATA( ).

     if O_FILE->SAVE_ON_FRONTEND( FINAL_DOC ) ne 0.

       message 'Выгрузка отменена' type 'S'.

     endif.

   endmethod.                    "Display

   method FIND_BLOCK.

     data: LX_ROOT type ref to CX_SXML_ERROR.

     data: LO_OPELEM type ref to IF_SXML_OPEN_ELEMENT.

     data: L_AT_VAL type ref to IF_SXML_VALUE.

     data: L_VAL type STRING.

     if O_SREADER is bound and O_SWRITER is bound.

       while RV_FOUND ne ABAP_TRUE.

         try.

             O_SNODE = O_SREADER->READ_NEXT_NODE( ).

             if O_SNODE is initial.

               exit.

             endif.

             if O_SNODE->TYPE eq IF_SXML_NODE=>CO_NT_ELEMENT_OPEN.

               LO_OPELEM ?= O_SNODE.

               if LO_OPELEM->IF_SXML_NAMED~QNAME-NAME eq 'block'.

                 L_AT_VAL = LO_OPELEM->GET_ATTRIBUTE_VALUE( 'num' ).

                 L_VAL = L_AT_VAL->GET_VALUE( ).

                 if L_VAL eq I_BLOCK.

                   RV_FOUND = ABAP_TRUE.

                 endif.

               endif.

             endif.

             O_SWRITER->WRITE_NODE( O_SNODE ).

           catch CX_SXML_ERROR into LX_ROOT.

             exit.

         endtry.

       endwhile.

     endif.

   endmethod.                    "FIND_BLOCK

   method FIND_VARIABLE.

     data: LX_ROOT type ref to CX_SXML_ERROR.

     data: LO_OPELEM type ref to IF_SXML_OPEN_ELEMENT.

     data: L_AT_VAL type ref to IF_SXML_VALUE.

     data: L_VAL type STRING.

     if O_SREADER is bound and O_SWRITER is bound.

       while RV_FOUND ne ABAP_TRUE.

         try.

             O_SNODE = O_SREADER->READ_NEXT_NODE( ).

             if O_SNODE is initial.

               exit.

             endif.

             if O_SNODE->TYPE eq IF_SXML_NODE=>CO_NT_ELEMENT_OPEN.

               LO_OPELEM ?= O_SNODE.

               if LO_OPELEM->IF_SXML_NAMED~QNAME-NAME eq 'variable'.

                 L_AT_VAL = LO_OPELEM->GET_ATTRIBUTE_VALUE( 'mark' ).

                 L_VAL = L_AT_VAL->GET_VALUE( ).

                 if L_VAL eq I_VAR.

                   RV_FOUND = ABAP_TRUE.

                 endif.

               endif.

             endif.

             O_SWRITER->WRITE_NODE( O_SNODE ).

           catch CX_SXML_ERROR into LX_ROOT.

             exit.

         endtry.

       endwhile.

       clear RV_FOUND.

       while RV_FOUND ne ABAP_TRUE.

         try.

             O_SNODE = O_SREADER->READ_NEXT_NODE( ).

             if O_SNODE is initial.

               exit.

             endif.

             if O_SNODE->TYPE eq IF_SXML_NODE=>CO_NT_ELEMENT_OPEN.

               LO_OPELEM ?= O_SNODE.

               if LO_OPELEM->IF_SXML_NAMED~QNAME-NAME eq 't'.

                 RV_FOUND = ABAP_TRUE.

               endif.

             endif.

             O_SWRITER->WRITE_NODE( O_SNODE ).

           catch CX_SXML_ERROR into LX_ROOT.

             exit.

         endtry.

       endwhile.

       clear RV_FOUND.

       while RV_FOUND ne ABAP_TRUE.

         try.

             O_SNODE = O_SREADER->READ_NEXT_NODE( ).

             if O_SNODE is initial.

               exit.

             endif.

             if O_SNODE->TYPE eq IF_SXML_NODE=>CO_NT_VALUE.

               O_SVALUE_NODE ?= O_SNODE.

               RV_FOUND = ABAP_TRUE.

               exit.

             endif.

             O_SWRITER->WRITE_NODE( O_SNODE ).

           catch CX_SXML_ERROR into LX_ROOT.

             exit.

         endtry.

       endwhile.

     endif.

   endmethod.                    "FIND_VARIABLE

   method FINISH_SEQ_ACCESS.

     data: LX_ROOT type ref to CX_SXML_ERROR.

     data: LO_WRITER type ref to CL_SXML_STRING_WRITER.

     if O_SREADER is not initial and O_SWRITER is bound.

       do.

         try.

             O_SNODE = O_SREADER->READ_NEXT_NODE( ).

             if O_SNODE is initial.

               exit.

             endif.

             O_SWRITER->WRITE_NODE( O_SNODE ).

           catch CX_SXML_ERROR into LX_ROOT.

             exit.

         endtry.

       enddo.

       try.

           LO_WRITER ?= O_SWRITER.

           INTRM_PART = LO_WRITER->GET_OUTPUT( ).

         catch CX_SXML_ERROR into LX_ROOT.

           exit.

       endtry.

     endif.

   endmethod.                    "FINISH_SEQ_ACCESS

   method PREP_SEQ_ACCESS.

     if INTRM_PART is not initial.

       O_SREADER ?= CL_SXML_STRING_READER=>CREATE( INTRM_PART ).

       O_SWRITER ?= CL_SXML_STRING_WRITER=>CREATE( ).

     endif.

   endmethod.                    "prep_seq_access

   method REPLICATE.


     if INTRM_PART is initial.

       call transformation Z_REPLICATE

       source xml MAIN_PART

       result xml INTRM_PART

       parameters TEMPLATE_ID = I_TEMPLATE_ID

                  COPY_NUM = I_COPY_NUM.

     else.

       call transformation Z_REPLICATE

       source xml INTRM_PART

       result xml INTRM_PART

       parameters TEMPLATE_ID = I_TEMPLATE_ID

                  COPY_NUM = I_COPY_NUM.

     endif.

   endmethod.                    "replicate

  method  SET_VALUE.

     data: LX_ROOT type ref to CX_SXML_ERROR.

     data: L_XSTRING type XSTRING.

*  L_XSTRING = CL_ABAP_CODEPAGE=>CONVERT_TO( I_VAL ).

     if O_SVALUE_NODE is bound and O_SWRITER is bound.

       try.

           O_SVALUE_NODE->IF_SXML_VALUE~SET_VALUE( I_VAL ).

           O_SWRITER->WRITE_NODE( O_SNODE ).

         catch CX_SXML_ERROR into LX_ROOT.

           exit.

       endtry.

     endif.

  endmethod.                    "set_value

ENDCLASS.


Following are the transformations used in the class described above.


Transformation z_replicate



<xsl:transformxmlns:xsl="http://www.w3.org/1999/XSL/Transform"xmlns:sap="http://www.sap.com/sapxsl"xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" version="1.0">
   <xsl:output encoding="UTF-8" indent="yes" method="xml" omit-xml-declaration="no" standalone="yes"/>
   <xsl:param name="TEMPLATE_ID"/>
   <xsl:param name="COPY_NUM" sap:type="number"/>
   <xsl:template match="node()|@*">
     <xsl:copy>
       <xsl:apply-templates select="node()|@*"/>
     </xsl:copy>
   </xsl:template>
   <xsl:template match="w:sdt">
     <xsl:choose>
       <xsl:when test="descendant::w:tag[@w:val=$TEMPLATE_ID]">
         <xsl:call-template name="multiply">
           <xsl:with-param name="maxCount" select="$COPY_NUM"/>
           <xsl:with-param name="nodeToCopy" select="."/>
         </xsl:call-template>
       </xsl:when>
       <xsl:otherwise>
         <xsl:element name="variable">
           <xsl:attribute name="mark">
             <xsl:value-of select="descendant::w:tag/@w:val"/>
           </xsl:attribute>
           <xsl:apply-templates select="w:sdtContent/node()|@*" mode="variable"/>
         </xsl:element>
       </xsl:otherwise>
     </xsl:choose>
   </xsl:template>
   <xsl:template name="multiply">
     <xsl:param name="maxCount"/>
     <xsl:param name="i" select="1"/>
     <xsl:param name="nodeToCopy"/>
     <xsl:choose>
       <xsl:when test="$i &lt;= $maxCount">
         <xsl:element name="block">
           <xsl:attribute name="num">
             <xsl:value-of select="$i"/>
           </xsl:attribute>
           <!--          <xsl:copy-of select="$nodeToCopy/w:sdtContent/node()|@*"/>-->
           <xsl:apply-templates select="$nodeToCopy/w:sdtContent/node()|@*"/>
         </xsl:element>
         <xsl:call-template name="multiply">
           <xsl:with-param name="maxCount" select="$maxCount"/>
           <xsl:with-param name="nodeToCopy" select="$nodeToCopy"/>
           <xsl:with-param name="i" select="$i+1"/>
         </xsl:call-template>
       </xsl:when>
       <xsl:otherwise/>
     </xsl:choose>
   </xsl:template>
   <xsl:template match="node()|@*" mode="variable">
     <xsl:copy>
       <xsl:apply-templates select="node()|@*" mode="variable"/>
     </xsl:copy>
   </xsl:template>
   <xsl:template match="w:sdtContent/w:r[1]" mode="variable">
     <xsl:copy>
        <xsl:apply-templates select="node()|@*" mode="variable"/>
     </xsl:copy>
   </xsl:template>
    <xsl:template match="w:sdtContent/w:r[position() != 1]" mode="variable">
   </xsl:template>
</xsl:transform>



Transformation z_clean


<xsl:transformxmlns:xsl="http://www.w3.org/1999/XSL/Transform"xmlns:sap="http://www.sap.com/sapxsl"xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" version="1.0">
   <xsl:output encoding="UTF-8" indent="yes" method="xml" omit-xml-declaration="no" standalone="yes"/>
   <xsl:template match="node()|@*">
     <xsl:copy>
       <xsl:apply-templates select="node()|@*"/>
     </xsl:copy>
   </xsl:template>
   <xsl:template match="variable">
       <xsl:apply-templates select="node()|@*"/>
   </xsl:template>
   <xsl:template match="block">
       <xsl:apply-templates select="node()|@*"/>
   </xsl:template>
</xsl:transform>




3 Comments