Calificación:
  • 0 voto(s) - 0 Media
  • 1
  • 2
  • 3
  • 4
  • 5
Python y XML indentado
#1
Buenas.

Tengo un pequeño problema al procesar un XML desde Python y espero que alguien pueda echarme un cable. Simplificaré mi ejercicio para que nadie pierda mucho tiempo con esto.

Creé este fichero XML:

Código:
<Equipo>
     <ListaPersonas>
          <Persona>
               <Dni>11111111A</Dni>
               <Nombre>Ana</Nombre>
               <Sexo>Femenino</Sexo>
          </Persona>
          <Persona>
               <Dni>22222222B</Dni>
               <Nombre>Antonio</Nombre>
               <Sexo>Masculino</Sexo>
          </Persona>
          <Persona>
               <Dni>33333333C</Dni>
               <Nombre>Marta</Nombre>
               <Sexo>Femenino</Sexo>
          </Persona>
     </ListaPersonas>
</Equipo>

Y también el siguiente código Python:

Código:
from xml.etree import ElementTree

arbolXML = ElementTree.parse("Fichero.xml");
equipoXML = arbolXML.getroot();
listPersonasXML = equipoXML[0];
primeraPersonaXML = listPersonasXML[0];

unidad = ElementTree.Element("Ciudad");
unidad.text = "Madrid";
primeraPersonaXML.append(unidad);
arbolXML.write("Fichero.xml");

Después de ejecutar este código, el fichero XML queda así:

Código:
<Equipo>
     <ListaPersonas>
          <Persona>
               <Dni>11111111A</Dni>
               <Nombre>Ana</Nombre>
               <Sexo>Femenino</Sexo>
          <Ciudad>Madrid</Ciudad></Persona>
          <Persona>
               <Dni>22222222B</Dni>
               <Nombre>Antonio</Nombre>
               <Sexo>Masculino</Sexo>
          </Persona>
          <Persona>
               <Dni>33333333C</Dni>
               <Nombre>Marta</Nombre>
               <Sexo>Femenino</Sexo>
          </Persona>
     </ListaPersonas>
</Equipo>

Como se puede ver en la 7ª línea, el campo ciudad se me inserta pero me rompe toda la estructura de indentación. ¿Alguien tiene alguna idea de cómo arreglar esto de una forma fácil? Me gustaría conservar una estructura limpia y legible en el XML después de procesarlo para que cualquiera pueda leerlo y modificarlo directamente desde el fichero.

Millones de gracias.
Responder
#2
Hola. El módulo estándar no puede por sí mismo controlar ese tipo de cuestiones secundarias al generar el código XML. Tendrías que crear tu propia función que reemplace a write() para que se aplique la sangría correspondiente. O bien podés usar una librería más completa como lxml que tiene recursos para manejar estas situaciones:

  1. from lxml import etree
  2.  
  3. parser = etree.XMLParser(remove_blank_text=True)
  4. arbolXML = etree.parse("Fichero.xml", parser=parser)
  5. equipoXML = arbolXML.getroot()
  6. listPersonasXML = equipoXML[0]
  7. primeraPersonaXML = listPersonasXML[0]
  8.  
  9. unidad = etree.Element("Ciudad")
  10. unidad.text = "Madrid"
  11. primeraPersonaXML.append(unidad)
  12. arbolXML.write("Fichero.xml", pretty_print=True)


Como verás, la API es bastante similar a la del módulo estándar.

Saludos!
Responder
#3
(07-01-2019, 01:41 PM)Francisco escribió: Hola. El módulo estándar no puede por sí mismo controlar ese tipo de cuestiones secundarias al generar el código XML. Tendrías que crear tu propia función que reemplace a write() para que se aplique la sangría correspondiente. O bien podés usar una librería más completa como lxml que tiene recursos para manejar estas situaciones:

  1. from lxml import etree
  2.  
  3. parser = etree.XMLParser(remove_blank_text=True)
  4. arbolXML = etree.parse("Fichero.xml", parser=parser)
  5. equipoXML = arbolXML.getroot()
  6. listPersonasXML = equipoXML[0]
  7. primeraPersonaXML = listPersonasXML[0]
  8.  
  9. unidad = etree.Element("Ciudad")
  10. unidad.text = "Madrid"
  11. primeraPersonaXML.append(unidad)
  12. arbolXML.write("Fichero.xml", pretty_print=True)


Como verás, la API es bastante similar a la del módulo estándar.

Saludos!

Gracias por la idea, aunque me costará probar esa solución. Toqueteé un poco lxml cuando empecé a programar con Python (versión 2.7), pero luego decidí pasarme a una versión más actual (versión 3.5) y en ella no conseguí usar esa librería. No sé si lxml no viene por defecto con Python 3.5 o si al instalar esa librería por consola (uso Linux) se me instaló solo en la versión de Python 2.7. Fuera lo que fuera, en el código no pude importarla para usarla. Igual tengo que buscar e instalar una versión de la librería lxml que se entienda con Python 3.5. Me pondré a investigar eso.
Responder
#4
lxml soporta perfectamente Python 3 (de hecho el código lo probé en Python 3.7). En Linux bastaría con ejecutar pip3.5 install lxml (o pip3, o pip según cómo lo tengas configurado).

Saludos
Responder
#5
(07-01-2019, 11:17 PM)Francisco escribió: lxml soporta perfectamente Python 3 (de hecho el código lo probé en Python 3.7). En Linux bastaría con ejecutar pip3.5 install lxml (o pip3, o pip según cómo lo tengas configurado).

Saludos

Ahora mismo te estoy queriendo mucho.  Big Grin  

Funciona perfecto y es justo lo que necesitaba, muchas gracias. No solo he resuelto esto con tu ayuda, también he aprendido alguna cosa nueva (no sabía nada sobre esa especie de "aptitude para Python" llamada Pip).

Mañana investigaré un poco por Internet para saber a qué viene esta línea: "parser = etree.XMLParser(remove_blank_text=True)". No quiero solo copiar y pegar, quiero entender eso.

Muchas gracias de nuevo.
Responder
#6
Me alegro que te haya servido. Respecto a esa línea te recomiendo el siguiente enlace para esclarecer un poco el código: https://lxml.de/1.3/FAQ.html#why-doesn-t...xml-output.

Saludos!
Responder


Salto de foro:


Usuarios navegando en este tema: 2 invitado(s)