AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Sonstige Fragen zu Delphi Suchen & Ersetzen in einem OpenOffice-Dokument
Thema durchsuchen
Ansicht
Themen-Optionen

Suchen & Ersetzen in einem OpenOffice-Dokument

Ein Thema von Killuah · begonnen am 28. Aug 2009 · letzter Beitrag vom 6. Jun 2010
Antwort Antwort
Killuah

Registriert seit: 18. Okt 2007
6 Beiträge
 
Delphi 2006 Architect
 
#1

Suchen & Ersetzen in einem OpenOffice-Dokument

  Alt 28. Aug 2009, 14:57
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:
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.
Nach dem Auswählen der Datei suche ich alle Tabellen und gehe diese der Reihe nach, beginnend mit der Letzten, einzeln durch.

Delphi-Quellcode:
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.
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.


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
Angehängte Dateien
Dateityp: zip openoffice-suchenundersetzen_511.zip (199,2 KB, 12x aufgerufen)
  Mit Zitat antworten Zitat
worker
(Gast)

n/a Beiträge
 
#2

Re: Suchen & Ersetzen in einem OpenOffice-Dokument

  Alt 28. Aug 2009, 15:06
ODT-Dateien bestehen doch nur aus XML-FILES:
In diesen mittels RegEx Search&Replace.
  Mit Zitat antworten Zitat
Killuah

Registriert seit: 18. Okt 2007
6 Beiträge
 
Delphi 2006 Architect
 
#3

Re: Suchen & Ersetzen in einem OpenOffice-Dokument

  Alt 28. Aug 2009, 15:47
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:
<text>
  [CV_Start]
  <tabelle>
    [CV_Daten][CV_Next]
  </tabelle>
  [CV_Ende]
</text>
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.

XML-Code:
<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>
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.

Edit: Das mit den Größen einfach nicht beachten, habs falsch interpretiert und ist somit hinfällig!

XML-Code:
<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>
Ich werde das mit der XML mal austesten. Für weitere Lösungsansätze bin ich trotzdem dankbar.

freundliche Grüße
Killuah
  Mit Zitat antworten Zitat
Killuah

Registriert seit: 18. Okt 2007
6 Beiträge
 
Delphi 2006 Architect
 
#4

Re: Suchen & Ersetzen in einem OpenOffice-Dokument

  Alt 2. Sep 2009, 10:17
*push*

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:
<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>
Wie man sieht, sind im Bereich "office:automatic-styles" nur die Tabelle und 2 der 3 Spalten
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
  Mit Zitat antworten Zitat
Schwedenbitter

Registriert seit: 22. Mär 2003
Ort: Finsterwalde
622 Beiträge
 
Turbo Delphi für Win32
 
#5

AW: Re: Suchen & Ersetzen in einem OpenOffice-Dokument

  Alt 6. Jun 2010, 20:28
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:
  1. Das Öffnen und Bearbeiten mit der in Deinem ersten Eintrag beschriebenen Vorgehensweise dauert mir bereits zu lange. Ich möchte später einige Dateien anhand des Inhalts sortieren. Das würde dann ewig brauchen.
  2. Ferner habe ich das Problem, dass ich zwar mittlerweile an den gesamten Text einer odt-Datei rankomme. Das aber auch nur, wenn keine separaten Textfelder vorhanden sind. Die "sehe" ich leider nicht. Und wenn dann dort meine wichtigen Infos enthalten sind, bin ich schon zum Scheitern verurteilt.
Ich wollte daher nach Plan B vorgehen. Dieser sah vor, die content.xml aus der odt-Datei zu entpacken und dann diese zu durchsuchen. Ich habe bereits probiert, die odt-Datei in eine tmp.zip zu kopieren und damit auszupacken. Das klappt nur leider nicht. Ich teste gerade, ob es an der odt-Datei oder am Code liegt.

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
Alex Winzer
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 07:38 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz