Quantcast
Channel: ABAP Development
Viewing all articles
Browse latest Browse all 948

Creating word document from template using wordml defined in ECMA-376

$
0
0

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.

Exmaple 1.png

 

Write the program that will fill the document.

 

  data: LO_FORM typerefto Z_MWL_FORM.

 

   data: L_TEMPLATE type STRING value'block'.

   data: L_INDEX typeIvalue1.

   data: L_NUM typeI.

 

   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.

 

   do2times.

 

     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.

     add1to L_INDEX.

   enddo.

 

   LO_FORM->FINISH_SEQ_ACCESS( ).

 

   LO_FORM->CLEAN(  ).

   LO_FORM->DISPLAY( ).

 

Open the filled document on client machine.

Example 2.png

 

 

Implemantaion details

 

class Z_MWL_FILE definition

  public

   createpublic .

 

  publicsection.

 

     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.

 

   protectedsection.

   privatesection.

 

ENDCLASS.

 

 

 

CLASS Z_MWL_FILE IMPLEMENTATION.

 

   method DOWNLOAD.

 

     data: LS_KEY type WWWDATATAB.

     data: LS_MIME type W3MIME.

     data: LT_MIME typestandardtableof W3MIME.

     field-symbols <LFS_DATA> typeANY.

 

     LS_KEY-RELID = 'MI'.

     LS_KEY-OBJID = I_TEMPLATE.

 

     callfunction'WWWDATA_IMPORT'

       exporting

         KEY               = LS_KEY

       tables

         MIME              = LT_MIME

       exceptions

         WRONG_OBJECT_TYPE = 1

         IMPORT_ERROR      = 2

         others            = 3.

 

     if SY-SUBRC eq0.

       loopat LT_MIME into LS_MIME.

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

         if<LFS_DATA> isassigned.

           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     typestandardtableof SOLISTI1,

           LV_BYTECOUNT    typeI.

     data: L_FPATH type STRING.

     callfunction'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 isnotinitial.

       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 ne0.

         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

   createpublic .

 

   publicsection.

     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 typeI.

 

     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

   protectedsection.

     data: O_FILE               typerefto ZCL_ZK_MWL_FILE.

     data: O_DOC               typerefto CL_DOCX_DOCUMENT.

     data: O_DOCUMENTPART       typerefto CL_DOCX_MAINDOCUMENTPART.

 

     data: O_SREADER typerefto IF_SXML_READER.

     data: O_SWRITER typerefto IF_SXML_WRITER.

     data: O_SNODE  typerefto IF_SXML_NODE.

     data: O_SVALUE_NODE  typerefto IF_SXML_VALUE_NODE.

   privatesection.

 

ENDCLASS.

 

 

 

CLASS Z_MWL_FORM IMPLEMENTATION.

 

   method CLEAN.

     if INTRM_PART isnotinitial.

       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 isnotinitial.

       O_DOCUMENTPART->FEED_DATA( FINAL_DOC ).

     elseif MAIN_PART isnotinitial.

       O_DOCUMENTPART->FEED_DATA( MAIN_PART ).

     endif.

     FINAL_DOC = O_DOC->GET_PACKAGE_DATA( ).

     if O_FILE->SAVE_ON_FRONTEND( FINAL_DOC ) ne0.

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

     endif.

   endmethod.                    "Display

 

   method FIND_BLOCK.

     data: LX_ROOT typerefto CX_SXML_ERROR.

     data: LO_OPELEM typerefto IF_SXML_OPEN_ELEMENT.

     data: L_AT_VAL typerefto IF_SXML_VALUE.

     data: L_VAL type STRING.

 

     if O_SREADER isboundand O_SWRITER isbound.

 

       while RV_FOUND ne ABAP_TRUE.

         try.

             O_SNODE = O_SREADER->READ_NEXT_NODE( ).

             if O_SNODE isinitial.

               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 typerefto CX_SXML_ERROR.

     data: LO_OPELEM typerefto IF_SXML_OPEN_ELEMENT.

     data: L_AT_VAL typerefto IF_SXML_VALUE.

     data: L_VAL type STRING.

 

     if O_SREADER isboundand O_SWRITER isbound.

 

       while RV_FOUND ne ABAP_TRUE.

         try.

             O_SNODE = O_SREADER->READ_NEXT_NODE( ).

             if O_SNODE isinitial.

               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 isinitial.

               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 isinitial.

               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 typerefto CX_SXML_ERROR.

     data: LO_WRITER typerefto CL_SXML_STRING_WRITER.

     if O_SREADER isnotinitialand O_SWRITER isbound.

       do.

         try.

             O_SNODE = O_SREADER->READ_NEXT_NODE( ).

             if O_SNODE isinitial.

               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 isnotinitial.

       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 isinitial.

       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 typerefto CX_SXML_ERROR.

     data: L_XSTRING type XSTRING.

 

*  L_XSTRING = CL_ABAP_CODEPAGE=>CONVERT_TO( I_VAL ).

 

     if O_SVALUE_NODE isboundand O_SWRITER isbound.

       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>



Viewing all articles
Browse latest Browse all 948

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>