![]() |
Suchen & Ersetzen in einem OpenOffice-Dokument
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo erstmal,
zur Zeit bin ich auf der Suche nach einer Möglichkeit in einem OpenOffice-Dokument(.odt / Writer) alle Variablen mit Inhalten zu ersetzen. Syntax der Variable ist immer "[Bezeichnung]". Da ich schon einige verschiedene Möglichkeiten ausprobiert habe und nichts meinen Anforderungen ensprechen konnte bitte ich hier um etwas Hilfe. Die wohl einfachste Methode wäre über den Search-/ ReplaceDescriptor von OpenOffice. Da ich hier jedoch den genauen Suchbegriff eingeben muss und ich in meinen Variablen auch If/Else-Anweisungen zulasse (eigener interner Parser der das Ganze verarbeitet) scheidet diese Möglichkeit leider aus. Eine weitere Möglichkeit ist, über den SearchDescriptor eine Range zu erhalten, an dem die Variable beginnt und dort mit einem TextCursor zu arbeiten. Das funktioniert in reinem Text wirklich ausgezeichnet. Erst wenn man mit Tabellen oder Textfeldern arbeitet stößt man bei dieser Methode allein an seine Grenzen. So ist es leider nicht möglich in der Tabelle den TextCursor zu erstellen, da ich diesen nur auf einem XText-Objekt erstellen kann, und jede Tabelle ein eigenes XText behinhaltet, das ich hier nicht herausbekomme. (vielleicht weiß ja einer wie ich das rauskriege) Eine weitere Möglichkeit ist, das ich alle XText-Objekte der Reihe nach durchgehe und schaue, ob die eckigen Klammern vorhanden sind. Jedoch tauchen auch hier Probleme bei den Tabellen auf. Wie man in der Datei im Anhang sieht, habe ich in einer Tabelle eine weitere Tabelle. Im Folgenden ersteinmal der bisherige QuellText:
Delphi-Quellcode:
Nach dem Auswählen der Datei suche ich alle Tabellen und gehe diese der Reihe nach, beginnend mit der Letzten, einzeln durch.
type
TOOTest = class(TForm) OpenDialog1: TOpenDialog; procedure FormCreate(Sender: TObject); public OOSrvMgr: Variant; // ServiceManager OOfficeApp: Variant; // XDesktop OODispHlp: Variant; // DispatchHelper OODokument: Variant; procedure ReplaceTables; procedure ReplaceText(XText: Variant); function GetCountInString(sAllText, sSearch: String): Integer; end; implementation procedure TOOTest.FormCreate(Sender: TObject); var sURLLocation: String; begin // Vorbereitung OOSrvMgr := CreateOleObject('com.sun.star.ServiceManager'); OOfficeApp := OOSrvMgr.CreateInstance('com.sun.star.frame.Desktop'); OODispHlp := OOSrvMgr.CreateInstance('com.sun.star.frame.DispatchHelper'); if OpenDialog1.Execute then sURLLocation := ConvertToURL(OpenDialog1.FileName); // ConvertToURL ist aus den Examples von OOC OODokument := OOfficeApp.LoadComponentFromURL(sURLLocation, '_blank', 0, VarArrayCreate([0, -1], VarVariant)); ReplaceTables; OODokument.Close(False); OOfficeApp := unassigned; OOSrvMgr := Null; end; procedure TOOTest.ReplaceTables; var XTextTables: Variant; XTable: Variant; XCell : Variant; iTable: Integer; Row, Column: Integer; begin XTextTables := OODokument.getTextTables; for iTable := XTextTables.getCount -1 downto 0 do begin XTable:= XTextTables.getByIndex(iTable); for Row := 0 to XTable.Rows.Count -1 do begin for Column := 0 to XTable.Columns.Count -1 do begin XCell := XTable.getCellByPosition(Column, Row); //ShowMessage('CellText = "'+XCell.getText.getString+'"'); ReplaceText(XCell.getText); end; end; end; end; procedure TOOTest.ReplaceText(XText: Variant); var XTextCursor: Variant; // XTextCursor2: Variant; // XHlpCursor: Variant; bSelect: Boolean; sAllText: String; iAktPos: Integer; begin XTextCursor := XText.createTextCursor; XTextCursor.gotoStart(False); // XTextCursor2 := XText.createTextCursor; // XTextCursor2.gotoStart(False); // XHlpCursor := XText.createTextCursor; // XHlpCursor.gotoStart(False); sAllText := XText.getString; bSelect := False; while (Pos('[', sAllText) > 0) and (Pos(']', sAllText) > 0) do begin if sAllText[1] = '[' then begin bSelect := True; XTextCursor.goRight(1, bSelect); end else if sAllText[1] = ']' then begin XTextCursor.goRight(1, bSelect); if XTextCursor.getString <> '' then // überprüfen, ob die Anzahl an '[' und ']' identisch sind (für internen Parser (bzgl. If-Abfragen) wichtig) // GetCountInString(Text, SuchString: String): Integer; if GetCountInString(XTextCursor.getString, '[') = GetCountInString(XTextCursor.getString, ']') then begin XTextCursor.setString(''); bSelect := False; end; end else XTextCursor.goRight(1, bSelect); // ToDo: geht so nicht, da der TextCursor ÜBER die Tabelle springt und // der sAllText die Inhalte enthält sAllText := Copy(sAllText, 2, Length(sAllText)-1); // ToDo: "sAllText := XTextCursor2.getText.getString;" gibt immer den kompletten Inhalt der Zelle zurück // XTextCursor2.goRight(1, False); // XTextCursor2.gotoEnd(True); // XHlpCursor.goRight(1, False); // sAllText := XTextCursor2.getText.getString; // Expand = True, damit die Seletierung wieder aufgehoben wird (?) // XTextCursor2.gotoRange(XHlpCursor, True); end; end; end.
Delphi-Quellcode:
Dann wähle ich jede Zelle einzeln aus und ersetze mit "ReplaceText(XText: Variant)" die Variablen. Wie man anhand der beiden ToDo's in der Prozedur sehen kann stoße ich jedoch auf Probleme, wenn ich in einer Tabelle eine weitere habe.
Info: Warum mit der Letzten beginnen?
In OpenOffice sind die Tabellen im Dokument von Oben nach Unten einfach durchnummeriert. Bsp: [Dokument] [Tabelle1] [/Tabelle1] [Tabelle2] [Tabelle3] [/Tabelle3] [/Tabelle2] [/Dokument] Wenn ich in Tabelle2 bin und mir "sAllText" hole dann enthält dieser den kompletten Textinhalt von Tabelle3 - getrennt über einen Zeilenumbruch #13#10. Wenn ich also von hinten beginne habe ich in Tabelle3 keine '[' oder ']' mehr. Im Anhang einmal die Textdatei mit der ich teste und der Quellcode zum Debuggen. Ich selber Suche zur Zeit entweder in verschiedenen Foren, der API-Seite von OpenOffice oder in dem ObjektInspektor den man als Plugin in OpenOffice starten kann. Jedoch konnte bisher nichts weiterhelfen. freundliche Grüße Killuah |
Re: Suchen & Ersetzen in einem OpenOffice-Dokument
ODT-Dateien bestehen doch nur aus XML-FILES:
In diesen mittels RegEx Search&Replace. |
Re: Suchen & Ersetzen in einem OpenOffice-Dokument
XML sieht auf den ersten Blick recht gut aus.
Um meine Problematik etwas genauer zu definieren komme ich wohl nicht drum rum mehr zu erzählen. ^^ Ich will die Variablen mit Personendaten aus einer Datenbank ersetzen. Diese Personendaten enthalten unter Anderen auch einen Lebenslauf. Da ich bei der Erstellung einer Vorlage dafür nie genau weiß, wieviele CV-Einträge ich habe, ersetzte ich Diese während der Laufzeit. Beispiel: Eine Person hat 5 Einträge im Lebenslauf. In einer Vorlage würde dies für mich so aussehen.
XML-Code:
Programmiertechnisch wurde (bisher über MS Word) der Inhalt zwischen [CV_Start] und [CV_Ende] für jeden Eintrag kopiert damit das Ganze vor dem eigentlichen Ersetzen der Variablen so aussieht.
<text>
[CV_Start] <tabelle> [CV_Daten][CV_Next] </tabelle> [CV_Ende] </text>
XML-Code:
Da in der XML die Tabellen jedoch schon vor dem eigentlichen Text deklariert sind und die CV_Daten unterschiedliche Längen haben können, weiß ich nicht genau ob ich dann in der XML einfach die Tabelle erweitern kann, da hier feste Größen eingestellt sind.
<text>
[CV_Start] <tabelle> [CV_Daten][CV_Next] </tabelle> <tabelle> [CV_Daten][CV_Next] </tabelle> <tabelle> [CV_Daten][CV_Next] </tabelle> <tabelle> [CV_Daten][CV_Next] </tabelle> <tabelle> [CV_Daten][CV_Next] </tabelle> [CV_Ende] </text> Edit: Das mit den Größen einfach nicht beachten, habs falsch interpretiert und ist somit hinfällig!
XML-Code:
Ich werde das mit der XML mal austesten. Für weitere Lösungsansätze bin ich trotzdem dankbar.
<style:style style:name="Tabelle2.A" style:family="table-column">
<style:table-column-properties style:column-width="16.999cm" style:rel-column-width="65535*"/> </style:style> <style:style style:name="Tabelle2.A1" style:family="table-cell"> <style:table-cell-properties fo:padding="0.097cm" fo:border="0.002cm solid #000000"/> </style:style> freundliche Grüße Killuah |
Re: Suchen & Ersetzen in einem OpenOffice-Dokument
*push* :coder:
So, ich habe mir das Ganze mit XML jetzt mal etwas genauer angesehn. Ich öffne die content.xml in Delphi mit der JvSimpleXML und gehe rekursiv durch die einzelnen Nodes/ChildNodes und ersetze dann jeweils die im Value stehenden Variablen. Klappt soweit echt super. Bezüglich der Tabellen habe ich mir überlegt einfach weitere Nodes einzufügen. Da das an zwei verschiedenen Stellen geschehen muss könnte ich ja den Namen der Tabelle/Zelle im Bereich "office:automatic-styles" suchen und das Ganze dann dort noch erweitern. Dazu habe ich testweise eine Writer-Datei erstellt, die eine Tabelle mit drei Spalten und einer Zeile besitzt. Jetzt sieht meine XML folgendermaßen aus:
XML-Code:
Wie man sieht, sind im Bereich "office:automatic-styles" nur die Tabelle und 2 der 3 Spalten
<office:automatic-styles>
<style:style style:name="Tabelle1" style:family="table"> <style:table-properties style:width="16.999cm" table:align="margins"/> </style:style> <style:style style:name="Tabelle1.A" style:family="table-column"> <style:table-column-properties style:column-width="5.666cm" style:rel-column-width="21845*"/> </style:style> <style:style style:name="Tabelle1.A1" style:family="table-cell"> <style:table-cell-properties fo:padding="0.097cm" fo:border-left="0.002cm solid #000000" fo:border-right="none" fo:border-top="0.002cm solid #000000" fo:border-bottom="0.002cm solid #000000"/> </style:style> <style:style style:name="Tabelle1.C1" style:family="table-cell"> <style:table-cell-properties fo:padding="0.097cm" fo:border="0.002cm solid #000000"/> </style:style> </office:automatic-styles> <office:body> <office:text> <table:table table:name="Tabelle1" table:style-name="Tabelle1"> <table:table-column table:style-name="Tabelle1.A" table:number-columns-repeated="3"/> <table:table-row> <table:table-cell table:style-name="Tabelle1.A1" office:value-type="string"> <text:p text:style-name="Table_20_Contents"/> </table:table-cell> <table:table-cell table:style-name="Tabelle1.A1" office:value-type="string"> <text:p text:style-name="Table_20_Contents"/> </table:table-cell> <table:table-cell table:style-name="Tabelle1.C1" office:value-type="string"> <text:p text:style-name="Table_20_Contents"/> </table:table-cell> </table:table-row> </table:table> </office:text> </office:body> deklariert. Im Bereich "office:body" wurde dann der Stylename 'Tabelle1.A1' doppelt vergeben, obwohl es unterschiedliche Zellen sind. In der API-Beschreibung von OpenOffice habe ich gelesen, das die Zellennamen eindeutig zugewiesen sind und man auch über Funktionen direkt auf eine spezielle Zelle per Namen zugreifen kann. Wo sind diese Namen denn hinterlegt, wenn nicht hier? (habe alle andern .xml durchgeschaut aber nix gefunden) Eine weitere Frage ist, was mir "table:number-columns-repeated" aussagen soll. Ich habe in der Tabelle doch alle Spalten/Zellen deklariert, wozu dann also nochmal solch eine Eigenschaft? Ich werds weiterversuchen, für jede Hilfe bin ich dennoch dankbar. Mfg Killuah Edit: "Delphi-Code" durch "XML-Code" ersetzt |
AW: Re: Suchen & Ersetzen in einem OpenOffice-Dokument
Hallo,
ich komme mit OOO nicht ganz klar. Ich möchte odt-Dateien nach einem ganz bestimmten String durchsuchen. Dabei habe ich ein paar Probleme:
![]() Ich habe in Deinen Beiträgen zu diesem Thema mehrfach das Wort "content.xml" gefunden. Extrahierst Du die auch oder wie kommt man an deren Inhalt? Gruß & Dank, Alex |
Alle Zeitangaben in WEZ +1. Es ist jetzt 08:25 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz