Formatos e fontes de dados 5 min de leitura

Parsing de XML: bibliotecas, XPath e exemplos em várias linguagens

Como trabalhar com XML em diferentes linguagens: DOM versus SAX, XPath, namespaces e leitura em fluxo de arquivos grandes sem estourar a memória.

EW
Equipe Web-Scraping.biz
Coleta de dados para as demandas do negócio
Publicado: 21 abril 2025

XML (eXtensible Markup Language) é um formato de texto para armazenar e transmitir dados estruturados em forma de árvore. Sobre ele se constroem os feeds de produtos de marketplaces e agregadores, os formatos bancários e de intercâmbio, os arquivos de configuração e também seus formatos derivados: os feeds RSS e os mapas do site. Este artigo faz parte do nosso panorama geral do parsing de documentos, com foco específico em XML.

Como um XML é construído

Um documento XML é uma árvore de elementos. Cada elemento tem um nome (a tag) e pode ter um conjunto de atributos, conteúdo de texto e elementos aninhados.

xml
<catalog>
  <product id="101" available="true">
    <name>Moedor de café</name>
    <price currency="EUR">34.90</price>
  </product>
  <product id="102" available="false">
    <name>Chaleira elétrica</name>
    <price currency="EUR">21.90</price>
  </product>
</catalog>

A diferença-chave em relação ao JSON é que no XML os dados vivem em dois lugares ao mesmo tempo: no texto dos elementos (<name>Moedor de café</name>) e nos atributos (id="101"). É preciso ter isso em mente: na extração, às vezes se consulta o conteúdo da tag e, outras vezes, seus atributos.

Um tema à parte são os espaços de nomes (namespaces). Nos formatos complexos, as tags aparecem como <g:price> ou <atom:link>, em que o prefixo está ligado a um URI. Os parsers exigem levar o namespace em conta na busca de nós; caso contrário, a consulta devolve um resultado vazio — é a causa mais frequente do «o parser não encontra nada, embora os dados estejam lá».

Duas abordagens: árvore em memória e leitura em fluxo

Existem duas maneiras radicalmente distintas de fazer o parsing. A abordagem DOM constrói a árvore inteira em memória e oferece uma navegação cômoda, XPath incluída: é simples e serve para arquivos de até dezenas de megabytes. A abordagem em fluxo (SAX / iterparse) lê o arquivo por eventos, sem carregá-lo por inteiro, e é insubstituível com dumps de centenas de megabytes ou de gigabytes. Para as tarefas típicas, o DOM quase sempre basta; passa-se ao modo em fluxo quando o arquivo deixa de caber na memória.

Python

A biblioteca padrão inclui o módulo xml.etree.ElementTree: é suficiente para os casos simples e não exige instalação.

python
import xml.etree.ElementTree as ET

tree = ET.parse("catalog.xml")
root = tree.getroot()

for product in root.findall("product"):
    name = product.find("name").text
    price = product.find("price").text
    available = product.get("available")  # leitura do atributo
    print(name, price, available)

Para o trabalho sério, usa-se o lxml: é mais rápido, digere melhor o XML «sujo» e suporta XPath por completo, namespaces incluídos.

python
from lxml import etree

tree = etree.parse("catalog.xml")

# XPath: todos os produtos disponíveis
for product in tree.xpath("//product[@available='true']"):
    name = product.xpath("string(name)")
    price = product.xpath("string(price)")
    print(name, price)

Se os dados chegaram de uma API em XML, mas é mais cômodo trabalhar com eles como com um dicionário, ajuda a biblioteca xmltodict, que converte o XML em estruturas aninhadas comuns de Python — bem parecido com o processamento de um JSON.

JavaScript / Node.js

No Node, duas soluções são populares. O fast-xml-parser parseia o XML para um objeto sem dependências externas e funciona muito rápido.

javascript
const { XMLParser } = require("fast-xml-parser");
const fs = require("fs");

const xml = fs.readFileSync("catalog.xml", "utf-8");
const parser = new XMLParser({ ignoreAttributes: false, attributeNamePrefix: "@_" });
const data = parser.parse(xml);

for (const product of data.catalog.product) {
  console.log(product.name, product.price["#text"], product["@_available"]);
}

A alternativa é o xml2js, veterano no ecossistema e cômodo para o processamento assíncrono. No navegador, está disponível o DOMParser embutido, que permite percorrer o XML com os mesmos métodos de um documento HTML.

PHP

Para os documentos simples, o SimpleXML embutido cai como uma luva: dá acesso aos elementos como se fossem propriedades de um objeto.

php
<?php
$xml = simplexml_load_file("catalog.xml");

foreach ($xml->product as $product) {
    $name  = (string) $product->name;
    $price = (string) $product->price;
    $available = (string) $product["available"]; // atributo
    echo "$name — $price — $available\n";
}

Quando são necessários namespaces, XPath complexo ou o processamento em fluxo de arquivos grandes, passa-se ao DOMDocument e ao XMLReader, incluídos na mesma distribuição padrão do PHP.

Go

A biblioteca padrão do Go inclui o pacote encoding/xml, que parseia o XML diretamente para structs por meio das tags dos campos.

go
package main

import (
    "encoding/xml"
    "fmt"
    "os"
)

type Catalog struct {
    Products []struct {
        ID        string `xml:"id,attr"`
        Available string `xml:"available,attr"`
        Name      string `xml:"name"`
        Price     string `xml:"price"`
    } `xml:"product"`
}

func main() {
    data, _ := os.ReadFile("catalog.xml")
    var c Catalog
    xml.Unmarshal(data, &c)
    for _, p := range c.Products {
        fmt.Println(p.Name, p.Price, p.Available)
    }
}

Erros típicos

O mais comum é tropeçar na codificação: se a declaração anuncia ISO-8859-1 (ou windows-1252) e o arquivo é lido como UTF-8, os caracteres viram lixo — é preciso deixar a codificação por conta do parser ou recodificar de forma explícita. A segunda causa em frequência são os namespaces ignorados, que fazem as consultas XPath devolverem em silêncio um resultado vazio. A terceira, tentar carregar por inteiro no DOM um arquivo grande demais: um dump de gigabytes deve ser lido em fluxo. E, por fim, não parseie XML com expressões regulares: o formato é aninhado e recursivo, e as regex quebram no primeiro caso fora do comum — para texto sem estrutura elas se justificam (veja o parsing de TXT), mas não para XML.

Se no seu caso há um esquema de exportação fora do padrão, namespaces quebrados ou arquivos de gigabytes, configuramos o parsing de XML sob medida para o seu formato. E se os dados de origem não chegam em XML puro, mas em seus derivados, consulte os materiais vizinhos: RSS e sitemap.