WORD 2007 docx: search/replace is working

Post Reply
User avatar
Otto
Posts: 4470
Joined: Fri Oct 07, 2005 7:07 pm
Contact:

WORD 2007 docx: search/replace is working

Post by Otto »

I did some tests with the new Word Open XML format and have
"search replace" working.

This is what I did:
1. rename from docx to zip
2. unpack
3. Seek and replace in the document.xml for placeholders
4. Zip again the files and rename back to docx.

Walkthrough: Word 2007 XML Format
http://msdn.microsoft.com/en-us/library/ms771890.aspx

Regards,
Otto

Image

Code: Select all

#include "FiveWin.ch"
#INCLUDE "directry.ch"
//----------------------------------------------------------------------------//
function Main()
   local DCOM
   local cTxtFile
   local cRCFile
   local cPath := "c:\soft"    // is a tmp directry to expand the docx file
   local aFiles

   DELETE FILE ('archive.zip')
   DELETE FILE ('temp.zip')
   
   // clear the directory - sure there is a better way
   do while .t.
      aFiles   := directory( cPath + '\*.*', 'D' )
      if len(aFiles) > 2
         dir_recurs( cPath )
      else
         exit
      endif
   enddo


   MOVEFILE( "demo.docx" , "temp.zip" )
   SYSREFRESH()

   //extracts all *.* files from the archive archive.zip to c:\soft folder.
   // 7Z.exe - thanks to Richard - maybe someone can help with the build in function
   DCOM  := '7Z.exe x '  + "temp.zip" + " -oc:\soft *.* -r"
   WAITRUN(DCOM,0)
   SYSREFRESH()

   cRCFile  := "c:\soft\word\document.xml"
   cTxtFile = MemoRead( cRCFile )
   SYSREFRESH()

   cTxtFile := STRTRAN(cTxtFile, "[ANREDE]",           "Herr")
   cTxtFile := STRTRAN(cTxtFile, "[TITELVORNAMENAME]", "Dr. Mustermann Hans")
   cTxtFile := STRTRAN(cTxtFile, "[BRIEFANRED]",       "Lieber Hans")
   cTxtFile := STRTRAN(cTxtFile, "[STRASSE]",          "Bahnhofstrasse")
   cTxtFile := STRTRAN(cTxtFile, "[ORT]",              "Musterort" )

   //xHarbours memowrit adds a chr(26) - therfore I linked the harbour function here
   memowrit(cRCFile, cTxtFile,.f.  )
   SYSREFRESH()

   //adds all files and subfolders from folder subdir to archive archive.zip.
   DCOM  := '7z a -tzip archive.zip  -ir!c:\soft\*.*'

   WAITRUN(DCOM,0)
   SYSREFRESH()

   MOVEFILE("archive.zip", "demo.docx" )

   SYSREFRESH()

   msginfo("Ende")
return nil

//----------------------------------------------------------------------------//

