Come faccio ad avere il codice XML completo o il contenuto HTML di un elemento usando ElementTree?

StackOverflow https://stackoverflow.com/questions/380603

  •  22-08-2019
  •  | 
  •  

Domanda

Cioè, tutto il testo e sottotag, senza il cartellino di un elemento in sé?

Avere

<p>blah <b>bleh</b> blih</p>

Voglio

blah <b>bleh</b> blih

restituisce element.text "blah" e etree.tostring (elemento) restituisce:

<p>blah <b>bleh</b> blih</p>
È stato utile?

Soluzione 2

Questa è la soluzione che ho finito per usare:

def element_to_string(element):
    s = element.text or ""
    for sub_element in element:
        s += etree.tostring(sub_element)
    s += element.tail
    return s

Altri suggerimenti

elementtree funziona perfettamente, devi montare la risposta da soli. Qualcosa di simile a questo ...

"".join( [ "" if t.text is None else t.text ] + [ xml.tostring(e) for e in t.getchildren() ] )

Grazie alla JV AMD PEZ per sottolineare gli errori.


Modifica.

>>> import xml.etree.ElementTree as xml
>>> s= '<p>blah <b>bleh</b> blih</p>\n'
>>> t=xml.fromstring(s)
>>> "".join( [ t.text ] + [ xml.tostring(e) for e in t.getchildren() ] )
'blah <b>bleh</b> blih'
>>> 

Tail non è necessaria.

Queste sono buone risposte, che rispondono alla domanda del PO, in particolare se la questione si limita a HTML. Ma i documenti sono intrinsecamente disordinati, e la profondità di elemento di nidificazione di solito è impossibile prevedere.

Per simulare getTextContent del DOM () si dovrebbe usare una (molto) semplice meccanismo ricorsivo.

Per ottenere solo il testo a nudo:

def get_deep_text( element ):
    text = element.text or ''
    for subelement in element:
        text += get_deep_text( subelement )
    text += element.tail or ''
    return text
print( get_deep_text( element_of_interest ))

Per avere tutti i dettagli circa i confini tra testo grezzo:

root_el_of_interest.element_count = 0
def get_deep_text_w_boundaries( element, depth = 0 ):
    root_el_of_interest.element_count += 1
    element_no = root_el_of_interest.element_count 
    indent = depth * '  '
    text1 = '%s(el %d - attribs: %s)\n' % ( indent, element_no, element.attrib, )
    text1 += '%s(el %d - text: |%s|)' % ( indent, element_no, element.text or '', )
    print( text1 )
    for subelement in element:
        get_deep_text_w_boundaries( subelement, depth + 1 )
    text2 = '%s(el %d - tail: |%s|)' % ( indent, element_no, element.tail or '', )
    print( text2 )
get_deep_text_w_boundaries( root_el_of_interest )

Esempio di output da singolo para in LibreOffice Writer doc (file .fodt):

(el 1 - attribs: {'{urn:oasis:names:tc:opendocument:xmlns:text:1.0}style-name': 'Standard'})
(el 1 - text: |Ci-après individuellement la "|)
  (el 2 - attribs: {'{urn:oasis:names:tc:opendocument:xmlns:text:1.0}style-name': 'T5'})
  (el 2 - text: |Partie|)
  (el 2 - tail: |" et ensemble les "|)
  (el 3 - attribs: {'{urn:oasis:names:tc:opendocument:xmlns:text:1.0}style-name': 'T5'})
  (el 3 - text: |Parties|)
  (el 3 - tail: |", |)
(el 1 - tail: |
   |)

Uno dei punti circa confusione è che non esiste una regola dura e veloce su quando uno stile di testo indica un confine di parola e quando si pretende molto: apice subito dopo una parola (senza spazi) significa una parola separata in tutti gli usi casi posso immaginare. OTOH a volte si potrebbe trovare, per esempio, un documento in cui la prima lettera o è in grassetto per qualche motivo, o forse utilizza uno stile diverso per la prima lettera di rappresentarlo come maiuscolo, piuttosto che semplicemente usando il normale carattere UC.

E naturalmente il meno in primo luogo "Inglese-centric" questa discussione ottiene la maggiore le sottigliezze e le complessità!

Dubito ElementTree è la cosa da utilizzare per questo. Ma a patto di avere forti ragioni per il suo utilizzo forse si potrebbe provare a nudo il tag radice dal frammento:

 re.sub(r'(^<%s\b.*?>|</%s\b.*?>$)' % (element.tag, element.tag), '', ElementTree.tostring(element))

La maggior parte delle risposte qui si basano sul ElementTree parser XML, anche risposta regex-based di PEZ ancora in parte si basa su ElementTree.

Tutti coloro che sono buoni e adatti per la maggior parte dei casi d'uso, ma, solo per ragioni di completezza, vale la pena notare che, ElementTree.tostring(...) vi darà un frammento di equivalente, ma non sempre identico al payload originale. Se, per qualche ragione molto raro, che si desidera estrarre il contenuto così come sono, è necessario utilizzare una soluzione di pura regex-based. Questo esempio è come uso regex- soluzione a base.

Non ho idea se una libreria esterna potrebbe essere un'opzione, ma in ogni caso - supponendo che c'è una <p> con questo testo sulla pagina, un jQuery-soluzione potrebbe essere:

alert($('p').html()); // returns blah <b>bleh</b> blih
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top