minidom no Python: manipule XML com DOM

Publicado em: 22/08/2026
Tempo de leitura: 5 minutos
Detailed shot of a Jungle Carpet Python (Morelia spilota cheynei) in its natural habitat.

xml.dom.minidom é uma implementação compacta do Document Object Model, ou DOM, na biblioteca padrão do Python. Em vez de trabalhar apenas com elementos e filhos, o DOM representa documento, elementos, atributos, nós de texto, comentários e outros tipos por meio de uma API parecida com a encontrada em navegadores e outras linguagens.

O módulo é útil quando uma integração exige conceitos DOM, quando você precisa manipular nós individualmente ou portar código de outra plataforma. Para a maioria dos trabalhos comuns com XML, a própria documentação recomenda ElementTree no Python, que costuma ser mais simples e econômico.

Parseando um arquivo

from xml.dom import minidom

with minidom.parse("catalogo.xml") as documento:
    raiz = documento.documentElement
    print(raiz.tagName)

parse() recebe um nome de arquivo ou objeto semelhante a arquivo e devolve um Document. O context manager chama unlink() ao sair, liberando referências internas mais cedo.

O parsing constrói toda a árvore antes de retornar. Portanto, não use minidom para arquivos enormes ou fluxos sem limites.

Parseando uma string

xml = "<produto id='7'><nome>Teclado</nome></produto>"

with minidom.parseString(xml) as documento:
    produto = documento.documentElement
    print(produto.getAttribute("id"))

Antes de chamar parseString(), imponha limite de bytes ou caracteres. XML pequeno pode criar uma árvore grande, dependendo da estrutura e do parser.

Tipos de nós

Cada objeto possui nodeType. Tipos comuns incluem DOCUMENT_NODE, ELEMENT_NODE, TEXT_NODE, COMMENT_NODE e PROCESSING_INSTRUCTION_NODE.

from xml.dom import Node

for no in produto.childNodes:
    if no.nodeType == Node.ELEMENT_NODE:
        print("elemento", no.tagName)
    elif no.nodeType == Node.TEXT_NODE:
        print("texto", repr(no.data))

Espaços e quebras entre tags também podem virar nós de texto. Não presuma que o primeiro filho é sempre um elemento.

Obtendo elementos

produtos = documento.getElementsByTagName("produto")

for produto in produtos:
    print(produto.getAttribute("id"))

getElementsByTagName() procura recursivamente todos os descendentes. Para filhos diretos, filtre childNodes. Em documentos grandes, buscas repetidas podem custar tempo; crie índices da aplicação quando necessário.

Extraindo texto corretamente

Um elemento pode conter vários nós de texto e elementos misturados. Crie uma função que percorra somente os nós desejados.

from xml.dom import Node

def texto_direto(elemento: Node) -> str:
    partes = []
    for filho in elemento.childNodes:
        if filho.nodeType == Node.TEXT_NODE:
            partes.append(filho.data)
    return "".join(partes)

Para conteúdo recursivo, percorra descendentes. Defina se comentários, CDATA e espaços devem ser preservados.

Atributos

produto.setAttribute("ativo", "sim")
identificador = produto.getAttribute("id")

if produto.hasAttribute("temporario"):
    produto.removeAttribute("temporario")

getAttribute() retorna string vazia quando o atributo não existe. Use hasAttribute() quando precisar diferenciar ausência de valor vazio.

Criando um documento

from xml.dom.minidom import getDOMImplementation

implementacao = getDOMImplementation()
documento = implementacao.createDocument(None, "catalogo", None)
raiz = documento.documentElement

produto = documento.createElement("produto")
produto.setAttribute("id", "7")
raiz.appendChild(produto)

nome = documento.createElement("nome")
nome.appendChild(documento.createTextNode("Teclado"))
produto.appendChild(nome)

Sempre crie nós usando o Document correspondente. Não instancie classes internas diretamente.

Adicionando e removendo nós

preco = documento.createElement("preco")
preco.appendChild(documento.createTextNode("199.90"))
produto.appendChild(preco)

produto.removeChild(preco)
preco.unlink()

removeChild() separa o nó, mas ele ainda pode manter referências. unlink() torna o nó e descendentes inutilizáveis e facilita a liberação de memória.

Clonando nós

copia = produto.cloneNode(deep=True)
copia.setAttribute("id", "8")
raiz.appendChild(copia)

Com deep=False, apenas o próprio nó é clonado. Revise identificadores e referências antes de inserir cópias, para não gerar IDs duplicados no documento.

Namespaces

URI = "https://example.com/catalogo"

documento = implementacao.createDocument(URI, "cat:catalogo", None)
produto = documento.createElementNS(URI, "cat:produto")
documento.documentElement.appendChild(produto)

Use métodos terminados em NS, como createElementNS(), getElementsByTagNameNS() e setAttributeNS(). O prefixo é uma representação; a identidade é a URI do namespace.

Serialização com toxml

dados = documento.toxml(
    encoding="utf-8",
    standalone=True,
)

with open("catalogo.xml", "wb") as arquivo:
    arquivo.write(dados)

Com encoding, toxml() retorna bytes. Sem encoding, retorna string Unicode. Use nomes válidos na declaração XML, como UTF-8.

Pretty print

bonito = documento.toprettyxml(
    indent="  ",
    newl="\n",
    encoding="utf-8",
)

toprettyxml() melhora legibilidade, mas pode adicionar espaços e quebras de linha que alteram conteúdo significativo em documentos com texto misto. Para dados assinados ou comparação byte a byte, não use pretty print.

writexml

with open("catalogo.xml", "w", encoding="utf-8") as arquivo:
    documento.writexml(
        arquivo,
        addindent="  ",
        newl="\n",
        encoding="UTF-8",
    )

