saxutils no Python: utilitários para XML

Publicado em: 23/08/2026
Tempo de leitura: 6 minutos
Close-up view of a computer screen displaying code in a software development environment.

O módulo xml.sax.saxutils reúne funções e classes auxiliares para aplicações XML baseadas em SAX. Ele ajuda a escapar texto, preparar valores de atributos, desfazer entidades conhecidas, gerar XML a partir de eventos e criar filtros entre o parser e o código da aplicação.

Apesar do nome ligado a SAX, algumas funções são úteis mesmo fora de um parser orientado a eventos. Ainda assim, elas precisam ser usadas no contexto correto. Escapar texto XML não é o mesmo que sanitizar HTML, validar dados, impedir injeção em SQL ou proteger comandos de shell.

As principais funções

As funções mais conhecidas são escape(), unescape() e quoteattr(). As classes principais são XMLGenerator e XMLFilterBase. O módulo também oferece prepare_input_source() para normalizar entradas aceitas por parsers.

Escapar texto com escape()

escape() substitui os caracteres &, < e > pelas entidades XML correspondentes. Isso permite colocar um texto dentro do conteúdo de um elemento sem quebrar a estrutura.

from xml.sax.saxutils import escape

texto = "5 < 10 & 12 > 8"
seguro = escape(texto)
print(seguro)
# 5 &lt; 10 &amp; 12 &gt; 8

A função sempre escapa esses três caracteres. O argumento opcional entities permite adicionar substituições extras, mas não deve ser usado como mecanismo genérico de tradução de strings.

from xml.sax.saxutils import escape

