phpbar.de logo

Mailinglisten-Archive

[php] DOM appendChild

[php] DOM appendChild

Andi Voss andi at andis.mine.nu
Don Mar 29 22:28:20 CEST 2007


Hallo Sacha, Peter und Yannik,

erstmal vielen Dank für eure Antworten und Entschuldigung, dass ich mich
erst jetzt wieder dazu melde.
Ich antworte mal in einer Mail, damit ich nicht alles nochmal schreiben
muss.

Zu Peter:
Danke dass du sogar ein konkretes Beispiel für das Problem erstellt hast
http://www.media-palette.de/test/xmltable.zip

Letztendlich habe ich es jetzt vom Prinzip her gleich gemacht wie du, 
nur dass ich direkt DOM verwendet habe mit ein klein wenig str_replace, 
anstatt DOMCharacterData. Details dazu sind weiter unten.
Deine Klasse habe ich mir noch nicht genauer angesehen, habe nur mal die
Beschreibung dazu auf deiner Seite durchgelesen.
In meinem konkreten Fall würde deine XML-Line Klasse wohl vollkommen 
ausreichen, wobei mir die Verwendung von DOM im Prinzip sehr zusagt. Ich 
muss mich diesbezüglich nur noch ein wenig mehr einarbeiten.
Trotzdem vielen Dank nochmal, dass du dir die Mühe gemacht hast, das zu 
demonstrieren.
Mit deiner Klasse könnten ja prinzipiell auch mehrere XML-Dateien 
bearbeitet werden - oder? Eine .odt Datei besteht ja aus mehreren 
XML-Dateien, die evtl. zu bearbeiten wären.
Ich werde mir deine Klasse auf jedenfall nochmal genauer anschauen.

Sascha Grossenbacher wrote:
> Meiner Meinung nach solltest du nicht verschiedene Technologien 
> miteinander vermischen. Entweder machst du ein Template, dann kannst du 
> mit einer Template-Klasse auch direkt in der Vorlage eine Schleife 
> machen, die ist nämlich genau für solche Sachen gedacht. Das hat 
> allerdings den Nachteil das die Vorlage nicht mehr mit OO bearbeitet 
> werden, weil es dann nicht mehr valides XML ist.
> 
> Oder, du machst es mit DOM bzw. allgemein mit XML, dann kannst du, 
> genauso wie du Nodes kopieren etc. kannst, auch den Inhalt und Attribute 
> von denen verändern und schreiben. Dann kannst du auch genau angeben, 
> welche Zeile du bearbeiten willst.

genau das habe ich versucht - alles mit DOM zu machen, aber hier gab es
halt die Probleme die ich nicht gelöst bekommen habe, daher bin ich auf
str_replace ausgewichen und habe die Technologien vermischt.

Ich hatte das hier probiert:
...
if ( strstr( $node_list->item($i)->nodeValue, '{NO. RECEIPTS}' ) )
{
   $parent_node = $node_list->item($i)->parentNode;
   $actual      = $node_list->item($i);
}

for ( $r = 0; $r < count( $focus->receipts ) - 1; $r++ )
{
   $actual->nodeValue = str_replace( '{NO. RECEIPTS}', $focus->number );
   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   // das dann für jeden Platzhalter


   // clone actual node and append it to his parent
   $cloned_node[$r]    = $actual->cloneNode( true );
   $appended_node[$r]  = $parent_node->appendChild( $cloned_node[$r] );
}
...

Das Ersetzen hat an sich schon geklappt, aber leider/komischerweise
werden dann z.B. Formatierungen der Childs (auch komplette table-cells) 
in dem aktuellen Knoten gelöscht und der korrekt ersetzte Inhalt 
eingetragen. Das führt natürlich dazu, dass in OO nix mehr geht.
Da gibts ja eigentlich DOMCharacterData->replaceData() dafür - 
eigentlich genau das was ich für mein Vorhaben brauche, aber ich habe es 
nicht geschafft es korrekt zu benutzen... :( Wo und wie könnte ich das 
in meinem Beispiel oben einsetzen?).

Ansonsten habe ich erst die Knoten vervielfältigt und dann die Vorkommen 
der Platzhalter im gesamten XML-String geparst und gefüllt.
Das hab ich jetzt so gelöst:

// define all non-table fields to replace
$odt_expenses_data = array(
   '{NO}'          => $focus->number,
   '{USERNAME}'    => $user->last_name . ", " . $user->first_name,
   '{DATE FROM}'   => $focus->date_start,
   '{DATE TO}'     => $focus->date_end,
   '{DESTINATION}' => $focus->destination,
   '{DESCRIPTION}' => $focus->description,
   '{TIME FROM}'   => $focus->time_start,
   '{TIME TO}'     => $focus->time_end,
   '{COUNTRY}'     => $focus->country,
   '{AMOUNT}'      => $focus->amount );

// define all table fields to replace
// retrieve all receipts for an expense
for ( $s = 0; $s < count( $focus->receipts ); $s += 1 )
{
   $odt_receipts_data[] = array(
     '{NO. RECEIPTS}'            => $s + 1,
     '{RECEIPT CATEGORY}'       => $focus->receipts[$s]->category,
     '{RECEIPT AMOUNT}'         => $focus->receipts[$s]->amount,
     '{RECEIPT DESCRIPTION}'    => $focus->receipts[$s]->name );
}

// normal replacement
// replace from $odt_expenses_data each entry with the belonging data
foreach ( $odt_expenses_data as $odt_key => $odt_value )
{
   $odt_content = $odt->replaceOdtContent( $odt_key, $odt_value,
$odt_content );
}

// Table replacement
// replace from $odt_receipts_data[] each entry
for ( $s = 0; $s < count( $focus->receipts ); $s++ )
{
   foreach ( $odt_receipts_data[$s] as $receipt_key => $receipt_value )
   {
     $pos         = strpos( $odt_content, $receipt_key );
     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
     $odt_content = substr_replace( $odt_content, $receipt_value, $pos,
strlen( $receipt_key ) );
     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   }
}

also Stück für Stück vorangeschritten und ersetzt.

> 
> Ode, als dritte Alternative, du verwendest eine OpenDocument-Klasse [1], 
> [2]. Scheinen aber beide noch in einem sehr frühen Stadium zu sein, ich 
> bezweifle das man sie schon für produktive Sachen einsetzen kann.

Die habe ich lange getestet und lange dran rumgeschraubt, aber die sind
noch in einem so frühen Stadium, dass das echt momentan keine
Alternative war. End-User Dokumentation hab ich zu beiden auch nicht
gefunden, nur die API Doku. Die Beispiele habe ich bei beiden nach echt
langem Probieren auch nicht zum Laufen gebracht (vielleicht lags auch an
mir...), daher hab ich mir "schnell" eine eigene Klasse gebastelt, die
im Prinzip genau das gleiche macht wie die beiden, aber natürlich
erstmal auf mein Problem beschränkte Funktionalität bietet.

> 
> Gruss Sascha
> 
> [1] http://pear.php.net/package/OpenDocument
> [2] http://opendocumentphp.org/

Danke für eure Antworten und sorry für meine lange Antwort.

Gruss Andi

php::bar PHP Wiki   -   Listenarchive