Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > it.comp.www.php > #20939 > unrolled thread
| Started by | Sandro kensan <kensan@kensan.it> |
|---|---|
| First post | 2016-06-17 18:48 +0200 |
| Last post | 2016-06-18 12:29 -0700 |
| Articles | 11 — 3 participants |
Back to article view | Back to it.comp.www.php
ritornare una list mixed Sandro kensan <kensan@kensan.it> - 2016-06-17 18:48 +0200
Re: ritornare una list mixed fmassei@gmail.com - 2016-06-17 10:26 -0700
Re: ritornare una list mixed Sandro kensan <kensan@kensan.it> - 2016-06-17 20:49 +0200
Re: ritornare una list mixed fmassei@gmail.com - 2016-06-17 12:11 -0700
Re: ritornare una list mixed Sandro kensan <kensan@kensan.it> - 2016-06-17 22:01 +0200
Re: ritornare una list mixed fmassei@gmail.com - 2016-06-17 16:51 -0700
Re: ritornare una list mixed Alessandro Pellizzari <shuriken@amiran.it> - 2016-06-17 20:34 +0000
Re: ritornare una list mixed Sandro kensan <kensan@kensan.it> - 2016-06-18 00:18 +0200
Re: ritornare una list mixed fmassei@gmail.com - 2016-06-17 17:26 -0700
Re: ritornare una list mixed Alessandro Pellizzari <shuriken@amiran.it> - 2016-06-18 16:28 +0000
Re: ritornare una list mixed fmassei@gmail.com - 2016-06-18 12:29 -0700
| From | Sandro kensan <kensan@kensan.it> |
|---|---|
| Date | 2016-06-17 18:48 +0200 |
| Subject | ritornare una list mixed |
| Message-ID | <dsinv7F5lpjU1@mid.individual.net> |
Ho una funzione ricorsiva che usa come valori di ritorno un array di
stringhe e un array di nodi di un DOM document, gli array sono della
stessa lunghezza. Come posso ritornarli nella mia funzione ricorsiva?
function recursively_find_text_nodes($dom_element) {
global $node;
$return = array();
foreach ($dom_element->childNodes as $dom_child) {
switch ($dom_child->nodeType) {
case XML_TEXT_NODE:
if (trim($dom_child->nodeValue) !== '') {
$return[] = $dom_child->nodeValue;
$node[] = $dom_child;
}
break;
case XML_ELEMENT_NODE:
$return = array_merge($return, recursively_find_text_nodes(
$dom_child ));
break;
}
}
return $return;
}
Vorrei fare un return array($return, $node); e poi un list($a, $b) =
recursively_find_text_nodes($dom_element);
Quindi un:
$return = array_merge($return, recursively_find_text_nodes( $dom_child ));
===>
modifica di conseguenza.
Può funzionare?
--
Sandro kensan www.kensan.it & www.qiqi.it geek site
Saluto gli agenti della NSA - Hello NSA - www.nsa.gov
[toc] | [next] | [standalone]
| From | fmassei@gmail.com |
|---|---|
| Date | 2016-06-17 10:26 -0700 |
| Message-ID | <691b2344-a346-4d13-97bc-44ba68fa1fc8@googlegroups.com> |
| In reply to | #20939 |
On Friday, June 17, 2016 at 12:48:41 PM UTC-4, Sandro kensan wrote: > Ho una funzione ricorsiva che usa come valori di ritorno un array di > stringhe e un array di nodi di un DOM document, gli array sono della > stessa lunghezza. Come posso ritornarli nella mia funzione ricorsiva? > > <snip> > Perché non puoi direttamente usare XPath? :) Questa funzione che deve fare? ;) Ciao!
[toc] | [prev] | [next] | [standalone]
| From | Sandro kensan <kensan@kensan.it> |
|---|---|
| Date | 2016-06-17 20:49 +0200 |
| Message-ID | <dsiv17Faq2hU1@mid.individual.net> |
| In reply to | #20940 |
On 17/06/2016 19:26, fmassei@gmail.com wrote: > Perché non puoi direttamente usare XPath? :) > Questa funzione che deve fare? ;) Non so molto usare il DOM che è molto utile sapere gestire e quindi sto facendo pratica esclusivamente col DOM. In generale è utile percorrere tutto l'albero: è l'abc. Nel mio caso si tratta di trovare tutti i nodi che hanno del testo come foglie. Mi serve memorizzare sia il testo che il nodo in modo da potere poi modificare il testo. Ma in generale con le funzioni ricorsive c'è il problema di fare entrare i dati e di farli uscire e questo è un caso tipico. Chiedo se si può risolvere. -- Sandro kensan www.kensan.it & www.qiqi.it geek site Saluto gli agenti della NSA - Hello NSA - www.nsa.gov
[toc] | [prev] | [next] | [standalone]
| From | fmassei@gmail.com |
|---|---|
| Date | 2016-06-17 12:11 -0700 |
| Message-ID | <1a8490fd-1a38-47c9-aa68-c7efb6527a2b@googlegroups.com> |
| In reply to | #20941 |
On Friday, June 17, 2016 at 2:49:13 PM UTC-4, Sandro kensan wrote: > On 17/06/2016 19:26, fmassei@gmail.com wrote: > > > Perché non puoi direttamente usare XPath? :) > > Questa funzione che deve fare? ;) > > Non so molto usare il DOM che è molto utile sapere gestire e quindi sto > facendo pratica esclusivamente col DOM. > Ah OK, se è per far pratica.. :) > In generale è utile percorrere tutto l'albero: è l'abc. Nel mio caso si > tratta di trovare tutti i nodi che hanno del testo come foglie. Mi serve > memorizzare sia il testo che il nodo in modo da potere poi modificare il > testo. > Questa non la capisco.. perché devi memorizzare (cosa poi?)? Non puoi passare alla funzione ricorsiva una callback che fa quello che deve fare su ogni nodo? Altrimenti stai solo cambiando la rappresentazione dei dati da albero (il DOM) a vettore (i tuoi array_merge), che è un passaggio in più che non mi sembra tanto sensato.. > Ma in generale con le funzioni ricorsive c'è il problema di fare entrare > i dati e di farli uscire e questo è un caso tipico. Chiedo se si può > risolvere. > Se vuoi linearizzare l'albero come stai facendo va bene. Non vedo a cosa mai potrebbe servire, però. Ciao!
[toc] | [prev] | [next] | [standalone]
| From | Sandro kensan <kensan@kensan.it> |
|---|---|
| Date | 2016-06-17 22:01 +0200 |
| Message-ID | <dsj385Faq2hU2@mid.individual.net> |
| In reply to | #20942 |
On 17/06/2016 21:11, fmassei@gmail.com wrote: > Ah OK, se è per far pratica.. :) Si, serve per fare pratica ma ha anche un risvolto pratico: ho un problema da risolvere e lo vorrei risolvere col DOM. > Questa non la capisco.. perché devi memorizzare (cosa poi?)? > Non puoi passare alla funzione ricorsiva una callback che fa quello che deve > fare su ogni nodo? Anche questa è una buona idea. Però dal punto di vista teorico mi piace poco perché in caso di malfunzionamenti ho problemi col debug soprattutto per me che il DOM lo mastico molto poco. Quindi preferisco tenere separate le due fasi: trovo tutte le foglie di tipo testo, modifico le foglie di tipo testo in un modo particolare. > Altrimenti stai solo cambiando la rappresentazione dei > dati da albero (il DOM) a vettore (i tuoi array_merge), che è un passaggio > in più che non mi sembra tanto sensato.. è in più ma permette di separare. > Se vuoi linearizzare l'albero come stai facendo va bene. Non vedo a cosa mai > potrebbe servire, però. All'atto pratico serve a questo: http://www.kensan.it/articoli/Volantino.php La cosa impressionate del php è che ti stupisce. Quello che chiedevo nel mio primo post ho provato a realizzarlo e funziona! In pratica gli array con elementi di tipo nodo di un DOM e di tipo string sono possibili. Non credevo. -- Sandro kensan www.kensan.it & www.qiqi.it geek site Saluto gli agenti della NSA - Hello NSA - www.nsa.gov
[toc] | [prev] | [next] | [standalone]
| From | fmassei@gmail.com |
|---|---|
| Date | 2016-06-17 16:51 -0700 |
| Message-ID | <5762bf40-00c8-49bb-abcd-c011265b5eaf@googlegroups.com> |
| In reply to | #20943 |
On Friday, June 17, 2016 at 4:01:13 PM UTC-4, Sandro kensan wrote: > On 17/06/2016 21:11, fmassei@gmail.com wrote: > > Questa non la capisco.. perché devi memorizzare (cosa poi?)? > > Non puoi passare alla funzione ricorsiva una callback che fa quello che > > deve fare su ogni nodo? > > Anche questa è una buona idea. Però dal punto di vista teorico mi piace > poco perché in caso di malfunzionamenti ho problemi col debug > soprattutto per me che il DOM lo mastico molto poco. Quindi preferisco > tenere separate le due fasi: trovo tutte le foglie di tipo testo, > modifico le foglie di tipo testo in un modo particolare. > Visto che stai giusto provando cose per conto tuo non entro nei dettagli, però puntualizzo una cosa... Dal "punto di vista teorico" passare una callback alla funzione ricorsiva è esattamente come bisognerebbe fare :) Lascia stare il fatto che è un albero: quando hai una struttura dati e devi fare un'operazione su ogni elemento (una "map" nella terminologia lambda) semplicemente la cicli. Può essere un array, un albero, un grafo o chissà quale strana struttura, ma il concetto è lo stesso. Se hai un vettore (un array) cosa fai, metti ognuno degli N elementi in N variabili e chiami N volte la funzione, o fai un for? :) Allo stesso modo, se hai un albero, che senso ha metterlo in un vettore quando puoi semplicemente ciclarlo? :) Magari ora ti sembra complicato perché non l'hai fatto mai, o non molto spesso, ma ti garantisco che, specialmente nel debug, quando c'è un errore, è più facile capire dov'è in una funzione sola che in due (l'errore è sulla funzione ricorsiva che mi trasforma l'albero in array o su quella che fa le trasformazioni su nodi?). > > Altrimenti stai solo cambiando la rappresentazione dei > > dati da albero (il DOM) a vettore (i tuoi array_merge), che è un passaggio > > in più che non mi sembra tanto sensato.. > > è in più ma permette di separare. > E' solo questione d'abitudine. Se vuoi provarci e scriverla con una callback, vedrai che tutto il codice sarà soprendentemente (dico per te, io già ne sono sicuro ;)) più chiaro! Ciao!
[toc] | [prev] | [next] | [standalone]
| From | Alessandro Pellizzari <shuriken@amiran.it> |
|---|---|
| Date | 2016-06-17 20:34 +0000 |
| Message-ID | <dsj563Fbsg9U1@mid.individual.net> |
| In reply to | #20939 |
Il Fri, 17 Jun 2016 18:48:39 +0200, Sandro kensan ha scritto:
> Ho una funzione ricorsiva che usa come valori di ritorno un array di
> stringhe e un array di nodi di un DOM document, gli array sono della
> stessa lunghezza. Come posso ritornarli nella mia funzione ricorsiva?
Puoi sicuramente tornare un array (di array) misto. L'unica limitazione
degli array di PHP è che le chiavi devono essere scalari, ma i valori
possono essere qualsiasi cosa.
Ma io onestamente farei in modo diverso...
> function recursively_find_text_nodes($dom_element) {
> global $node;
> $return = array();
>
> foreach ($dom_element->childNodes as $dom_child) {
> switch ($dom_child->nodeType) {
> case XML_TEXT_NODE:
> if (trim($dom_child->nodeValue) !== '') {
> $return[] = $dom_child->nodeValue;
> $node[] = $dom_child;
Qui i due valori sono strettamente correlati.
Hai due possibilità, secondo me:
1- tornare solo il nodo, che tanto da lì puoi sempre recuperare il valore:
$return[] = $domNode;
2- tornare ogni elemento come "sotto-array" che li contiene entrambi:
$return[] = [$dom_child, $dom_child->nodeValue];
Questa seconda ti permette di fare
foreach (recursively_find_text_nodes($dom) as list($elem, value)) { ... }
(Non mi ricordo da che versione di PHP puoi usare "as list()")
> Può funzionare?
Se <strike>ti vuoi male</strike> vuoi vivere nel futuro, puoi usare i
generatori:
function find_text_nodes($dom_element)
{
foreach ($dom_element->childNodes as $dom_child) {
switch ($dom_child->nodeType) {
case XML_TEXT_NODE:
if (trim($dom_child->nodeValue) !== '') {
yield $dom_child;
}
break;
case XML_ELEMENT_NODE:
yield from find_text_nodes($dom_child);
break;
}
}
}
foreach (find_text_nodes($elem) as $node) {
...
}
WARNING: codice non testato, scritto di getto, e richiede PHP7. :)
Questa versione ha il vantaggio che non tiene in memoria la lista di tutti
i nodi e del loro contenuto, ma ne genera uno alla volta man mano che li
consumi, quindi puoi potenzialmente parsare un HTML il doppio più grosso
con la stessa quantità di RAM.
Bye.
[toc] | [prev] | [next] | [standalone]
| From | Sandro kensan <kensan@kensan.it> |
|---|---|
| Date | 2016-06-18 00:18 +0200 |
| Message-ID | <dsjba0Faq2hU3@mid.individual.net> |
| In reply to | #20944 |
On 17/06/2016 22:34, Alessandro Pellizzari wrote:
> Puoi sicuramente tornare un array (di array) misto. L'unica limitazione
> degli array di PHP è che le chiavi devono essere scalari, ma i valori
> possono essere qualsiasi cosa.
infatti, ho provato e funziona perfettamente.
> Ma io onestamente farei in modo diverso...
>
>> function recursively_find_text_nodes($dom_element) {
>> global $node;
>> $return = array();
>>
>> foreach ($dom_element->childNodes as $dom_child) {
>> switch ($dom_child->nodeType) {
>> case XML_TEXT_NODE:
>> if (trim($dom_child->nodeValue) !== '') {
>> $return[] = $dom_child->nodeValue;
>> $node[] = $dom_child;
>
> Qui i due valori sono strettamente correlati.
>
> Hai due possibilità, secondo me:
>
> 1- tornare solo il nodo, che tanto da lì puoi sempre recuperare il valore:
> $return[] = $domNode;
>
> 2- tornare ogni elemento come "sotto-array" che li contiene entrambi:
> $return[] = [$dom_child, $dom_child->nodeValue];
Non so se l'ultima notazione funziona ma si può scrivere come
$return[] = [array($dom_child, $dom_child->nodeValue);
In alcuni casi si può anche scrivere come
$return[$dom_child->nodeValue] = $dom_child
> Questa seconda ti permette di fare
>
> foreach (recursively_find_text_nodes($dom) as list($elem, value)) { ... }
>
> (Non mi ricordo da che versione di PHP puoi usare "as list()")
Questa mi avrebbe risparmiato un'istruzione.
>
>> Può funzionare?
>
> Se <strike>ti vuoi male</strike> vuoi vivere nel futuro, puoi usare i
> generatori:
>
> function find_text_nodes($dom_element)
> {
> foreach ($dom_element->childNodes as $dom_child) {
> switch ($dom_child->nodeType) {
> case XML_TEXT_NODE:
> if (trim($dom_child->nodeValue) !== '') {
> yield $dom_child;
> }
> break;
> case XML_ELEMENT_NODE:
> yield from find_text_nodes($dom_child);
> break;
> }
> }
> }
>
> foreach (find_text_nodes($elem) as $node) {
> ...
> }
>
> WARNING: codice non testato, scritto di getto, e richiede PHP7. :)
>
> Questa versione ha il vantaggio che non tiene in memoria la lista di tutti
> i nodi e del loro contenuto, ma ne genera uno alla volta man mano che li
> consumi, quindi puoi potenzialmente parsare un HTML il doppio più grosso
> con la stessa quantità di RAM.
Troppo complicato per me...
--
Sandro kensan www.kensan.it & www.qiqi.it geek site
Saluto gli agenti della NSA - Hello NSA - www.nsa.gov
[toc] | [prev] | [next] | [standalone]
| From | fmassei@gmail.com |
|---|---|
| Date | 2016-06-17 17:26 -0700 |
| Message-ID | <cf9260d3-bf5b-43c8-9235-868190fe5a3b@googlegroups.com> |
| In reply to | #20944 |
On Friday, June 17, 2016 at 4:34:14 PM UTC-4, Alessandro Pellizzari wrote: > Se <strike>ti vuoi male</strike> vuoi vivere nel futuro, puoi usare i > generatori: > ehehehe! Guarda, ero sicuro che, fin da quando abbiamo parlato di generatori qui qualche mese fa, ti bruciavano le mani per poterli usarli in qualche esempio :D > Questa versione ha il vantaggio che non tiene in memoria la lista di tutti > i nodi e del loro contenuto, ma ne genera uno alla volta man mano che li > consumi, quindi puoi potenzialmente parsare un HTML il doppio più grosso > con la stessa quantità di RAM. > Questo secondo me invece è sbagliato. Dovrei fare delle prove per vedere se ho ragione, ma sono "confident" al 95% :) Scrivo il perché.. Come prima cosa, iniziamo a dire che nel caso in oggetto il generatore deve generare tutto, ovvero non ci sono casi in cui si processa solo una parte di input. La domanda quindi è, quanto si risparmia in termini d'occupazione di memoria per l'array temporaneo, che in un caso (dell'OP) deve essere tutto presente in memoria e nell'altro può essere riciclato durante il processing. Pensiero 1: in ritorno abbiamo un array dove ogni elemento sono due puntatori (la stringa e il reference ad un DOMelement, che è un resource): su un 64bit sono 16byte ad elemento, per (diciamo) 100mila nodi fanno 1.5Mbyte. Come sappiamo la struttura potrebbe non essere compatta, ma in questo caso l'array sarebbe memoria contigua, per cui anche considerando gli sprechi e i buchi, è una quantità comunque troppo irrisoria per farci conti sopra.. Pensiero 2: suppongo stiamo usando il GC (altrimenti non avrebbe nemmeno senso fare questo discorso..). Calcolare quanta memoria è riciclata durante l'uso d'un generatore è compito arduo, ma in questo caso si può fare un'osservazione facile: visto che il GC di PHP opera con reference-counting, e visto che il DOM rimane referenziato mentre gira il generatore, non è possibile riciclare nulla di quello che effettivamente pesa! L'unico riciclo sarebbe sul riuso della struttura di cui sopra (quel megabyte e qualcosa). Pensiero 3: per quanto riguarda le performances, sia di memoria che di CPU, ovviamente sia la soluzione dell'OP che i generatori sono una bestemmia :) La migliore soluzione è, naturalmente, la classica map (che si emula in PHP con il passaggio di una callback alla funzione che cicla l'albero). Ciao!
[toc] | [prev] | [next] | [standalone]
| From | Alessandro Pellizzari <shuriken@amiran.it> |
|---|---|
| Date | 2016-06-18 16:28 +0000 |
| Message-ID | <dslb5aFj5kiU1@mid.individual.net> |
| In reply to | #20947 |
Il Fri, 17 Jun 2016 17:26:37 -0700, fmassei ha scritto: > On Friday, June 17, 2016 at 4:34:14 PM UTC-4, Alessandro Pellizzari > wrote: >> Se <strike>ti vuoi male</strike> vuoi vivere nel futuro, puoi usare i >> generatori: > ehehehe! Guarda, ero sicuro che, fin da quando abbiamo parlato di > generatori qui qualche mese fa, ti bruciavano le mani per poterli usarli > in qualche esempio :D Ah, beccato! :D In realtà ultimamente "mi tocca" perchè il nostro frontendista sta spingendo un po' troppo velocemente react.js e javascript oltre i limiti, e si è messo a usare i generatori per le chiamate asincrone. Siccome in teoria io dovrei poterlo sostituire in caso di ferie o malattie, mi tocca addentrarmici. :) > Pensiero 1: in ritorno abbiamo un array dove ogni elemento sono due > puntatori (la stringa e il reference ad un DOMelement, che è un > resource): su un 64bit sono 16byte ad elemento, per (diciamo) 100mila > nodi fanno 1.5Mbyte. Come sappiamo la struttura potrebbe non essere > compatta, ma in questo caso l'array sarebbe memoria contigua, per cui > anche considerando gli sprechi e i buchi, > è una quantità comunque troppo irrisoria per farci conti sopra.. Questo effettivamente è vero nel caso di PHP7 (richiesto, tra l'altro) viste le ottimizzazioni a livello di copy on write e di allocazione di memoria degli array che hanno introdotto. Diciamo che mi sono trovato a dover processare XML di 100 MB e mi sto facendo forse un po' troppe pare. :) > Pensiero 3: per quanto riguarda le performances, sia di memoria che di > CPU, ovviamente sia la soluzione dell'OP che i generatori sono una > bestemmia :) > La migliore soluzione è, naturalmente, la classica map (che si emula in > PHP con il passaggio di una callback alla funzione che cicla l'albero). La soluzione migliore sarebbe un parser alla XMLReader, ma effettivamente per file così piccoli stiamo pettinando il pelo sull'uovo. :P Bye.
[toc] | [prev] | [next] | [standalone]
| From | fmassei@gmail.com |
|---|---|
| Date | 2016-06-18 12:29 -0700 |
| Message-ID | <ad47a8eb-ba73-4309-807f-2d9bc6f57a8e@googlegroups.com> |
| In reply to | #20951 |
On Saturday, June 18, 2016 at 12:28:28 PM UTC-4, Alessandro Pellizzari wrote: > Il Fri, 17 Jun 2016 17:26:37 -0700, fmassei ha scritto: > > La migliore soluzione è, naturalmente, la classica map (che si emula in > > PHP con il passaggio di una callback alla funzione che cicla l'albero). > > La soluzione migliore sarebbe un parser alla XMLReader, ma effettivamente > per file così piccoli stiamo pettinando il pelo sull'uovo. :P > Ah, fossi stato io avrei usato XPath.. una riga e tutti a casa! ;) Ciao!
[toc] | [prev] | [standalone]
Back to top | Article view | it.comp.www.php
csiph-web