xml_set_character_data_handler()
A função xml_set_character_data_handler() define um callback para dados de caracteres em um parser XML no PHP.
A função xml_set_character_data_handler() registra um callback definido pelo usuário que o parser XML chama toda vez que encontra dados de caracteres — o conteúdo de texto que fica entre as tags XML. Ela pertence à extensão legada xml, que encapsula o parser Expat orientado a eventos, fazendo parte da API de parsing baseada em fluxo ("estilo SAX") do PHP, em vez das abordagens baseadas em árvore DOMDocument ou SimpleXML.
Você usa essa função quando quer capturar ou transformar o texto dentro dos elementos enquanto o documento é processado em fluxo — por exemplo, coletando o título de cada <item> em um feed RSS, ou executando uma transformação no texto extraído sem nunca construir o documento inteiro na memória. Ela é quase sempre usada em conjunto com xml_set_element_handler(), que informa a qual elemento o texto pertence.
Atenção: A extensão
xmlé legada. Para código novo, prefiraSimpleXMLouDOMDocument. Use este handler quando estiver mantendo parsers existentes baseados em Expat ou quando realmente precisar de streaming orientado a eventos para documentos muito grandes.
Sintaxe
xml_set_character_data_handler(XMLParser $parser, callable $handler): bool$parser— o parser criado porxml_parser_create().$handler— o callback a ser invocado para dados de caracteres. Passe o nome de uma função como string, uma closure ou um array para um callback de método. Passar uma string vazia""cancela o registro de um handler previamente registrado.
A função retorna true em caso de sucesso.
A assinatura do handler
Seu handler recebe dois argumentos — o parser e o trecho de texto:
function handler(XMLParser $parser, string $data): voidDocumentações mais antigas às vezes mostram um terceiro parâmetro $length, mas a extensão xml baseada em Expat não o passa. No PHP 8+, declarar um terceiro parâmetro obrigatório lança um ArgumentCountError, portanto mantenha seu handler com dois parâmetros (ou torne os extras opcionais).
Exemplos de Uso
Exemplo 1: Um handler mínimo de dados de caracteres
Crie um parser, anexe um handler e, em seguida, alimente-o com uma string XML. O handler simplesmente exibe o texto com espaços removidos:
function handle_character_data($parser, $data) {
echo trim($data);
}
$xml_parser = xml_parser_create();
xml_set_character_data_handler($xml_parser, "handle_character_data");
$xml_data = '<root><item>Hello World</item></root>';
xml_parse($xml_parser, $xml_data, true);
xml_parser_free($xml_parser);
// Output: Hello Worldxml_parser_create() cria o parser, xml_set_character_data_handler() conecta o callback, xml_parse() processa os dados em fluxo (o true final indica que é o último trecho) e xml_parser_free() libera o parser.
O problema dos fragmentos
O parser pode chamar seu handler várias vezes para um único elemento, e ele também é acionado para o espaço em branco entre elementos. Ele não entrega uma string organizada por elemento. Observe o que acontece com dois itens e algum recuo:
function show($parser, $data) {
echo '[' . $data . "]\n";
}
$p = xml_parser_create();
xml_set_character_data_handler($p, "show");
$xml = '<root><item>Hello World</item> <item>Goodbye</item></root>';
xml_parse($p, $xml, true);
xml_parser_free($p);
// Output:
// [Hello World]
// [ ]
// [Goodbye]O espaço de dois caracteres entre </item> e o próximo <item> aciona sua própria chamada. Textos longos também podem chegar divididos em várias chamadas. Por isso, você deve armazenar os dados em um buffer e agir somente quando souber que o elemento terminou.
Exemplo 2: Acumulando texto com um handler de elementos
O padrão confiável é: limpe um buffer quando um elemento começa, acrescente cada trecho de dados de caracteres a ele e leia o buffer quando o elemento terminar. É por isso que xml_set_element_handler() é quase sempre usado em conjunto com esta função.
$buffer = '';
function start_element($parser, $name, $attrs) {
global $buffer;
$buffer = ''; // start collecting fresh text
}
function character_data($parser, $data) {
global $buffer;
$buffer .= $data; // chunks may arrive in pieces — append
}
function end_element($parser, $name) {
global $buffer;
$text = trim($buffer);
if ($text !== '') {
echo "$name: $text\n";
}
}
$parser = xml_parser_create();
xml_set_element_handler($parser, "start_element", "end_element");
xml_set_character_data_handler($parser, "character_data");
$xml = '<books><title>PHP Basics</title><title>Advanced XML</title></books>';
xml_parse($parser, $xml, true);
xml_parser_free($parser);
// Output:
// TITLE: PHP Basics
// TITLE: Advanced XMLOs nomes dos elementos chegam em maiúsculas por padrão porque o parser dobra a capitalização. Para manter a capitalização original, desative o dobramento de capitalização com xml_parser_set_option():
xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);Armadilhas comuns
- Assumir uma chamada por elemento. Como mostrado acima, os dados de caracteres podem ser entregues em vários fragmentos; acumule sempre em um buffer.
- Chamadas apenas com espaço em branco. Recuos e quebras de linha entre tags acionam o handler com espaço em branco. Filtre com
trim()antes de agir. - Um terceiro parâmetro no handler. O handler Expat passa apenas
$parsere$data; um parâmetro$lengthobrigatório causa umArgumentCountError. - Registrar o handler após o parsing. Anexe todos os handlers antes de chamar
xml_parse(), ou os eventos já terão passado.
Conclusão
xml_set_character_data_handler() registra um callback para o texto entre tags XML na extensão xml legada baseada em Expat do PHP. Seu handler recebe dois argumentos — o parser e o trecho de dados — e pode ser acionado muitas vezes por elemento, inclusive para espaços em branco. Portanto, a abordagem confiável é acumular o texto em um buffer e processá-lo quando o elemento terminar via xml_set_element_handler(). Para novos projetos, prefira as APIs modernas SimpleXML ou DOMDocument; use esta função ao manter parsers existentes ou ao fazer streaming de documentos muito grandes.