O writer de writexml() recebe texto, não bytes. Combine o modo do arquivo com o tipo esperado.

Escrita atômica

Grave em arquivo temporário no mesmo diretório, faça flush quando necessário e substitua o destino somente após sucesso. Veja tempfile no Python.

O DOM mantém referências entre pais e filhos e armazena toda a árvore. Para documentos grandes, isso consome mais memória do que APIs de streaming. Chame documento.unlink() quando terminar ou use with minidom.parse(...) as documento.

Depois de unlink(), não reutilize os nós. A operação existe para liberar recursos cedo, não para limpar parcialmente e continuar trabalhando.

XML externo e segurança

A documentação direciona para as vulnerabilidades de XML. Dados não confiáveis podem explorar expansão de entidades, profundidade e consumo de recursos. Limite tamanho antes do parsing, use parser atualizado e considere bibliotecas endurecidas.

Não use minidom para abrir uma URL ou caminho escolhido pelo usuário. Separe obtenção, validação de destino e parsing para evitar SSRF e leitura de arquivos locais.

Parser SAX personalizado

parse() pode receber um parser SAX2 já configurado. Isso permite instalar um entity resolver ou features antes de construir o DOM.

import xml.sax
from xml.dom import minidom

parser = xml.sax.make_parser()
# Configure features e resolver antes do parsing.
documento = minidom.parse("dados.xml", parser=parser)

O minidom altera o document handler e ativa namespaces. Teste a configuração exata do parser na versão usada em produção.

Comentários e instruções

O DOM pode representar comentários e processing instructions. Trate seus conteúdos como dados não confiáveis. Ao transformar documentos, defina se esses nós devem ser preservados ou removidos.

Comparação com ElementTree

ElementTree oferece uma API mais Pythonica para a maioria dos arquivos XML e possui opções incrementais. Minidom faz sentido quando você precisa da API DOM, de tipos de nós explícitos, ou de compatibilidade com código baseado no padrão W3C.

Validação

Parsing não valida a estrutura de negócio. Depois de construir o DOM, confira elemento raiz, namespaces, atributos obrigatórios, cardinalidade, tipos, intervalos e relações. Minidom não valida XSD automaticamente.

Erros

XML malformado pode lançar exceções do parser SAX. Capture a região de parsing e preserve a causa sem divulgar o documento completo.

from xml.parsers.expat import ExpatError

try:
    documento = minidom.parseString(xml_recebido)
except ExpatError as erro:
    raise ValueError(
        f"XML inválido na linha {erro.lineno}, coluna {erro.offset}"
    ) from erro

Testes recomendados

Teste nós de texto entre elementos, comentários, CDATA, atributos vazios e ausentes, namespaces, clonagem profunda, remoção, pretty print, encoding, documento grande, XML malformado, profundidade excessiva, cleanup com unlink e validação de domínio.

Erros comuns

Os erros frequentes são usar o primeiro childNode sem verificar tipo, confundir atributo ausente com string vazia, manter documentos grandes em memória, esquecer unlink, usar pretty print em texto misto, criar nós sem o Document, ignorar namespaces, parsear XML ilimitado e tratar parsing como validação.

Conclusão

xml.dom.minidom fornece uma implementação DOM compacta e familiar. Use-a quando o modelo de nós completo for importante. Para tarefas simples ou arquivos grandes, ElementTree ou SAX podem ser opções melhores.

Consulte a documentação oficial de minidom e a especificação DOM Level 1. Para XML externo, combine limites, parser atualizado, validação e liberação explícita de recursos.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Conteúdo do artigo

    Artigos relacionados

    Vibrant green snake coiled on a tree branch amidst lush jungle foliage.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    ElementTree: leia e modifique XML no Python

    Aprenda ElementTree no Python para ler, buscar, modificar e gerar XML com namespaces, parsing incremental, limites e segurança.

    Ler mais

    Tempo de leitura: 5 minutos
    22/08/2026
    High-angle view of woman coding on a laptop, with a Python book nearby. Ideal for programming and tech content.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    poplib no Python: leia e-mails com POP3

    Aprenda poplib no Python para acessar POP3 com TLS, listar e baixar mensagens, usar UIDL, limitar dados e evitar exclusões

    Ler mais

    Tempo de leitura: 6 minutos
    22/08/2026
    A close-up of a laptop on a table, displaying a book on test-driven software with Python, set in a comfortable environment.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    imaplib no Python: leia e-mails com IMAP

    Aprenda imaplib no Python para acessar caixas IMAP com TLS, buscar por UID, ler mensagens sem marcá-las, usar flags e

    Ler mais

    Tempo de leitura: 5 minutos
    22/08/2026
    A developer typing code on a laptop with a Python book beside in an office.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    ftplib no Python: FTP e FTPS seguros

    Aprenda ftplib no Python para listar, baixar e enviar arquivos por FTP ou FTPS com TLS, timeouts, limites, retomada e

    Ler mais

    Tempo de leitura: 5 minutos
    21/08/2026
    Rack de servidores representando um endpoint criado com xmlrpc.server no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    xmlrpc.server: crie servidores XML-RPC

    Aprenda xmlrpc.server no Python para criar servidores XML-RPC, registrar funções, limitar métodos e caminhos e evitar exposição insegura.

    Ler mais

    Tempo de leitura: 6 minutos
    21/08/2026
    Cabos conectados a servidor representando chamadas remotas com xmlrpc.client no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    xmlrpc.client no Python: chamadas RPC

    Aprenda xmlrpc.client no Python para chamar serviços XML-RPC, tratar Fault e ProtocolError, usar TLS, tipos compatíveis e limites seguros.

    Ler mais

    Tempo de leitura: 4 minutos
    21/08/2026