tutorial leer extraer example etree datos datacamp con archivo python xml pretty-print

leer - xml python 3



Bonita impresiĆ³n de XML en Python (19)

Aquí está mi (¿hacky?) Solución para solucionar el problema del nodo de texto feo.

uglyXml = doc.toprettyxml(indent='' '') text_re = re.compile(''>/n/s+([^<>/s].*?)/n/s+</'', re.DOTALL) prettyXml = text_re.sub(''>/g<1></'', uglyXml) print prettyXml

El código anterior producirá:

<?xml version="1.0" ?> <issues> <issue> <id>1</id> <title>Add Visual Studio 2005 and 2008 solution files</title> <details>We need Visual Studio 2005/2008 project files for Windows.</details> </issue> </issues>

En lugar de esto:

<?xml version="1.0" ?> <issues> <issue> <id> 1 </id> <title> Add Visual Studio 2005 and 2008 solution files </title> <details> We need Visual Studio 2005/2008 project files for Windows. </details> </issue> </issues>

Descargo de responsabilidad: Probablemente hay algunas limitaciones.

¿Cuál es la mejor manera (o incluso las varias) de imprimir bonitos xml en Python?


BeautifulSoup tiene una función fácil de usar prettify() .

Se sangra un espacio por nivel de sangría. Funciona mucho mejor que pretty_print de lxml y es corto y dulce.

def pretty_print_xml(xml): proc = subprocess.Popen( [''xmllint'', ''--format'', ''/dev/stdin''], stdin=subprocess.PIPE, stdout=subprocess.PIPE, ) (output, error_output) = proc.communicate(xml); return output print(pretty_print_xml(data))


Como han señalado otros, lxml tiene una impresora bonita incorporada.

Tenga en cuenta que, de forma predeterminada, cambia las secciones CDATA a texto normal, lo que puede tener resultados desagradables.

Aquí hay una función de Python que conserva el archivo de entrada y solo cambia la sangría (observe el strip_cdata=False ). Además, se asegura de que la salida utilice UTF-8 como codificación en lugar del ASCII predeterminado (observe la encoding=''utf-8'' ):

from lxml import etree def prettyPrintXml(xmlFilePathToPrettyPrint): assert xmlFilePathToPrettyPrint is not None parser = etree.XMLParser(resolve_entities=False, strip_cdata=False) document = etree.parse(xmlFilePathToPrettyPrint, parser) document.write(xmlFilePathToPrettyPrint, pretty_print=True, encoding=''utf-8'')

Ejemplo de uso:

prettyPrintXml(''some_folder/some_file.xml'')


Echa un vistazo al módulo vkbeautify .

Es una versión de python de mi muy popular complemento javascript / nodejs con el mismo nombre. Puede imprimir bastante / minificar texto XML, JSON y CSS. La entrada y la salida pueden ser cadenas / archivos en cualquier combinación. Es muy compacto y no tiene ninguna dependencia.

Ejemplos :

import vkbeautify as vkb vkb.xml(text) vkb.xml(text, ''path/to/dest/file'') vkb.xml(''path/to/src/file'') vkb.xml(''path/to/src/file'', ''path/to/dest/file'')


Escribí una solución para recorrer un ElementTree existente y usar texto / cola para sangrar como se espera normalmente.

def prettify(element, indent='' ''): queue = [(0, element)] # (level, element) while queue: level, element = queue.pop(0) children = [(level + 1, child) for child in list(element)] if children: element.text = ''/n'' + indent * (level+1) # for child open if queue: element.tail = ''/n'' + indent * queue[0][0] # for sibling open else: element.tail = ''/n'' + indent * (level-1) # for parent close queue[0:0] = children # prepend so children come before siblings


Otra solución es tomar prestada esta función de indent , para usar con la biblioteca ElementTree que está integrada en Python desde la versión 2.5. Así es como se vería eso:

from xml.etree import ElementTree def indent(elem, level=0): i = "/n" + level*" " j = "/n" + (level-1)*" " if len(elem): if not elem.text or not elem.text.strip(): elem.text = i + " " if not elem.tail or not elem.tail.strip(): elem.tail = i for subelem in elem: indent(subelem, level+1) if not elem.tail or not elem.tail.strip(): elem.tail = j else: if level and (not elem.tail or not elem.tail.strip()): elem.tail = j return elem root = ElementTree.parse(''/tmp/xmlfile'').getroot() indent(root) ElementTree.dump(root)


Puede usar la biblioteca externa popular xmltodict , con unparse y pretty=True obtendrá el mejor resultado:

xmltodict.unparse( xmltodict.parse(my_xml), full_document=False, pretty=True)

full_document=False contra <?xml version="1.0" encoding="UTF-8"?> en la parte superior.


Resolví esto con algunas líneas de código, abriendo el archivo, revisándolo y agregando sangría, luego guardándolo de nuevo. Estaba trabajando con pequeños archivos xml y no quería agregar dependencias, o más bibliotecas para instalar para el usuario. De todos modos, esto es lo que terminé con:

f = open(file_name,''r'') xml = f.read() f.close() #Removing old indendations raw_xml = '''' for line in xml: raw_xml += line xml = raw_xml new_xml = '''' indent = '' '' deepness = 0 for i in range((len(xml))): new_xml += xml[i] if(i<len(xml)-3): simpleSplit = xml[i:(i+2)] == ''><'' advancSplit = xml[i:(i+3)] == ''></'' end = xml[i:(i+2)] == ''/>'' start = xml[i] == ''<'' if(advancSplit): deepness += -1 new_xml += ''/n'' + indent*deepness simpleSplit = False deepness += -1 if(simpleSplit): new_xml += ''/n'' + indent*deepness if(start): deepness += 1 if(end): deepness += -1 f = open(file_name,''w'') f.write(new_xml) f.close()

