Ver la versión completa : [Ayuda] ¿Me recomendáis un parser XML en C/C++?
Puck2099
20/02/2009, 16:28
Hola,
Estoy pensando en hacer los niveles del Lady Killer para Wiz usando archivos XML (ahora están codificados en el propio código fuente) de forma que pudieran ser modificables fácilmente sin necesidad de recompilar.
Antes de programarme yo una biblioteca para parsear los XML se me ha ocurrido buscar por Internet y salen decenas de ellas...
¿Sabéis de alguna buena, eficiente y fácil de implementar? Así me ahorro el prueba y error con las que encuentre...
Gracias :brindis:
Libxml2
De todas formas, crearse tu propio parser de XML tipo SAX es muy muy fácil. Alguna vez lo he tenido que hacer para pequeños dispositivos para ahorrarme toda la morralla que introducen los parsers completos. Aquí la idea de funcionamiento de los SAX: http://www.saxproject.org/event.html
No la he probado, pero es pequeña y eficiente.
http://www.minixml.org/
romeroca
20/02/2009, 17:54
Prueba la siguiente
http://xerces.apache.org/xerces-c/
No sé que tal irá la versión en C++ pero la de JAVA va muy bien.
Un saludo.
^MiSaTo^
20/02/2009, 18:06
Prueba la siguiente
http://xerces.apache.org/xerces-c/
No sé que tal irá la versión en C++ pero la de JAVA va muy bien.
Un saludo.
Ostras no sabía que estaba Xerces para C!
Yo normalmente uso xerces para java y corroboro que va fenomenal ^^
Una librería que suele estar en los toolchains de la gp2x es libxml. No sé qué tal funciona, pero es bastante estándar en Linux.
Para que veas lo fácil que es hacer un parser tipo SAX en C para XML sin librerías externas:
#include <stdio.h>
#include <string.h>
void startElement(char *element){
printf("new element: %s\n", element);
}
void closeElement(char *element){
printf("close element: %s\n", element);
}
void newContent(char *text){
printf("new content: %s\n", text);
}
void parseXML(char *xml){
char buffer[256];
int pos_b=0, i=0;
while(xml[i]!=0){
switch(xml[i]){
case '<': /* inicio de un elemento */
if(pos_b < i - 1){ /* si había contenido previo, lanza evento newContent */
strncpy(buffer, xml+pos_b+1, i-pos_b);
buffer[i-pos_b-1]=0;
newContent(buffer);
}
pos_b=i;
break;
case '>': /* final de una etiqueta */
if(xml[pos_b+1]=='/'){ /* ¿era una etiqueta de cierre */
strncpy(buffer, xml+pos_b+2, i-pos_b-2);
buffer[i-pos_b-2]=0;
closeElement(buffer); /* lanza el evento closeElement con el nombre del elemento (sin incluir /)
}else{
strncpy(buffer, xml+pos_b+1, i-pos_b-1);
buffer[i-pos_b-1]=0;
startElement(buffer); /* lanza el evento startElement */
}
pos_b=i;
}
i++;
}
}
int main(){
parseXML(
"<nivel>"
"<mensaje>Hola</mensaje>"
"<paredes>12345678</paredes>"
"<maloso><posx>1</posx><posy>2</posy></maloso>"
"<maloso><posx>5</posx><posy>8</posy></maloso>"
"</nivel>");
return 0;
}
Es un parser que no admite atributos en los elementos, ni comprueba desbordamiento de buffer, ni sporta DTDs o namespaces, incluso se atascará con los XMLs con errores. Pero, oye, es muy sencillo y fácil de usar :D Tú solo tienes que preocuparte de escribir las funciones newElement/closeElement/newContent
Puck2099
20/02/2009, 19:16
Gracias por las recomendaciones, en realidad me vale con algo sencillito, lo que usaría sería algo así:
<fases>
<fase1>
<fondo>chica1.bmp</fondo>
<texto>Hace mucho calor aquí.</texto>
<enemigo>
<tipo>Sirvienta</tipo>
<x>15</x>
<y>120</y>
</enemigo>
<enemigo>
<tipo>Sirvienta</tipo>
<x>130</x>
<y>120</y>
</enemigo>
</fase1>
</fases>
Osea sin atributos ni nada, sólo unas estructuras jerárquicas para organizar las cosas.
PharaOnyx
20/02/2009, 19:31
Si es para algo sencillo y con archivos no muy grandes, ezXML te puede ir bien. Se basa en SimpleXML de php, así que su uso es muy... ¿simple? x'D
Saludos, Alex
Aprovecha el parseXML del código que te he pasado antes y modifica las funciones startElement/closeElement/newContent/main con esto:
struct Enemigo{
char tipo[32];
char x[4];
char y[4];
};
struct Fase{
char fondo[32];
char texto[256];
struct Enemigo enemigos[5];
};
struct Fase fases[10];
int c_f=0; // current_fase
int c_e=0; // current_enemigo
char *c_d; // current_data
void startElement(char *name){
if(strcmp(name, "fondo")==0)
c_d=fases[c_f].fondo;
else if(strcmp(name, "texto")==0)
c_d=fases[c_f].texto;
else if(strcmp(name, "tipo")==0)
c_d=fases[c_f].enemigos[c_e].tipo;
else if(strcmp(name, "x")==0)
c_d=fases[c_f].enemigos[c_e].x;
else if(strcmp(name, "y")==0)
c_d=fases[c_f].enemigos[c_e].y;
}
void closeElement(char *name){
if(strcmp(name, "enemigo")==0)
c_e++;
if(strcmp(name, "fase")==0)
c_f++;
}
void newContent(char *content){
strcpy(c_d, content);
}
int main(){
parseXML(
"<fases>"
"<fase1>"
"<fondo>chica1.bmp</fondo>"
"<texto>Hace mucho calor aquí.</texto>"
"<enemigo>"
"<tipo>Sirvienta</tipo>"
"<x>15</x>"
"<y>120</y>"
"</enemigo>"
"<enemigo>"
"<tipo>Sirvienta</tipo>"
"<x>130</x>"
"<y>120</y>"
"</enemigo>"
"</fase1>"
"</fases>"
);
printf("Fase fondo: %s, enemigo tipo %s en (%s, %s)\n",
fases[0].fondo,
fases[0].enemigos[0].tipo,
fases[0].enemigos[0].x,
fases[0].enemigos[0].y);
return 0;
}
Observa que no trato x,y como números por simplicidad: tendrás que convertirlos después del parseado. Deberías además añadir a la struct Fase contadores de cuántos enemigos tienes, pero eso te lo dejo como ejercicio :D)
Edito: adjunto parser.c con este ejemplo completo, que puedes compilar con gcc -o parser parser.c
Puck2099
20/02/2009, 20:23
Muchas gracias a todos, he estado probando lo que me habéis aconsejado y al final me quedaré o bien con la solución de juanvvc o bien con el ezXML o, lo más seguro, mezcle ambas cosas y lo transforme en una clase de C++ añadiéndole ya las conversiones a enteros y demás.
Gracias de nuevo :brindis:
Añado :) para que las cosas funcionen bien cuando metes espacios e identaciones, deberás añadir un c_d=0 and principio de startElement y closeElement, y cambiar newContent para que solo copie la cadena si c_d!=0
mortimor
20/02/2009, 21:49
jejeje
Tambien puedes probar MLLib que incluimos en Vorton, esta el código fuente en sourceforge :)
Powered by vBulletin® Version 4.2.5 Copyright © 2025 vBulletin Solutions Inc. All rights reserved.