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.
Memória e unlink
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.