A mí me funciona, tal vez alguien lo use :)


Si está usando una implementación DOM, cada uno tiene su propia forma de impresión integrada:

# minidom # document.toprettyxml() # 4DOM # xml.dom.ext.PrettyPrint(document, stream) # pxdom (or other DOM Level 3 LS-compliant imp) # serializer.domConfig.setParameter(''format-pretty-print'', True) serializer.writeToString(document)

Si está usando otra cosa sin su propia impresora bonita, o esas impresoras bonitas no lo hacen como usted quiere, probablemente tenga que escribir o crear una subclase de su propio serializador.


Si tiene xmllint , puede generar un subproceso y usarlo. xmllint --format <file> imprime bastante su entrada XML en salida estándar.

Tenga en cuenta que este método utiliza un programa externo a python, lo que lo convierte en una especie de hack.

from bs4 import BeautifulSoup bs = BeautifulSoup(open(xml_file), ''xml'') print bs.prettify()


Traté de editar la respuesta de "ade" anteriormente, pero no me dejaba editar después de que inicialmente proporcioné comentarios de forma anónima. Esta es una versión con menos errores de la función para imprimir bastante un ElementTree.

def indent(elem, level=0, more_sibs=False): i = "/n" if level: i += (level-1) * '' '' num_kids = len(elem) if num_kids: if not elem.text or not elem.text.strip(): elem.text = i + " " if level: elem.text += '' '' count = 0 for kid in elem: indent(kid, level+1, count < num_kids - 1) count += 1 if not elem.tail or not elem.tail.strip(): elem.tail = i if more_sibs: elem.tail += '' '' else: if level and (not elem.tail or not elem.tail.strip()): elem.tail = i if more_sibs: elem.tail += '' ''


Tuve algunos problemas con la impresión bonita de minidom. doc.toprettyxml(encoding=''latin-1'') cada vez que intentaba imprimir un documento con caracteres fuera de la codificación dada, por ejemplo, si tenía un β en un documento y probaba doc.toprettyxml(encoding=''latin-1'') . Aquí está mi solución para ello:

def toprettyxml(doc, encoding): """Return a pretty-printed XML document in a given encoding.""" unistr = doc.toprettyxml().replace(u''<?xml version="1.0" ?>'', u''<?xml version="1.0" encoding="%s"?>'' % encoding) return unistr.encode(encoding, ''xmlcharrefreplace'')


Tuve este problema y lo resolví así:

def write_xml_file (self, file, xml_root_element, xml_declaration=False, pretty_print=False, encoding=''unicode'', indent=''/t''): pretty_printed_xml = etree.tostring(xml_root_element, xml_declaration=xml_declaration, pretty_print=pretty_print, encoding=encoding) if pretty_print: pretty_printed_xml = pretty_printed_xml.replace('' '', indent) file.write(pretty_printed_xml)

En mi código este método se llama así:

try: with open(file_path, ''w'') as file: file.write(''<?xml version="1.0" encoding="utf-8" ?>'') # create some xml content using etree ... xml_parser = XMLParser() xml_parser.write_xml_file(file, xml_root, xml_declaration=False, pretty_print=True, encoding=''unicode'', indent=''/t'') except IOError: print("Error while writing in log file!")

Esto funciona solo porque etree por defecto usa two spaces para sangrar, lo cual no encuentro mucho enfatizando la sangría y por lo tanto no es bonito. No pude encontrar ninguna configuración para etree o parámetro para que una función cambie la sangría estándar de etree. Me gusta lo fácil que es usar etree, pero esto me molestó mucho.


Una alternativa si no quiere tener que volver a analizar, está la biblioteca xmlpp.py con la función get_pprint() . Funcionó bien y sin problemas para mis casos de uso, sin tener que volver a analizar un objeto ElementTree lxml.


lxml es reciente, actualizado e incluye una función de impresión bonita

import lxml.etree as etree x = etree.parse("filename") print etree.tostring(x, pretty_print=True)

Revisa el tutorial lxml: http://lxml.de/tutorial.html



Para convertir un documento XML completo en un documento XML bonito
(p. ej .: suponiendo que ha extraído [descomprimido] un archivo .odt o .ods de LibreOffice Writer, y desea convertir el archivo "content.xml" feo en uno bonito para el control de versiones automatizado de git y la git difftool de datos de .odt /.ods archivos , como estoy implementando here )

import xml.dom.minidom file = open("./content.xml", ''r'') xml_string = file.read() file.close() parsed_xml = xml.dom.minidom.parseString(xml_string) pretty_xml_as_string = parsed_xml.toprettyxml() file = open("./content_new.xml", ''w'') file.write(pretty_xml_as_string) file.close()

Referencias:
- Gracias a la respuesta de Ben Noland en esta página que me ayudó a llegar hasta allí.


from yattag import indent pretty_string = indent(ugly_string)

No agregará espacios o nuevas líneas dentro de los nodos de texto, a menos que lo solicite con:

indent(mystring, indent_text = True)

Puede especificar qué debe ser la unidad de sangría y qué aspecto debe tener la nueva línea.

pretty_xml_string = indent( ugly_xml_string, indentation = '' '', newline = ''/r/n'' )

El documento está en la página de inicio de http://www.yattag.org .


import xml.dom.minidom xml = xml.dom.minidom.parse(xml_fname) # or xml.dom.minidom.parseString(xml_string) pretty_xml_as_string = xml.toprettyxml()