static function dir_recurs( cPath )
   local x
   local aFiles   := directory( cPath + '\*.*', 'D' )
   local nFilCount := len( aFiles )

   dirremove(cPath)

   for x := 1 to nFilCount

      if aFiles[ X, F_NAME ] <> '..'
         ferase (cPath + "\" +  aFiles[ X, F_NAME ])
      endif

      if 'D' $ aFiles[ X, F_ATTR ]
         if aFiles[ X, F_NAME ] <> '.'
            dir_recurs( cPath + '\' + aFiles[ X, F_NAME ] )
         endif
      endif
   next

return NIL
//----------------------------------------------------------------------------//

#pragma BEGINDUMP

#include <hbapi.h>
#include <hbapiitm.h>
#include "hbapifs.h"

HB_FUNC( MEMOWRIT )
{
PHB_ITEM pFileName = hb_param( 1, HB_IT_STRING );
   PHB_ITEM pString = hb_param( 2, HB_IT_STRING );
BOOL bWriteEof = TRUE; /* write Eof !, by default is .T. */
BOOL bRetVal = FALSE;

   if( hb_parinfo(0) == 3                       && ISLOG( 3 ) )
bWriteEof = hb_parl( 3 );

   if( pFileName                                && pString )
{
FHANDLE fhnd = hb_fsCreate( ( BYTE * ) hb_itemGetCPtr( pFileName ), FC_NORMAL );

   if( fhnd != FS_ERROR )
{
ULONG ulSize = hb_itemGetCLen( pString );

   bRetVal = ( hb_fsWriteLarge( fhnd, ( BYTE * ) hb_itemGetCPtr( pString ), ulSize ) == ulSize );

/* NOTE: CA-Clipper will add the EOF even if the write failed. [vszakats] */
/* NOTE: CA-Clipper will not return .F. when the EOF could not be written. [vszakats] */
#if ! defined(OS_UNIX_COMPATIBLE)
{
if( bWriteEof ) /* if true, then write EOF */
{
BYTE byEOF = HB_CHAR_EOF;

   hb_fsWrite( fhnd, &byEOF, sizeof( BYTE ) );
   }
}
#endif

hb_fsClose( fhnd );
   }
}

hb_retl( bRetVal );
   }

#pragma ENDDUMP

//----------------------------------------------------------------------------//
User avatar
MauroArevalo
Posts: 98
Joined: Thu Jan 19, 2006 11:47 pm
Location: Bogota DC. Colombia
Contact:

Post by MauroArevalo »

Otto:

It is a very interesting topic, I will make supporting evidence.

Thank you
Edgar Mauricio Arévalo Mogollón.
Bogotá DC. Colombia
FWH 19.06 xHarbour 1.2.1, Pelles C, Fivedit, Borland 7.30
http://www.hymplus.com
Tratando de retomar la programación....
User avatar
driessen
Posts: 1239
Joined: Mon Oct 10, 2005 11:26 am
Location: Genk, Belgium

Post by driessen »

Otto,

A very interesting development you share with us.

I only have 1 problem.

As I told you before I use FCREATE, FREAD and FWRITE to obtain the same result. So far so good.

But I use some signs like "[<" and ">]". In XML they are written to the file somewhat different? So I have to find out how to solve this.

But keep us informed of your further developments.

Thanks.
Regards,

Michel D.
Genk (Belgium)
_____________________________________________________________________________________________
I use : FiveWin for (x)Harbour v. 21.01 - Harbour 3.2.0 (October 2020) - xHarbour Builder (January 2020) - Bcc7
User avatar
Otto
Posts: 4470
Joined: Fri Oct 07, 2005 7:07 pm
Contact:

Post by Otto »

Hello Michael,

If I remember well you told that you use RTF.

Here I use the new OPEN XML format from WORD 2007.
This is the new standard format – docx.

I uploaded my VB6 drag&dop program for test purpose.
http://www.atzwanger-software.com/fw/word2007.zip
I hope we can do this program in FWH.

You can try to drag and drop a placeholder from the program to word
and then have a look at the document.xml file inside the docx – file.
You will see that the brackets remain.

Example:
><w:t xml:space="preserve"> [STRASSE] </w:t></w:r></w:p><w:p w:rsidR="00313937" w:rsidRDefault="0034734A"><w:r w:rsidRPr="0034734A"><w:t>[ORT]<

Regards,
Otto


Image
Rochinha
Posts: 309
Joined: Sun Jan 08, 2006 10:09 pm
Location: Brasil - Sao Paulo
Contact:

Post by Rochinha »

Otto

Enchacement for your code:

Change the main function:

Code: Select all

Function Main( cDOCFile, cVFields, cVData )

   aVFields := StringToArray( cVFields, ";" )
   aVData   := StringToArray( cVData, ";" )
   ...
   MOVEFILE( cDOCFile, "temp.zip" ) 
   ...
   HB_UNZIPFILE( "temp.zip",,.f.,,"c:\soft")
   ...
   Hb_ZIPFILE( "temp.zip", cDOCFile, 8 )

Replace

Code: Select all

   cTxtFile := STRTRAN(cTxtFile, "[ANREDE]",           "Herr") 
   cTxtFile := STRTRAN(cTxtFile, "[TITELVORNAMENAME]", "Dr. Mustermann Hans") 
   cTxtFile := STRTRAN(cTxtFile, "[BRIEFANRED]",       "Lieber Hans") 
   cTxtFile := STRTRAN(cTxtFile, "[STRASSE]",          "Bahnhofstrasse") 
   cTxtFile := STRTRAN(cTxtFile, "[ORT]",              "Musterort" ) 
With

Code: Select all

   for i = 1 to len(aVFields)
       cTxtFile := STRTRAN(cTxtFile, aVFields[i], aVData[i]) 
   next

Code: Select all

function StringToArray( cString, cSeparator )
LOCAL nPos
LOCAL aString := {}
DEFAULT cSeparator := ";"
cString := ALLTRIM( cString ) + cSeparator
DO WHILE .T.
   nPos := AT( cSeparator, cString )
   IF nPos = 0
      EXIT
   ENDIF
   AADD( aString, SUBSTR( cString, 1, nPos-1 ) )
   cString := SUBSTR( cString, nPos+1 )
ENDDO
RETURN ( aString )
User avatar
Otto
Posts: 4470
Joined: Fri Oct 07, 2005 7:07 pm
Contact:

Post by Otto »

Hello Rochinha,

thank you very much for your enhancement.

Good news - mail merge and WINDOWS WORD 2007 programmatically from FWH is ready.

Call the function like:

MailMerge( cDOCFile, cVFields, cVData )

Where cDocFile is your WINWORD docx file, cVFields is a list with your placeholders you use in the wordfile and cVData is the corresponding data.

The document.xml files are very small and this makes this way replacing the “placeholders” very speedy.

BTW, did you also had a look at my VB6 program? Do you think this could be done with FWH: drag the contents of your list control to Word?

Next step: we have to take care about the non standard characters - in German “Umlauts” - which we pass via cVData to the xml-file.
I have to find out how to substitute the characters: for example ß will become //ß .


Thanks again and best regards,
Otto


I don’t understand why Zip/unzip from xHarbour for me is not working.
But at the moment this is not important because I can use 7Z.exe as a workaround.
Rochinha
Posts: 309
Joined: Sun Jan 08, 2006 10:09 pm
Location: Brasil - Sao Paulo
Contact:

Post by Rochinha »

Otto,

Your .DOCX have a DOCTYPE instruction like this?:

Code: Select all

<?xml version="1.0"?>
<!DOCTYPE xbel PUBLIC 
       "+//IDN python.org//DTD XML Bookmark Exchange
        Language 1.0//EN//XML" 
       "http://www.python.org/topics/xml/dtds/xbel-1.0.dtd">
In Language 1.0//EN//XML" you need replace with Language 1.0//DE//XML".

The German Charset is iso-8859-1 or x-IA5-German

Check and Try.
User avatar
Otto
Posts: 4470
Joined: Fri Oct 07, 2005 7:07 pm
Contact:

Post by Otto »

Rochinha,
thank you. There is no such instruction.
A origingal docx is in my zip file

http://www.atzwanger-software.com/fw/word2007.zip
Regards,
Otto
Post Reply