Een klant moet meer dan 100 documenten aanpassen.
Een gewone tekst moet dan vervangen worden door een mergefield (dat natuurlijk een paar eigenschappen heeft).
Zou dat programmatisch mogelijk zijn met OLE of anderszins?
Een klant moet meer dan 100 documenten aanpassen.
Een gewone tekst moet dan vervangen worden door een mergefield (dat natuurlijk een paar eigenschappen heeft).
Zou dat programmatisch mogelijk zijn met OLE of anderszins?
Ja hoor, geen problem.
Hou er rekening mee dat een pagina binnen Word (ook) een header en footer heeft, die
je apart moet aanroepen: het heeft mij destijds een hele tijd gekost voor ik doorhad
waarom een bepaald woord niet gevonden werd (hij stond in de header van de pagina).
TMemoryLeak.Create(Nil);
Bovenstaande oplossing vervangt alleen tekst door andere tekst. Het vervangt die tekst niet door een mergefield. Als je er een mergefield van wilt maken zul je volgens mij wat meer moeten doen.
Je zou dit een in een macro kunnen doen en dan de source van de vbs bekijken. Dan zie je gelijk hoe je dat in Delphi zou kunnen doen.
Delphi Code:
Function Word_StringReplace(ADocument: TFileName; SearchString, ReplaceString: String; Flags: TWordReplaceFlags): Boolean; Const WdFindContinue = 1; WdReplaceOne = 1; WdReplaceAll = 2; WdDoNotSaveChanges = 0; Var WordApp: OLEVariant; Begin Result := False; { Check if file exists } If Not FileExists(ADocument) Then Begin ShowMessage('Specified Document not found.'); Exit; End; { Create the OLE Object } Try WordApp := CreateOLEObject('Word.Application'); Except On E: Exception Do Begin E.Message := 'Word is not available.'; Raise ; End; End; Try { Hide Word } WordApp.Visible := False; { Open the document } WordApp.Documents.Open(ADocument); { Initialize parameters } WordApp.Selection.Find.ClearFormatting; WordApp.Selection.Find.Text := SearchString; WordApp.Selection.Find.Replacement.Text := ReplaceString; WordApp.Selection.Find.Forward := True; WordApp.Selection.Find.Wrap := WdFindContinue; WordApp.Selection.Find.Format := False; WordApp.Selection.Find.MatchCase := WrfMatchCase In Flags; WordApp.Selection.Find.MatchWholeWord := False; WordApp.Selection.Find.MatchWildcards := WrfMatchWildcards In Flags; WordApp.Selection.Find.MatchSoundsLike := False; WordApp.Selection.Find.MatchAllWordForms := False; { Perform the search } If WrfReplaceAll In Flags Then WordApp.Selection.Find.Execute(Replace := WdReplaceAll) Else WordApp.Selection.Find.Execute(Replace := WdReplaceOne); { Save word } WordApp.ActiveDocument.SaveAs(ADocument); { Assume that successful } Result := True; { Close the document } WordApp.ActiveDocument.Close(WdDoNotSaveChanges); Finally { Quit Word } WordApp.Quit; WordApp := Unassigned; End; End;
Ik heb een stukje oude code opgezocht.
Ooit werkte dat met Word2003 en WordXP
Nu krijg ik vele foutmeldingen, maar je krijg wel een in druk hou je het zou kunnen aanpakken.
gr. Peter
10.4.2, Delphi2010, of Lazarus 2.2.0
Dank.
De search replace code is al iets.
Misschien search en dan "insert mergefield at position".
Ik wacht even tot de klant evt. opdracht geeft. Het moet te doen zijn :-)
Ik had nog nooit van een MergeField gehoord (althans volgens deze definitie).
Wij gebruikten altijd een "Normaal" Word-document, met daarin specifieke en unieke woorden
(bijvoorbeeld %_NAAM_%) erin die verwezen naar een waarde waarmee het vervangen moest
worden.
Volgens mij is de code van Peter(Wok) dezelfde als die in mijn linkje (en zou dat niet werken
met mergefields).
TMemoryLeak.Create(Nil);
What on earth is dit?
WordApp.Selection.Find.Execute(Replace := WdReplaceAll)
Het compileert... Welke mij onbekende parameter syntax ligt hier aan ten grondslag?
Het zal wel een fancy naam hebben, maar de Execute-method heeft een zooi optionele parameters.
Je kunt via zo'n OLE-koppeling method gewoon alle parameters invullen (wel in de juiste volgorde),
maar je kunt ook opgeven wat voor waarde een bepaalde parameter moet hebben.
Delphi (Pascal) kent geen optionele parameters (alleen default parameters), dus daarom staat het
voor ons zo raar (persoonlijk zou ik liever dergelijke optionele parameters in Delphi hebben, dan
inline variabelen waar MarcoV het in het andere draadje over heeft).
TMemoryLeak.Create(Nil);
Ter info wat betreft het zoeken en vervangen door een MergeField. Werkelijk de Find/Replace hiervoor gebruiken zal niet lukken. Wat je wel kunt doen is zoeken en verwijderen en dan op die positie een MergeField tussenplaatsen.
In VBA (macro opnemen) wordt een MergeField op deze manier op Selection.Range geplaatst.
VBA Code:
ActiveDocument.Fields.Add Range:=Selection.Range, Type:=wdFieldMergeField, Text:="""Voornaam"""
Ander voorbeeldje met wat VBA code
https://stackoverflow.com/questions/...il-merge-field
en
https://answers.microsoft.com/en-us/...b-68b599b31bf5
VBA Code:
Dim oRng As Range Set oRng = ActiveDocument.Range With oRng.Find Do While .Execute(FindText:="(Player 1)") oRng.Fields.Add oRng, wdFieldMergeField, "Player_1", False oRng.Collapse wdCollapseEnd Loop End With
Ok snap ongeveer... Maar werkt deze (rode) syntax ook standaard in Delphi? Het lijkt van niet. Wanneer kan dit en wanneer niet?
(ik lees met grote interesse de Cantu-blog en de thread van MarcoV).
Thanks rvk. Wanneer ik bezig ga zal ik hier nog wel terugkomen..
Nee, die werkt niet met andere variabele. Dit zal in Delphi alleen werken met Variant variabele. Daar wordt met het aanroepen van procedures e.d. pas gecontroleerd wanneer deze uitgevoerd wordt (late binding). En dan is deze syntax wel toegestaan.
Ik heb even in mijn source gekeken en de enige instance waar ik dit bij mij tegenkom is dit:
ooDocument is een variant van ooApp.Workbooks[1] en ooApp is weer een CreateOleObject('Excel.Application');Delphi Code:
ooDocument.PrintOut(Preview := false);
gaat het om .doc bestanden of om .docx? Docx is een (gezipt) xml bestand en is als zodanig redelijk makkelijk te verwerken. Het zou me niet verbazen als de mergefields hierin direct kunnen worden benaderd.
Ik dacht dat docx een gewone gezipte doc was.
[EDIT]
Inderdaad... grappig: allemaal XML's.
Maar, ik heb even een test-docje opgeslagen met drie woorden en er worden wel veel dingen weggeschreven.
De tekst zelf staat in "document.xml", maar dat zou dan betekenen dat je je weer moet gaan verdiepen in hoe
een docx-bestand in elkaar zit; ik weet niet of ik daar zin in zou hebben (maar wellicht heeft Eric er wel zin in).
Last edited by VideoRipper; 01-Nov-18 at 15:53.
TMemoryLeak.Create(Nil);
Uiteraard had ik dit al geprobeerd tijdens een testje :-)
Echter er kan zoveel Word-onzin instaan (op de meest onvoorstelbare plekken) dat een unzip - search replace in document.xml - zip back ondoenlijk is.
Voor deze ene maal zou het wel kunnen met OLE, maar ik vermoed dat de klant het handmatig gaat doen. Dat gaat ze een paar dagen kosten.
Word OLE is overigens stom, tricky en vooral belachelijk langzaam, zelfs bij early binding.
There are currently 1 users browsing this thread. (0 members and 1 guests)
Bookmarks