''' Un documento HTML puo' essere rappresentato sotto forma di albero, come visto a lezione, che si chiama DOM (Document Object Model). Un qualsiasi nodo di questo albero puo' essere individuato sulla base delle proprie caratteristiche: - tag un tag del tipo indicato - .classe una delle parole presenti nel valore dell'attributo "class" - #id il valore dell'attributo "id" - @[attributo="valore"] valore di un attributo generico ed in base alla sua relazione con i tag che lo contengono: - avo discendente il tag 'avo' contiene un tag 'discendente' a qualsiasi profondita' - padre > figlio il tag 'padre' contiene il tag 'figlio' nel livello immediatamente sotto Un selettore CSS e' una successione di selettori di tag separati da spazio che serve ad individuare uno o piu' nodi all'interno del DOM. Esempio: div .class1 > #main_window seleziona un qualsiasi tag che ha id="main_window" e' il figlio di un tag che ha class="... class1 ..." e si trova all'interno (a qualsiasi livello di distanza) di un tag div Esempio2: p table > tr > td > a seleziona un link ( ) figlio di una casella ( ... ) figlia di una riga ( ... ) figlia di una tabella ( ...
) contenuta a qualsiasi livello in un paragrafo (

....

) NOTA: questa definizione del CSS e' una versione ridottissima che non segue lo standard completo. In particolare, non e' possibile usare piu' relazioni '>' consecutive o costruire selettori alternativi (in OR) e selettori in AND. Le modifiche da attuare su un DOM possono essere di 3 tipi: - conteggio dei nodi che soddisfano il selettore CSS - eliminazione di tutti i tag individuati da un selettore CSS - modifica degli attributi di tutti i tag individuati da un selettore CSS Realizzate le funzioni che esplorano e modificano l'albero: conta_nodi( fileIn, selettore) elimina_nodi( fileIn, selettore, fileOut) cambia_attributo( fileIn, selettore, chiave, valore, fileOut) ATTENZIONE: nei test verra' utilizzato un timout globale di 1*N secondi (se il grader fa N test) ''' from my_html import HTMLNode, fparse def conta_nodi(fileIn, selettore): '''Torna il numero di nodi dell'albero, che soddisfano il selettore CSS.''' #Inserite qui il vostro codice radice = fparse(fileIn) sequenza = selettore.split() return conta_matchCSS(radice, sequenza) def conta_matchCSS(dom, sequenza, ricorsione=True): if dom.istext(): return 0 if sequenza[0]=='>': return conta_matchCSS(dom, sequenza[1:], ricorsione=False) if match_CSS(dom, sequenza[0]): if not sequenza[1:]: return 1 ret = 0 for figlio in dom.content: ret += conta_matchCSS(figlio, sequenza[1:]) return ret ret = 0 if ricorsione: for figlio in dom.content: ret += conta_matchCSS(figlio, sequenza) return ret def match_CSS(dom, selettore): primo = selettore[0] valore= selettore[1:] if dom.tag == '_text_': return False if primo == '#': if 'id' in dom.attr and dom.attr['id']==valore: return True elif primo == '.': if 'class' in dom.attr and valore in dom.attr['class']: return True elif primo == '@': valore = valore.strip('[]') a,v=valore.split('=') v=v.strip('"\'') if a in dom.attr and dom.attr[a]==v: return True else: return dom.tag==selettore def elimina_matchCSS(dom, sequenza, padredom=None, ricorsione=True): if dom.istext(): return primo = sequenza[0] if primo =='>': return elimina_matchCSS(dom, sequenza[1:], padredom, ricorsione=False) if match_CSS(dom, primo): if not sequenza[1:]: padredom.content.remove(dom) del dom return for figlio in dom.content: elimina_matchCSS(figlio, sequenza[1:], dom) return if ricorsione: for figlio in dom.content: elimina_matchCSS(figlio, sequenza, dom) return def elimina_nodi(fileIn, selettore, fileOut): '''Elimina dall'albero tutti i nodi che soddisfano il selettore CSS (compreso il loro contenuto)''' #Inserite qui il vostro codice radice = fparse(fileIn) sequenza = selettore.split() elimina_matchCSS(radice, sequenza) with open(fileOut, 'w') as f: f.write(radice.to_string()) def cambia_matchCSS(dom, sequenza, chiave, valore, ricorsione=True): if dom.istext(): return primo = sequenza[0] if primo == '>': return cambia_matchCSS(dom, sequenza[1:], chiave, valore, ricorsione=False) if match_CSS(dom, primo): if not sequenza[1:]: dom.attr[chiave]=valore return for figlio in dom.content: cambia_matchCSS(figlio, sequenza[1:], chiave, valore) return if ricorsione: for figlio in dom.content: cambia_matchCSS(figlio, sequenza, chiave, valore) return def cambia_attributo(fileIn, selettore, chiave, valore, fileOut): '''Modifica tutti i nodi dell'albero che soddisfano il selettore CSS''' #Inserite qui il vostro codice radice = fparse(fileIn) sequenza = selettore.split() cambia_matchCSS(radice, sequenza, chiave, valore) with open(fileOut, 'w') as f: f.write(radice.to_string())