La instanciación del parser a traves de su constructor xmlparser() genera automáticamente todo el árbol del XML. Para ello tendremos que pasarle como argumento una cadena de texto (De la clase string ) que contenga el XML como vemos en el siguiente ejemplo:
xmlparser * parser;
string xml="<root><b>Hi!<b></root>";
parser = new xmlparser(xml);
...
delete parser;
En la clase xmlparser encontramos dos funciones útiles: getParentNode() y printTree(). Una obtiene el nodo raíz del XML lo cuál será muy útil para comenzar a trabajar con el y la otra sirve para imprimir, a modo de debug, el contenido de un XML. Veamos, utilizando el siguiente código, algunos ejemplos de uso de estas funciones:
ifstream textstream(argv[1],ifstream::in);
while (getline(textstream, line)) {
xml+=line;
}
textstream.close();
parser = new xmlparser(xml);
node = parser->getParentNode();
parser->printTree(parser->getParentNode());
El código completo de este programa puede encontrarse en el apartado de descargas de esta publicación, contenido en el paquete de código fuente del parser. Veamos un ejemplo de su ejecución sobre los siguientes XML de ejemplo:
<rss version="2.0">
<channel>
<title>RSS Example</title>
<description>This is an example of an RSS feed</description>
<link>http://www.domain.com/link.htm</link>
<lastBuildDate>Mon, 28 Aug 2006 11:12:55 -0400 </lastBuildDate>
<pubDate>Tue, 29 Aug 2006 09:00:00 -0400</pubDate>
<item>
<title>Item Example</title>
<description>This is an example of an Item</description>
<link>http://www.domain.com/link.htm</link>
<guid isPermaLink="false"> 1102345</guid>
<pubDate>Tue, 29 Aug 2006 09:00:00 -0400</pubDate>
</item>
</channel>
</rss>
La salida del programa, ejecutando la función printTree() es la siguiente:
|-<rss>[version=2.0]:
|-<channel>[No params]:
|-<title>[No params]:RSS Example
|-<description>[No params]:This is an example of an RSS feed
|-<link>[No params]:http://www.domain.com/link.htm
|-<lastBuildDate>[No params]:Mon, 28 Aug 2006 11:12:55 -0400
|-<pubDate>[No params]:Tue, 29 Aug 2006 09:00:00 -0400
|-<item>[No params]:
|-<title>[No params]:Item Example
|-<description>[No params]:This is an example of an Item
|-<link>[No params]:http://www.domain.com/link.htm
|-<guid>[isPermaLink=false]: 1102345
|-<pubDate>[No params]:Tue, 29 Aug 2006 09:00:00 -0400
Como vemos se ha formado toda la estructura del XML partiendo del nodo raíz con nombre rss. Cada uno de los niveles representa un nodo y sus hijos, así el nodo <channel> tiene por hijos a los nodos: title,description,link,lastBuildDate,pubDate e Item.
Se pueden encontrar más ejemplos de XML y el programa test.cpp utilizado para parsearlos en el código funde del proyecto en la sección de Descargas de esta publicación.
Ejemplo de uso
Veamos un ejemplo de uso del parser para casos en los que tengamos que manipular los datos y acceder a lugares específicos de la estructura de nuestro XML. Supongamos el siguiente fichero XML:
<game>
<edificios>
<edificio>
<tipo>ed1</tipo>
<nombre>Edificio 1</nombre>
<x>77</x>
<y>810</y>
</edificio>
<edificio>
<tipo>ed2</tipo>
<nombre>Edificio 2</nombre>
<x>153</x>
<y>615</y>
</edificio>
</edificios>
<personajes>
<personaje x="101" y="213" nombre="Homer" />
<personaje x="327" y="515" nombre="Edd" />
</personajes>
</game>
En primer lugar analizamos el fichero como lo hicimos en el apartado anterior:
xmlparser * parser;
xmlnode * gameXML;
string line,xml;
ifstream textstream("game.xml",ifstream::in);
while (getline(textstream, line)) {
xml+=line;
}
textstream.close();
parser = new xmlparser(xml);
gameXML = parser->getParentNode();
Una vez analizado el fichero XML tendremos que recorrer cada uno de los nodos del nodo raíz y comprobar si se trata de un nodo de tipo personajes en el cual tendremos que leer la estructura de una forma determinada o bien si se trata de un nodo de tipo edificios. Lo hacemos de la siguiente forma:
for(int i=0;i<gameXML->getChildCount();i++){
if(gameXML->getChild(i)->getNodeName().compare("edificios")==0){
/*Leer los nodos de tipo edificio*/
}
else
if(gameXML->getChild(i)->getNodeName().compare("personajes")==0){
/*Leer os nodos de tipo personaje */
}
}
Se ha realizado el XML de tal modo que en los elementos de tipo edificio tengamos los datos contenidos en sus respectivos tags XML y en los elementos de tipo personaje tengamos los datos contenidos como atributos del propio tag. Comenzaremos leyendo los datos de los nodos es este último tipo por su simplicidad:
if(gameXML->getChild(i)->getNodeName().compare("personajes")==0){
xmlnode * personajes=gameXML->getChild(i);
for(int j=0;j<personajes->getChildCount();j++){
cout << personajes->getChild(j)->getNodeParamValue("x");
cout << personajes->getChild(j)->getNodeParamValue("y");
cout << personajes->getChild(j)->getNodeParamValue("nombre");
}
}
Para leer los datos de cada edificio tendremos que hacer algo similar a la lectura de los datos desde el nodo raíz. Tendremos que analizar cada uno de los nodos hijos de un nodo de tipo edificio y comprobar qué tipo de nodo es para posteriormente asignar el valor que corresponda:
xmlnode * edificios=gameXML->getChild(i);
for(int j=0;j<edificios->getChildCount();j++){
xmlnode * edificio=edificios->getChild(j);
cout << "---New edificio---" << endl;
for(int k=0;k<edificio->getChildCount();k++){
/* Analizar cada nodo de un elemento edificio */
}
}
El análisis de cada nodo individual lo vemos a continuación:
if(edificio->getChild(k)->getNodeName().compare("tipo")==0){
cout << edificio->getChild(k)->getNodeText() << endl;
}
else if(edificio->getChild(k)->getNodeName().compare("nombre")==0){
cout << edificio->getChild(k)->getNodeText() << endl;
}
else if(edificio->getChild(k)->getNodeName().compare("x")==0){
cout << edificio->getChild(k)->getNodeText() << endl;
}
else if(edificio->getChild(k)->getNodeName().compare("y")==0){
cout << edificio->getChild(k)->getNodeText() << endl;
}
Comentario
Puedes usar las siguientes etiquetas y atributos HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>
Si te ha gustado el artículo inscribete al feed clicando en la imagen más abajo para tenerte siempre actualizado sobre los nuevos contenidos del blog:
0 comments:
No insertes enlaces clicables, de lo contrario se eliminará el comentario. Si quieres ser advertido via email de los nuevos comentarios marca la casilla "Notificarme". Si te ayudé con la publicación o con las respuestas a los comentarios, compártelo en Facebook, Twitter, Tumblr, Google +, Pinterest o Instagram. Gracias.