Formatear XML usando Python o PHP

Para formatear ficheros XML generalmente uso la variante 3 descrita en Formatear ficheros XML pero recientemente he tenido la necesidad de trabajar con ficheros XML que además de estar ofuscado una parte del XML usa entidades html, partamos de que debemos trabajar con un fichero XML como el siguiente:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE Edit_Mensaje SYSTEM "Edit_Mensaje.dtd">
<Edit_Mensaje>
     <Mensaje>
          <Remitente>
               <Nombre>Nombre del remitente</Nombre>
               <Mail> Correo del remitente </Mail>
          </Remitente>
          <Destinatario>
               <Nombre>Nombre del destinatario</Nombre>
               <Mail>Correo del destinatario</Mail>
          </Destinatario>
          <Texto>
               <Asunto>
                    Este es mi documento con una estructura muy sencilla
                    no contiene atributos ni entidades...
               </Asunto>
               <Parrafo>
                    Este es mi documento con una estructura muy sencilla
                    no contiene atributos ni entidades...
               </Parrafo>
          </Texto>
     </Mensaje>
</Edit_Mensaje>

Nota: Fichero Obtenido de Wikipedia: Extensible Markup Language

pero que en lugar de tenerlo como se muestra más arriba lo tenemos de la siguiente manera:

<Edit_Mensaje><Mensaje>&lt;Remitente&gt;&lt;Nombre&gt;Nombre del remitente&lt;/Nombre&gt;&lt;Mail&gt;Correo del remitente&lt;/Mail&gt;&lt;/Remitente&gt;&lt;Destinatario&gt;&lt;Nombre&gt;Nombre del destinatario&lt;/Nombre&gt;&lt;Mail&gt;Correo del destinatario&lt;/Mail&gt;&lt;/Destinatario&gt;&lt;Texto&gt;&lt;Asunto&gt;Este es mi documento con una estructura muy sencilla no contiene atributos ni entidades...&lt;/Asunto&gt;&lt;Parrafo&gt;Este es mi documento con una estructura muy sencilla no contiene atributos ni entidades... &lt;/Parrafo&gt;&lt;/Texto&gt;</Mensaje></Edit_Mensaje>

¿No muy bonito verdad? y no podemos aplicar las soluciones ofrecidas en Formatear ficheros XML debido a que el XML contiene entidades html así que tuve echarle mano y hacer un script primero en Python y luego en PHP:

Scripts

Ambos script ejecutan la siguiente lógica:

  1. Lee el nombre del fichero de la entrada standard
  2. Comprueba que el fichero existe y que el mismo se puede leer
  3. Almacena el contenido del fichero en una variable
  4. Decodifica entidades html
  5. Formatea el XML
  6. Visualiza el XML en un formato entendible

Script en Python

Fork me on Github
#!/usr/bin/python
import os
import re
import HTMLParser as parser
import xml.dom.minidom as minidom
import sys

try:
    # Read de file name from standard input
    filename = sys.argv[1]
    if os.path.isfile(filename) and os.access(filename, os.R_OK):
        # Open the file in read only mode
        file = open(filename, 'r')

        # Read the file and decode html entities
        xml = parser.HTMLParser().unescape(file.read())

        # Pretify the xml
        xml = minidom.parseString(xml).toprettyxml()

        # Handle issue with CDATA section due minidom add extraspace
        # before/after CDATA
        xml = re.sub('>\s+<!', '><!', xml)
        xml = re.sub(']>\s+<', ']><', xml)

        # Remove empty lines
        # Thanks to http://stackoverflow.com/questions/1140958/whats-a-quick-one-liner-to-remove-empty-lines-from-a-python-string
        print "".join([s for s in xml.strip().splitlines(True) if s.strip()])
    else:
        print "File is missing or is not readable!"
except IndexError:
    print "You must specify a file name!"
    

Script en PHP

Fork me on Github
#!/usr/bin/env php
<?php

// Check the scripts is called with arguments
if (empty($argv[1])) {
    die('You must specify a file!');
}

// Set the file name
$file = $argv[1];

// Verify if filename exists
if (!is_readable($file)) {
    die('File is missing or is not readable!');
}

// Get the file content
$content = file_get_contents($file);

// Verify the content is not empty
if (empty($content)) {
    die('File is empty nothing to do ;)');
}

// Decode html entities
$content = html_entity_decode($content);

// Parse the xml and format it
$doc = new DOMDocument();
$doc->preserveWhiteSpace = false;
$doc->formatOutput = true;
$doc->loadXML($content);

// Print the result
echo $doc->saveXML();

Ahora podemos integrar los scripts anteriores con gedit para ello (En este caso solo lo haremos para el script desarrollado en PHP):

  1. Ejecutamos gedit
  2. Menu > Tools > Manage External Tool
  3. Agregamos una nueva herramienta externa y establecemos los valores como muestra la figura

gedit-external-tool

Abrimos nuestro fichero xml al cual le llamamos garbage.xml

garbage-xml

Luego lo formateamos usando la combinación de teclas que establecimos cuando integramos la herramientas externa en el gedit y nos quedaría como muestra la figura.

ppxml

Lecturas recomendadas

* Formatear ficheros XML




2 Comentarios

  1. danesc87

    Excelente post, estoy usando el script en python con unas pequeñas modificaciones para hacerlo funcionar como acción personalizada en thunar, además de un port a python3.

    El repo github donde lo tengo alojado es en:

    https://github.com/danesc87/dotsAndConfs

    Responder
    1. sedlav (Publicaciones Autor)

      Gracias por tu contribución y hace un port a python3, los scripts anteriores también se pueden encontrar en:

      Python: https://gist.github.com/yoander/ae488ac7465a9e77f6f63b0c61e58f5c
      PHP: https://gist.github.com/yoander/7b9821ad5d077dc88cc29e1ab031ea0f

      Ambos script pueden usarse, distribuirse y modificarse libremente ya que son liberados bajos licencia GPLv2+

      Responder

Dejar un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *