Cargando...

Convertir XML a JSON e Importar JSON a MongoDB con Python y Docker

Aprende cómo Convertir un fichero con datos XML a JSON e Importar este archivo JSON a MongoDB utilizando Python y contenedores Docker.

Objetivos a cumplir:

  • Levantar contenedores Docker de Python y MongoDB.
  • Comprender el funcionamiento de los contenedores en cuestión.
  • Desarrollar el algoritmo en Python que se acota en las siguientes instrucciones:
    • Descargar un fichero .XML de la nube.
    • Convertir el fichero XML a JSON y generar un fichero JSON.
    • Importar el fichero JSON a MongoDB.
  • Conseguir una mirada más a Docker en la manipulación de contenedores.

Descargar el código fuente

Se descarga el repositorio Convert-XML-to-JSON-and-Import-JSON-to-MongoDB en GitHub. Este repositorio recoge las configuraciones Docker necesarias para levantar los servicios Python y MongoDB con Docker-Compose. En estos casos, te invito a que, si deseas participar en la mejora del mismo, bienvenido sea tu aporte al repositorio, que también es tuyo.

Clonas el repositorio por medio de Git.

git clone https://github.com/jersonmartinez/Convert-XML-to-JSON-and-Import-JSON-to-MongoDB.git

Arrancar el proyecto con Docker Compose

Para poner en marcha la instalación de los servicios y que los contenedores sean creados. Es tan sencillo como ir a la terminal donde puedas correr Docker y ubicarse en el repositorio "Convert-XML-to-JSON-and-Import-JSON-to-MongoDB" que anteriormente se ha clonado y lanzar la siguiente instrucción:

$ docker-compose up --build -d

Creating network "convert-xml-to-json-and-import-json-to-mongodb_default" with the default driver
Pulling database (mongo:latest)...
latest: Pulling from library/mongo
3b65ec22a9e9: Pull complete
016bc871e2b3: Pull complete
9ddd649edd82: Pull complete
39bf776c01e4: Pull complete
f7f0405a2fe3: Pull complete
417812e2676c: Pull complete
905384a6c9a9: Pull complete
768aa2a1becc: Pull complete
623c0121bf78: Pull complete
Digest: sha256:6f90d92eb8ed5c52eb602a734697b329a0441949d9bb737ddcd5dae56552cac9
Status: Downloaded newer image for mongo:latest
Building web
[+] Building 60.7s (10/15)
...
Creating mongodb ... done
Creating api     ... done

Se verifica que los contenedores estén creados, porque levantado solo uno y es el MongoDB. El primero contenedor donde se encuentra Python, este solo se ejecutó para correr el script Python que se ha señalado para realizar todas las operaciones mencionadas en los objetivos.

$ docker ps -a
CONTAINER ID   IMAGE                                                COMMAND                  CREATED              STATUS                          PORTS                                  NAMES
e2820f321600   convert-xml-to-json-and-import-json-to-mongodb_web   "python ./import-mon…"   About a minute ago   Exited (0) About a minute ago                                          api
ac19e1fa894f   mongo:latest                                         "docker-entrypoint.s…"   About a minute ago   Up About a minute               0.0.0.0:27017-27019->27017-27019/tcp   mongodb

Contenedores Python y MongoDB

El Dockerfile invocado desde el Docker Compose contiene las configuraciones para descargar la imagen python:3, además de ubicarse en el directorio /app. Copia el fichero requirements.txt, donde contiene las librerías de Python que se necesitan para lograr el cometido del algoritmo y de esta práctica. Ejecuta por medio de comandos, la instrucción python ./import-mongo.py.

# syntax=docker/dockerfile:1
FROM python:3

WORKDIR /app
COPY requirements.txt ./

RUN pip install -r requirements.txt

COPY . .

CMD [ "python", "./import-mongo.py" ]

El fichero de configuración docker-compose.yml tiene dos servicios, el de Python y MongoDB.

  • El primer servicio (web) tiene un enlace con el contenedor de base de datos, además que crea un volumen. Declara su conexión a la red por omisión, de este modo, es posible que el enlace se de sin problemas.
  • El segundo servicio (database), solicita crear el contenedor a partir de la imagen mongo:latest. En los puertos 27017-27019. Se le pasan algunas variables de entorno donde se especifician las credenciales del servidor de base de datos, MongoDB. Se crean algunos volúmenes para la persistencia de los datos.
version: '3.9'
services:
  web:
    env_file:
      - .env
    container_name: ${WEB_HOST}
    hostname: ${WEB_HOST}
    build: ./app
    links:
      - database
    depends_on:
      - database
    volumes:
      - ./app:/app
    networks:
      - default
  database:
    image: mongo:latest
    env_file:
      - .env
    container_name: ${MONGO_HOST}
    hostname: ${MONGO_HOST}
    environment:
      MONGO_INITDB_ROOT_USERNAME: ${MONGO_USER}
      MONGO_INITDB_ROOT_PASSWORD: ${MONGO_PASS}
      MONGO_INITDB_DATABASE: ${MONGO_DB}
    volumes:
      - ./mongo-init.js:/docker-entrypoint-initdb.d/mongo-init.js:ro
      - ./mongo-volume:/data/db
      - ./mongo-volume/log:/var/log/mongodb/
    ports:
      - '27017-27019:27017-27019'
    networks:
      - default
volumes:
  persistent:

Ficheros de configuración (.env, mongo-init.js) donde se definen las credenciales del MongoDB, además de las variables de entorno.

