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

    Arquivos protegidos representando extração segura de TAR com Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    tarfile extraction_filter: extraia TAR com segurança

    Aprenda tarfile extraction_filter no Python para extrair arquivos TAR com validação, segurança e controle de caminhos.

    Ler mais

    Tempo de leitura: 6 minutos
    08/10/2026
    Código Python exibindo avisos controlados com catch_warnings
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    catch_warnings: capture warnings em testes Python

    Aprenda catch_warnings no Python para capturar, testar e controlar avisos com filtros específicos e segurança.

    Ler mais

    Tempo de leitura: 5 minutos
    07/10/2026
    Código Python representando referências persistentes do pickle
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    pickle persistent_id: serialize referências externas

    Aprenda pickle persistent_id no Python para serializar referências externas com IDs estáveis, validação, segurança e compatibilidade.

    Ler mais

    Tempo de leitura: 5 minutos
    07/10/2026
    Código binário representando buffers e memória no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    memoryview.count: conte valores sem copiar buffers

    Aprenda memoryview.count no Python para contar bytes e valores em buffers sem cópias, com formatos, limites e boas práticas.

    Ler mais

    Tempo de leitura: 6 minutos
    06/10/2026
    Código Python com anotações de tipos
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    annotationlib: evite imports circulares em anotações

    Aprenda annotationlib no Python para ler anotações adiadas, evitar imports circulares e criar ferramentas de introspecção seguras.

    Ler mais

    Tempo de leitura: 6 minutos
    06/10/2026
    Código Python em tela representando inspeção de módulos e pacotes
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    inspect.ispackage: identifique pacotes Python

    Aprenda inspect.ispackage no Python para identificar pacotes, explorar módulos e criar ferramentas de introspecção seguras.

    Ler mais

    Tempo de leitura: 5 minutos
    05/10/2026