Como fazer parser de XML com Expat em C/C++

A mais utilizada do mundo, tais como: CMake, Godot, Firefox, LibreOffice e outros.


Como fazer parser de XML com Expat em C/C++

Nesse cpp::daily de hoje vamos falar uma das bibliotecas mais utilizadas do mundo.

Existem várias bibliotecas para fazer parser de XML e já já vamos postar uma lista das melhores. Cada uma com seus prós e contra, mas a Expat tem bastante diferenciais, começando pelo fato de ser indicada pela W3C.

De todas com certeza, a Expat é a mais difícil de implementar, mas a garantia do resultado é de 100% . Além de ser a mais utilizada de todas, projetos como: AbiWord, Android Studio, Apache OpenOffice, Audacity, aria2, CMake, D-Bus, Electron, Elinks, Firefox, Git, Godot, LibreOffice e muitos outros a utilizam.

A Expat pode ser implementada por diversas linguagens de programação, tais como: Python, PHP, Perl e entre outras.

Ela foi escrita em C e pode ser intimidante devido aos vários tipos de manipuladores e opções que você pode definir. Mas você só precisa aprender quatro funções para fazer 80% do que deseja fazer com elas:

  • XML_ParserCreate - Para criar um novo objeto analisador.
  • XML_SetElementHandler - Para definir manipuladores para tags de início e fim.
  • XML_SetCharacterDataHandler - Para definir o manipulador para texto.
  • XML_Parse - Para passar um buffer cheio de documentos para o analisador

Antes de qualquer coisa você precisa possuí-la instalada no seu include. Ela está em todos os repositórios de distro, então basta usar o gerenciador de pacotes da sua distro, exemplos:

emerge expat # Gentoo, Funtoo, ...
sudo apt install expat # Debian, Ubuntu, Mint, ...
sudo pacman -S expat # Arch, Manjaro, ...
sudo dnf install expat # Red Hat, Fedora, ...

Para entendermos, vamos mostrar um exemplo de um código e para mais detalhes, sugiro a leitura da documentação que é bem concisa, pois a única coisa que eu senti falta na documentação foi de um exemplo simples para entendimento em linhas gerais.

Então, eu criei esse exemplo básico, mas já funcional. Para fins didáticos o código não é orientada a objetos para que você possa usar tanto em C como em C++ .

Para isso vamos usar esse exemplo de XML: vim programmers.xml

<?xml version="1.0" encoding="UTF-8"?>
<data>
  <programmer>
    <name>Bjarne Stroustroup</name>
    <language>C++</language>
    <birth>December 30, 1950</birth>
    <country>Denmark</country>
    <profession>Computer Scientist</profession>
    <website>https://www.stroustrup.com/</website>
  </programmer>
  <programmer>
    <name>Dennis Ritchie</name>
    <language>C</language>
    <birth>September 9, 1941</birth>
    <country>USA</country>
    <profession>Physicist, Mathematical and BCS</profession>
    <website>https://web.archive.org/</website>
  </programmer>
  <programmer>
    <name>Brian Kernighan</name>
    <language>AWK</language>
    <birth>January 1, 1942</birth>
    <country>Canada</country>
    <profession>Computer Scientist, Engineer and Professor</profession>
    <website>https://www.cs.princeton.edu/~bwk/</website>
  </programmer>
</data>

E para ler esse XML vamos usar esse código: vim main.cpp

#include <iostream>
#include <expat.h>
#include <cstring> // strlen
 
void start(void *userData, const char *name, const char *args[]){
   std::cout << name << ": ";
}
 
void value(void *userData, const char *val, int len){
   int I;
   char cpy[128] = {};
   
   for(I = 0; I < len; I++){
      cpy[I] = val[I];
   }

   cpy[I] = 0;
   
   std::cout << cpy;
}
 
void end(void *userData, const char *name){}
 
int main(){
   XML_Parser parser = XML_ParserCreate(NULL);
 
   XML_SetElementHandler(parser, start, end);
   
   XML_SetCharacterDataHandler(parser, value);
   
   char val[1024] = {};
   FILE *fh = fopen("programmers.xml", "r");

   fread(&val, sizeof(char), 1024, fh);
   fclose( fh );

   XML_Parse(parser, val, strlen( val ), XML_TRUE);
   XML_ParserFree(parser);
   
   return 0;
}

Para compilar rode o comando:

g++ main.cpp -lexpat -o parser

Agora é só rodar o ./parser e notar que as tags são exibidas pela função start(void *userData, const char *name, const char *args[]) mais precisamente pela variável name.

E o conteúdo das tags pela value(void *userData, const char *val, int len) mais precisamente pela variável cpy. A função end não possui conteúdo, pois ela servirá para usarmos no XML_SetElementHandler, como dito acima.

Tente modificar, exibir em tabelas e outros como prática de exercício, ok?!


Por hoje é só, são pequenas doses diárias que farão sempre nos manter antenado com o C++ !

Acompanhe o cpp::daily

Deseja aprender C++ e criar seus programas Gráficos e para Terminal com portabilidade para Linux e Windows?

Então se inscreva nos nossos Cursos de C++ Moderno . Você aprender criar:

Acesse o endereço:

https://terminalroot.com.br/cpp/ e saiba mais!



cppdaily cpp


Compartilhe


Nosso canal no Youtube

Inscreva-se


Marcos Oliveira

Marcos Oliveira

Desenvolvedor de software
https://github.com/terroo


Crie Aplicativos Gráficos para Linux e Windows com C++

Aprenda C++ Moderno e crie Games, Programas CLI, GUI e TUI de forma fácil.

Saiba Mais

Receba as novidades no seu e-mail!

Após cadastro e confirmação do e-mail, enviaremos semanalmente resumos e também sempre que houver novidades por aqui para que você mantenha-se atualizado!