.env

WEB_HOST=api

MONGO_HOST=mongodb
MONGO_PORT=27017
MONGO_USER=root-master
MONGO_PASS=password-master
MONGO_DB=db-sports

mongo-init.js

db.createUser(
    {
        user: 'root-master',
        pwd: 'password-master',
        roles: [
            {
                role: 'readWrite',
                db: 'db-sports'
            }
        ]
    }
)

De este modo, se logra el cometido de levantar los contenedores con la configuración necesaria.

Convertir XML a JSON e Importar JSON a MongoDB

El algoritmo está conformado en una clase y 4 sencillos métodos:

  1. Método principal: getData(), descarga el fichero .XML, llama al siguiente método convertXMLtoJSON().
  2. Método convertXMLtoJSON(). En efecto, convierte el contenido XML a JSON y genera el nuevo archivo. Además, llama al método importJSONtoMongoDB().
  3. Método importJSONtoMongoDB(). Llama al método getDB() para conectarse al servidor de base de datos MongoDB. Además importa los datos JSON a MongoDB.
  4. Método getDB() realiza la conexión al servidor de base de datos y devuelve el flujo a los métodos que le soliciten.
import os
import xmltodict
import json
import requests
from pymongo import MongoClient

class getScriptXML:
    def __init__(self, url, save_folder, filename):
        self.url = url
        self.save_folder = save_folder
        self.filename = filename

    def getData(self):
        if not os.path.isdir(self.save_folder):
            os.system("mkdir " + self.save_folder)

        path = self.save_folder + "/" + self.filename

        response = requests.get(self.url)
        with open(path, 'wb') as file:
            file.write(response.content)
        
        self.convertXMLtoJSON(path)

    def convertXMLtoJSON(self, path):
        with open(path, "r") as xmlfileObj:
            #Converting xml data to dictionary
            data_dict = xmltodict.parse(xmlfileObj.read())
            xmlfileObj.close()
            
            #Creating JSON object using dictionary object
            jsonObj = json.dumps(data_dict)

        if not os.path.isdir("JSON"):
            os.system("mkdir " + "JSON")

        #storing json data to json file
        with open("JSON/sports.json", "w") as jsonfileObj:
            jsonfileObj.write(jsonObj)
            jsonfileObj.close()
        
        self.importJSONtoMongoDB()

    def getDB(self):
        mongoClient = MongoClient("mongodb://root-master:password-master@mongodb:27017/?authMechanism=DEFAULT&authSource=db-sports")

        return mongoClient["db-sports"]

    def importJSONtoMongoDB(self):
        db = self.getDB()
        Collection = db["sports"]

        with open('JSON/sports.json') as file:
            file_data = json.load(file)

        if isinstance(file_data, list):
            Collection.insert_many(file_data)
        else:
            Collection.insert_one(file_data)

if __name__ == "__main__":
    getScriptXML(
        'https://fx-nunchee-assets.s3.amazonaws.com/data/sports.xml',
        'XML',
        'sports.xml'
    ).getData()

Implementación del algoritmo y manipulación de contenedores

La forma en que este script es ejecutado es de dos maneras:

  1. En cuanto se levantan los servicios. La primera vez que se ejecuta el Docker Compose con su respectiva configuración.
  2. Cuando intentas levantar el contenedor "api".

Iniciar el contenedor "api".

$ docker start api
api

El contenedor "api" en cuanto se inicia, ejecuta el algoritmo por medio de la instrucción python import-mongo.py que fue definido en el Dockerfile. En cuanto finalice la ejecución, el contenedor también cumple su ciclo de vida, siendo este terminado. Por tal razón, si deseas volver a ejecutar le script, será iniciar el contenedor "api" específicamente. Lo contrario sucede con el MongoDB que siempre se mantiene activo.

Conectarse al MongoDB Server desde MongoDB Compass

Eliminando los contenedores y sus volúmenes

$ docker-compose down --volumes
Stopping mongodb ... done
Removing api     ... done
Removing mongodb ... done
Removing network convert-xml-to-json-and-import-json-to-mongodb_default
Removing volume convert-xml-to-json-and-import-json-to-mongodb_persistent

Eliminando la cache de los contenedores en Docker

Esta instrucción es solo por si existe algún problema al levantar los contenedores. Puede que haya que hacer alguna limpieza.

docker system prune -a -f && docker build prune -a -f

Eliminando los ficheros creados por MongoDB

El directorio mongo-value se usa para almacenar los registros del MongoDB, siendo este un volumen de datos señalado en el docker-compose.yml. Es importante volver a crearlo.

rm -rf mongo-value app/JSON app/XML && mkdir mongo-value

Concluyo en lo siguiente:

  • Se han levantado los contenedores Docker de Python y MongoDB.
  • Se comprendió (explicó y describió) el funcionamiento de los contenedores en cuestión.
  • Se desarrolló el algoritmo en Python que se acota en las siguientes instrucciones:
    • Se comprende el método para descargar un fichero .XML de la nube.
    • Se comprende el método para convertir el fichero XML a JSON y generar un fichero JSON.
    • Se Importa el fichero JSON a MongoDB.
  • Se ha conseguido una mirada más sobre Docker en la manipulación de contenedores y en la limpieza de los mismos.
  • John Doe
    43 Sales$156,24 Totals
    62%
  • Rosy O'Dowell
    12 Leads$56,24 Totals
    32%

With supporting text below as a natural lead-in to additional content.

Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled.