Trabalhando com JSON e XML
1. Introdução aos formatos JSON e XML
JSON (JavaScript Object Notation) e XML (eXtensible Markup Language) são dois dos formatos de intercâmbio de dados mais utilizados no desenvolvimento web. Enquanto o JSON é leve, baseado em texto e nativamente compatível com JavaScript, o XML oferece uma estrutura mais robusta com suporte a namespaces, schemas e validação formal.
Em aplicações PHP, a escolha entre JSON e XML depende do contexto: JSON é ideal para APIs RESTful, comunicação com JavaScript e armazenamento de configurações simples. XML é preferível para documentos complexos, integração com sistemas legados e quando validação rigorosa é necessária.
O PHP oferece funções nativas para ambos os formatos: json_encode()/json_decode() para JSON, e simplexml_load_string()/simplexml_load_file() para XML, além da poderosa extensão DOMDocument para manipulação avançada.
2. Codificando e decodificando JSON
Codificação com json_encode()
<?php
$dados = [
'nome' => 'Maria Silva',
'email' => 'maria@exemplo.com',
'idade' => 32,
'habilidades' => ['PHP', 'JavaScript', 'Python'],
'ativo' => true
];
// Codificação básica
$json = json_encode($dados);
echo $json;
// {"nome":"Maria Silva","email":"maria@exemplo.com","idade":32,"habilidades":["PHP","JavaScript","Python"],"ativo":true}
// Com formatação legível
$jsonPretty = json_encode($dados, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
echo $jsonPretty;
Decodificação com json_decode()
<?php
$jsonString = '{"nome":"João","idade":28,"ativo":false}';
// Para array associativo (segundo parâmetro true)
$array = json_decode($jsonString, true);
echo $array['nome']; // João
// Para objeto stdClass (padrão)
$objeto = json_decode($jsonString);
echo $objeto->idade; // 28
// Tratamento de erros
$jsonInvalido = '{"nome": "incompleto"';
$dados = json_decode($jsonInvalido);
if (json_last_error() !== JSON_ERROR_NONE) {
echo 'Erro JSON: ' . json_last_error_msg();
// Erro JSON: Syntax error
}
3. Manipulação avançada de JSON
Trabalhando com JSON aninhado
<?php
$complexo = [
'empresa' => 'TechCorp',
'departamentos' => [
'TI' => [
'funcionarios' => 15,
'projetos' => ['Alpha', 'Beta']
],
'RH' => [
'funcionarios' => 5,
'projetos' => ['Recrutamento 2024']
]
]
];
$jsonComplexo = json_encode($complexo, JSON_PRETTY_PRINT);
$decodificado = json_decode($jsonComplexo, true);
echo $decodificado['departamentos']['TI']['projetos'][0]; // Alpha
Serialização personalizada com JsonSerializable
<?php
class Usuario implements JsonSerializable {
private string $nome;
private string $email;
private string $senha;
public function __construct(string $nome, string $email, string $senha) {
$this->nome = $nome;
$this->email = $email;
$this->senha = $senha;
}
public function jsonSerialize(): array {
return [
'nome' => $this->nome,
'email' => $this->email,
// Senha NÃO é incluída na serialização
];
}
}
$usuario = new Usuario('Ana', 'ana@exemplo.com', '123456');
echo json_encode($usuario, JSON_PRETTY_PRINT);
// {"nome":"Ana","email":"ana@exemplo.com"}
Leitura e escrita de arquivos JSON
<?php
// Escrevendo JSON em arquivo
$config = ['db_host' => 'localhost', 'db_port' => 3306];
file_put_contents('config.json', json_encode($config, JSON_PRETTY_PRINT));
// Lendo JSON de arquivo
$jsonLido = file_get_contents('config.json');
$configArray = json_decode($jsonLido, true);
echo $configArray['db_host']; // localhost
4. Parsing de XML com SimpleXML
Carregando XML
<?php
$xmlString = <<<XML
<livros>
<livro id="1">
<titulo>PHP Moderno</titulo>
<autor>João Developer</autor>
<preco moeda="BRL">89.90</preco>
</livro>
<livro id="2">
<titulo>Clean Code</titulo>
<autor>Robert Martin</autor>
<preco moeda="USD">45.00</preco>
</livro>
</livros>
XML;
$xml = simplexml_load_string($xmlString);
// Ou carregar de arquivo
// $xml = simplexml_load_file('livros.xml');
Navegação pela árvore XML
<?php
// Acessando elementos filhos
foreach ($xml->livro as $livro) {
echo "ID: " . $livro['id'] . "\n";
echo "Título: " . $livro->titulo . "\n";
echo "Autor: " . $livro->autor . "\n";
echo "Preço: " . $livro->preco . " (" . $livro->preco['moeda'] . ")\n\n";
}
// Usando XPath
$livrosCaros = $xml->xpath("//livro[preco > 50]");
foreach ($livrosCaros as $livro) {
echo $livro->titulo . " - " . $livro->preco . "\n";
}
Modificação e criação de nós XML
<?php
// Adicionando novo livro
$novoLivro = $xml->addChild('livro');
$novoLivro->addAttribute('id', '3');
$novoLivro->addChild('titulo', 'Design Patterns');
$novoLivro->addChild('autor', 'Gang of Four');
$novoLivro->addChild('preco', '120.00')->addAttribute('moeda', 'BRL');
echo $xml->asXML();
5. Trabalhando com DOMDocument para XML complexo
Criando documentos XML do zero
<?php
$dom = new DOMDocument('1.0', 'UTF-8');
$dom->formatOutput = true;
$root = $dom->createElement('catalogo');
$dom->appendChild($root);
$produto = $dom->createElement('produto');
$produto->setAttribute('codigo', 'P001');
$root->appendChild($produto);
$nome = $dom->createElement('nome', 'Notebook Pro');
$produto->appendChild($nome);
$preco = $dom->createElement('preco', '4999.99');
$preco->setAttribute('moeda', 'BRL');
$produto->appendChild($preco);
echo $dom->saveXML();
// Salvar em arquivo: $dom->save('catalogo.xml');
Manipulação avançada e validação
<?php
$dom = new DOMDocument();
$dom->load('catalogo.xml');
// Remover elemento
$produtos = $dom->getElementsByTagName('produto');
if ($produtos->length > 0) {
$primeiro = $produtos->item(0);
$primeiro->parentNode->removeChild($primeiro);
}
// Validação contra DTD
$dom->validate(); // Retorna bool
// Validação contra XSD
$dom->schemaValidate('catalogo.xsd'); // Retorna bool
6. Conversão entre JSON e XML
Implementação manual com recursão
<?php
function jsonToXml($json, DOMDocument $dom, DOMElement $parent = null): void {
$data = json_decode($json, true);
if ($parent === null) {
$parent = $dom->documentElement;
if (!$parent) {
$root = $dom->createElement('root');
$dom->appendChild($root);
$parent = $root;
}
}
foreach ($data as $key => $value) {
if (is_array($value)) {
$element = $dom->createElement(is_numeric($key) ? 'item' : $key);
if (is_numeric($key)) {
$element->setAttribute('index', $key);
}
$parent->appendChild($element);
jsonToXml(json_encode($value), $dom, $element);
} else {
$element = $dom->createElement(is_numeric($key) ? 'item' : $key, htmlspecialchars((string)$value));
if (is_numeric($key)) {
$element->setAttribute('index', $key);
}
$parent->appendChild($element);
}
}
}
$json = '{"nome":"Produto","preco":100,"tags":["novo","promocao"]}';
$dom = new DOMDocument('1.0', 'UTF-8');
$dom->formatOutput = true;
jsonToXml($json, $dom);
echo $dom->saveXML();
Usando Symfony Serializer
<?php
require 'vendor/autoload.php';
use Symfony\Component\Serializer\Serializer;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Encoder\XmlEncoder;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
$encoders = [new XmlEncoder(), new JsonEncoder()];
$normalizers = [new ObjectNormalizer()];
$serializer = new Serializer($normalizers, $encoders);
$data = ['nome' => 'Exemplo', 'valor' => 99.90];
// JSON para XML
$json = json_encode($data);
$xml = $serializer->decode($json, 'xml');
echo $serializer->encode($xml, 'xml');
7. Boas práticas e segurança
Validação de dados
<?php
// Validar JSON antes de processar
function validarJson(string $json): bool {
json_decode($json);
return json_last_error() === JSON_ERROR_NONE;
}
// Validar XML com SimpleXML
function validarXml(string $xml): bool {
libxml_use_internal_errors(true);
simplexml_load_string($xml);
$errors = libxml_get_errors();
libxml_clear_errors();
return empty($errors);
}
Prevenção de ataques XXE
<?php
// Desabilitar entidades externas para evitar XXE
$opcoes = LIBXML_NOENT | LIBXML_DTDLOAD;
$xml = simplexml_load_string($xmlString, 'SimpleXMLElement', $opcoes);
// Ou usar DOMDocument com segurança
$dom = new DOMDocument();
$dom->loadXML($xmlString, LIBXML_NOENT | LIBXML_DTDLOAD | LIBXML_NONET);
Performance para grandes arquivos
<?php
// Lazy loading com XMLReader para arquivos grandes
$reader = new XMLReader();
$reader->open('grande.xml');
while ($reader->read()) {
if ($reader->nodeType === XMLReader::ELEMENT && $reader->name === 'registro') {
$xml = $reader->readOuterXML();
processarRegistro(simplexml_load_string($xml));
}
}
$reader->close();
// Cache de parsing
$cacheFile = 'cache/parsed_' . md5('dados.json');
if (file_exists($cacheFile)) {
$dados = unserialize(file_get_contents($cacheFile));
} else {
$dados = json_decode(file_get_contents('grande.json'), true);
file_put_contents($cacheFile, serialize($dados));
}
Referências
- PHP: JSON Functions — Documentação oficial das funções JSON do PHP, incluindo todas as flags e opções disponíveis
- PHP: SimpleXML — Guia completo da extensão SimpleXML para parsing básico de XML
- PHP: DOMDocument — Documentação oficial da classe DOMDocument para manipulação avançada de XML
- OWASP: XML External Entity Prevention — Guia de prevenção contra ataques XXE em aplicações PHP
- Symfony Serializer Component — Documentação do componente Serializer do Symfony para conversão entre formatos
- PHP: json_last_error — Referência para tratamento de erros na manipulação de JSON
- PHP: XMLReader — Documentação do XMLReader para parsing eficiente de grandes arquivos XML