resultado = escape(
    "linha 1\nlinha 2",
    {"\n": "
"},
)

Use substituições adicionais somente quando o formato exigir. Transformações arbitrárias podem produzir XML difícil de ler ou incompatível com o consumidor.

Escaping depende do contexto

Texto dentro de um elemento e valor de atributo são contextos diferentes. escape() não adiciona aspas ao redor de um atributo e não escolhe como tratar aspas simples e duplas. Para atributos, use quoteattr().

Também não use escape() para HTML completo recebido de usuários. Ele evita que o texto seja interpretado como markup quando inserido em um nó textual, mas não analisa políticas de tags, URLs, CSS, scripts ou atributos perigosos. O artigo de html.entities no Python explica a diferença entre entidades, decoding e sanitização.

Preparar atributos com quoteattr()

quoteattr() escapa os caracteres necessários, escolhe aspas adequadas e retorna o valor já delimitado.

from xml.sax.saxutils import quoteattr

valor = 'Relatório "final" & aprovado'
atributo = quoteattr(valor)
print(f"<arquivo nome={atributo}/>")

Se o texto contém apenas um tipo de aspas, a função tenta usar o outro como delimitador. Quando contém aspas simples e duplas, ela codifica as aspas necessárias.

Evite montar documentos XML extensos apenas com concatenação de strings. Para estruturas maiores, use ElementTree, minidom ou XMLGenerator. Veja ElementTree no Python para uma API orientada a árvores.

Desfazer entidades com unescape()

unescape() converte &amp;, &lt; e &gt; para os caracteres originais.

from xml.sax.saxutils import unescape

texto = "Tom &amp; Ana &lt;3 XML"
print(unescape(texto))

O argumento entities permite definir entidades adicionais. Entretanto, unescape() não é um parser XML completo. Ele não valida estrutura, encoding, DTD, namespaces nem documentos malformados.

Evite decodificar repetidamente o mesmo conteúdo. Um valor transformado duas vezes pode converter texto literal em markup inesperado. Defina claramente em qual camada o decoding ocorre.

Gerar XML com XMLGenerator

XMLGenerator implementa a interface ContentHandler e escreve eventos SAX de volta como XML. Ele pode reproduzir um documento recebido ou gerar um novo fluxo de saída.

from io import StringIO
from xml.sax.saxutils import XMLGenerator
from xml.sax.xmlreader import AttributesImpl

saida = StringIO()
gerador = XMLGenerator(
    saida,
    encoding="utf-8",
    short_empty_elements=True,
)

gerador.startDocument()
gerador.startElement("catalogo", AttributesImpl({"versao": "1"}))
gerador.startElement("produto", AttributesImpl({"id": "42"}))
gerador.characters("Café & código")
gerador.endElement("produto")
gerador.endElement("catalogo")
gerador.endDocument()

print(saida.getvalue())

O gerador escapa texto e atributos conforme os eventos recebidos. Use a mesma ordem lógica do XML: abra o documento, abra elementos, envie texto, feche os elementos em ordem inversa e finalize.

Encoding da saída

O encoding informado ao XMLGenerator deve corresponder ao stream de saída. Quando usar um stream binário, confirme a forma como o gerador codifica os dados. Com StringIO, o resultado é texto Unicode.

Para escrever arquivos, abra com uma estratégia coerente e teste caracteres não ASCII. O guia de codecs no Python aborda encodings, BOM e tratamento de erros.

Transformar eventos com XMLFilterBase

XMLFilterBase fica entre um XMLReader e o handler final. Por padrão, repassa eventos sem alterações. Uma subclasse pode interceptar eventos para renomear elementos, remover atributos, normalizar texto ou bloquear partes do documento.

from xml.sax.saxutils import XMLFilterBase

class RemoveSegredo(XMLFilterBase):
    def startElement(self, name, attrs):
        if "segredo" in attrs:
            novos = dict(attrs.items())
            novos.pop("segredo", None)
            from xml.sax.xmlreader import AttributesImpl
            attrs = AttributesImpl(novos)
        super().startElement(name, attrs)

Filtros devem preservar a sequência válida de eventos. Se um elemento de início for removido, o fim correspondente também precisa ser tratado. Teste documentos com namespaces, texto fragmentado, comentários e elementos vazios.

O guia de xml.sax no Python explica handlers, namespaces e o fluxo de callbacks.

Preparar fontes com prepare_input_source()

prepare_input_source() normaliza uma string, objeto semelhante a arquivo ou InputSource para uma entrada pronta para um parser. Ele também pode resolver referências relativas a partir de uma URL base.

from xml.sax.saxutils import prepare_input_source

fonte = prepare_input_source("dados.xml")
print(fonte.getSystemId())

Resolver caminhos e URLs automaticamente pode ser arriscado quando a origem é controlada por usuários. Valide protocolos, host, diretórios permitidos e tamanho. Não transforme uma referência externa em download irrestrito.

Segurança de XML externo

O módulo não elimina vulnerabilidades do parser. Mantenha entidades externas desativadas, limite bytes e profundidade, e não permita que documentos externos escolham livremente arquivos locais ou URLs. O guia de pulldom no Python apresenta limites para documentos grandes.

Ao gerar XML, valide nomes de elementos e atributos. escape() protege conteúdo textual, mas não torna um nome arbitrário válido como tag. Prefira nomes definidos pelo código ou por um esquema confiável.

Evitar XML montado por concatenação

Um erro comum é concatenar strings para criar documentos:

# Evite em documentos reais
xml = "<usuario nome=\"" + nome + "\">" + texto + "</usuario>"

Mesmo com escaping, é fácil esquecer um contexto, errar encoding ou produzir tags desequilibradas. Para estruturas pequenas, quoteattr() e escape() podem ser suficientes; para documentos completos, use uma API estrutural.

Testes recomendados

Teste &, <, >, aspas simples e duplas, Unicode, strings vazias, quebras de linha, valores já escapados e caracteres inválidos para XML. Em geradores, teste elementos vazios, namespaces, atributos em diferentes ordens e streams de texto ou bytes.

Em filtros, confirme que a saída continua bem-formada. Faça parsing da saída gerada durante os testes em vez de comparar apenas strings.

Erros comuns

Os erros mais frequentes são usar escape() em atributos, usar unescape() duas vezes, tratar escaping como sanitização, concatenar tags com dados externos, deixar encoding implícito, habilitar entidades externas e modificar eventos sem manter pares de abertura e fechamento.

Conclusão

xml.sax.saxutils fornece blocos úteis para escapar texto XML, preparar atributos, gerar documentos a partir de eventos, transformar streams SAX e normalizar fontes de entrada.

Use cada ferramenta no contexto correto, prefira APIs estruturais para documentos completos e mantenha limites de segurança para entradas externas. Consulte a documentação oficial de saxutils e a especificação XML do W3C.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Conteúdo do artigo

    Artigos relacionados

    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

    pulldom no Python: DOM parcial para XML

    Aprenda pulldom no Python para processar XML por eventos, expandir apenas subárvores necessárias e reduzir memória com segurança.

    Ler mais

    Tempo de leitura: 6 minutos
    23/08/2026
    Close-up view of a computer screen displaying code in a software development environment.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    xml.sax no Python: processe XML em eventos

    Aprenda xml.sax no Python para processar XML por eventos com baixo uso de memória, namespaces, handlers, limites e segurança.

    Ler mais

    Tempo de leitura: 5 minutos
    22/08/2026
    Detailed shot of a Jungle Carpet Python (Morelia spilota cheynei) in its natural habitat.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    minidom no Python: manipule XML com DOM

    Aprenda xml.dom.minidom no Python para ler, navegar, criar e serializar XML com DOM, namespaces, memória e segurança.

    Ler mais

    Tempo de leitura: 5 minutos
    22/08/2026
    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