Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Do I need MS Word to create and edit a .docx file

Status
Not open for further replies.

Doug Lindauer

Programmer
Feb 2, 2017
36
US
Hopefully this isn't a stupid question. My current system creates and edits a Word file. Here's a sample of some of the code:
Code:
local oWord, wdReplaceAll  
wdReplaceAll = 2

oWord     = Createobject("Word.Application")
oDocument = oWord.Documents.Open(mWORDFILE)
oRange    = oWord.ActiveDocument.Content

with oRange.Find
    .Text = "CARDYEAR"
    .Replacement.Text = mCARDYEAR
    .Execute( ,  , , , ,  , , , , ,  wdReplaceAll)

All of my computers do have MS Office installed so I don't really have a way to easily test it. One of my potential users wants to know if he needs to have Office installed or is something like Open Office sufficient. So that's my question if anyone can answer it. :)
 
Thanks for that, Chris. The reason I suggested WinZip was that it can be automated via a command line. I don't know if you can do that natively within Windows. I know you can ShellExecute() an Extract All command against a ZIP file, but it seems that that then launches a dialogue which the user would have to interact with.

I take you point about having to parse out the text rather than using a simple STRTRAN(). That would make it more difficult than I suggested. In any case, I doubt if my solution would be appropriate in this case, because the thread title mentions creating DOCXs as well as editing them. Still, I thought it was worth pointing out that the possibility exists.

UPDATE: Chris, you mentioned 7ZIP. I see that that also has a command-line interface, and so can be automated along the same lines as Winzip - and has the advantage of being free.

Mike
__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Mike,

using Windows zip functionality works both in directions. I bet at least at one time you knew about faq184-5113.
CopyHere() also offers options to decide whether to show a copy dialog or not.
Using anything else but this Shell functionality offers more features, but you actually could also do without 7zip, too.
I would only go that route if looking into Greg Greens or other solutions provides a library to be done with both the XML creation and parsing. Then this could become comparable to ASCII text or simpler said string manipulation.

There are also faqs using zlib.dll and there's VFPCompression.fll

But in principle all you need is built into VFP and the OS, including XML parsing, not only with VFPs XML functions but also with MSXML, it just doesn't have Office XML specific methods, I think. unless it's the XML version specifically for Office.

The difficulty is when your code uses the classic OLE automation interface of word.application and all the OLE objects and methods it offers. It only translates to the XML within docx while it's loaded into a Word instance capable to load a docx.

Chriss
 
I played around a bit with working on the core file having the content of a docx, the document.xml file.

You can use MSXML.DomDocument and load the xml file, manipulate nodes and then save it back.

One thing MSXML.DomDocument can give you is XML loading and parsing and then also saving back to an updated document.xml file that can be zipped up to make a docx file Word can then load.
That sounds more straight forward then it is. All text is in <w:t></w:t> nodes, so have to parse them.

Sample code:
Code:
oXMLDoc = CREATEOBJECT("msxml.domdocument")

cFile = GetFile('document.xml')
oXMLDoc.load(cFile)

oTextnodes = loXMLDoc.selectNodes('//w:t') && all <w/t> nodes in any nesting level
FOR EACH oNode IN oTextnodes
    ?? oNode.text  
ENDFOR

You can get all text by oXMLDoc.text alone, without the loop, but that's not a property you can write to. But each node is an object you can change, i.e. oNode.text can be overwritten. And as I said, once you are done with the changes the save method also creates valid document.xml

So that's roughly a way to work on a docx with VFP and msxml.domdocument. Since the partial texts in the XML combined could have the text you want to replace but each single node could have only a small part of the text to replace, which means a replace would fail to find it. Say you'd want to replace "brown fox" with "bad wolfe" you wouldn't find it as "brown fox" is split in two nodes.

I think I understand the nature of the splitting. At each point Word does a syntax check of what you write, there seems to be added a spellStart and spellEnd type node so word considers that portion of text as valid. Which also means the splitting within a word could happen when there's ambiguity about the text and the spellchecker begins its proof process before you finish writing the word. Say it detects "brow" as valid word, then rechecks "brown". And in some cases this might split a text portion mid word, too.

I was able to aggregate nodes, but I wouldn't generalize this for any word document as there are so many features that will not work when the whole document text is merged into one <w:t> node.

RTF is easier to handle in that respect.

Chriss
 
Chris,

Just to add to your previous post, I tried Mike Gangon's code to unzip the file (as per the FAQ that you referenced). It works perfectly. It created three new folders, one of which was named Word, which in turn contained documentl.xml.

I'll next try your code to parse the XML nodes.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
The zip routines can be slightly improved, as you can pass a collection of items to CopyHere, so the foreach loop is obsolete:

Code:
LPARAMETERS tcZipFilename, tcDestinationFolder, tlWithProgress

IF !DIRECTORY(tcDestinationfolder,1)
   MKDIR (tcDestinationFolder)
ENDIF

LOCAL loShell, loFiles
loShell = CREATEOBJECT("Shell.Application")
loFiles = loShell.NameSpace(tcZipFilename).Items
loShell.NameSpace(tcDestinationfolder).CopyHere(loFiles, IIF(tlWithProgress,256,4)+1552)

Code:
LPARAMETERS tcSourceFolder, tcZipFilename, tlWithProgress

LOCAL loShell, loFiles
StrToFile(0h504B0506000000000000000000000000000000000000,tcZipFilename)
loShell = CREATEOBJECT("Shell.Application")
loFiles = loShell.NameSpace(tcSourceFolder).Items
loShell.NameSpace(tcZipFilename).copyhere(loFiles,IIF(tlWithProgress,256,4)+1552)

The second CopyHere parameter (vOptions) is described here:

I spared to define constants for each flag. I picked a dialog free combination (unless you explicitly want a progress).
Note: If an error occurs, a dialog also is suppressed. I haven't created a test case where this happens to see what happens instead.

Chriss
 
One slight disadvantage of the unzipping routine is that it displays a progress bar while the unzipping is in progress. That doesn't affect its functionality in any way, of course. But I'm always hesitant about a background task that does something in the user interface.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
I think our posts crossed, Mike, you can suppress this and other dialogs.

Chriss
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top