====== TinyXML ======
Para trabajar con archivos .xml desde C\C++.
* [[http://www.grinninglizard.com/tinyxml/|Página oficial]]
* [[http://www.grinninglizard.com/tinyxmldocs/index.html|Documentación]]
* [[http://sourceforge.net/projects/tinyxml|Descarga]]
* {{fw:others:tinyxml_2_5_3.zip|Versión sobre la que se ha hecho este documento}}
===== General =====
==== Cómo empezar? ====
Una vez descargado y descomprimido nos encontramos con una serie de ficheros .cpp y .h. Los podemos añadir a un proyecto de Visual Studio si trabajamos en Windows o llamar al comando ''make'' si estamos trabajando en linux (ya viene con su makefile to mono) y directamente se compilará. Una vez compilemos y ejecutemos lo que estaremos viendo será el programa que viene de ejemplo en ''xmltest.cpp''. Aún así para utilizarlo en tu código únicamente tendrás que añadir ''#include "tinyxml.h"''.
==== Cargar un documento ====
TiXmlDocument doc( "demo.xml" );
if (!doc.LoadFile())
cout << "Carga incorrecta.\n";
''TiXmlDocument'' es un objeto que representa un documento .xml, el método ''LoadFile'' carga dicho documento sobre el objeto y devuelve un boolean indicando si la carga se ha realizado correctamente.
==== Estructura de clases ====
{{ fw:others:classtixmlbase.png |}}
\\ La clase de la que heredan todas las demás subclases es ''TiXmlBase'', inmediatamente, después de esta vienen ''[[#los_atributos|TiXmlAttribute]]'' y ''[[#recorrer_un_archivo|TiXmlNode]]''.
===== Escritura =====
==== Montar un documento ====
La estructura de un objeto .xml empieza con una declaración, luego tiene un elemento principal y dentro de este otros elementos. Un elemento puede contener otros elementos, texto y\o propiedades. Cada uno de estos conceptos tiene un objeto en TinyXML asociado:
* **TiXmlDeclaration**, el primer elemento del fichero. Se crea pasándole al constructor tres parámetros correspondientes a la versión, la codificación y el standalone. Sus métodos permiten consultar y asginar estas propiedades del documento.
* **TiXmlElement**, equivale a un elemento cualquiera (ya sea el principal o uno anidado), puedes añadir sus atributos mediante el método ''setAttribute''. Puedes recoger el texto, sin tener que acceder a su elemento anidado TiXmlText, mediante el método ''GetText''.
* **TiXmlText**, es el contenido, en texto, de un tag. El método más destacado es ''ToText''.
=== Cómo anidar elementos? ===
Para ello existe la función ''LinkEndChild'' que tienen tanto los elementos de un documento como el documento en sí, esta función añade al final el elemento pasado por parámetro:
TiXmlDocument doc;
TiXmlDeclaration * decl = new TiXmlDeclaration( "1.0", "", "" );
TiXmlElement * element = new TiXmlElement( "Hello" );
TiXmlText * text = new TiXmlText( "World" );
element->LinkEndChild( text );
doc.LinkEndChild( decl );
doc.LinkEndChild( element );
Montaría:
World
Otro ejemplo:
TiXmlDocument doc;
TiXmlElement* msg;
TiXmlDeclaration* decl = new TiXmlDeclaration( "1.0", "", "" );
doc.LinkEndChild( decl );
TiXmlElement * root = new TiXmlElement( "MyApp" );
doc.LinkEndChild( root );
msg = new TiXmlElement( "Welcome" );
msg->LinkEndChild( new TiXmlText( "Welcome to MyApp" ));
root->LinkEndChild( msg );
msg = new TiXmlElement( "Farewell" );
msg->LinkEndChild( new TiXmlText( "Thank you for using MyApp" ));
root->LinkEndChild( msg );
...
==== Los atributos ====
Asignar un atributo a un elemento es fácil utilizando la función ''SetAttribute(string, string|int)'' de este, como vemos permite asignar un valor en string o uno en integer, si quisieramos asignar un número decimal utilizaríamos ''SetDoubleAttribute''. \\
==== Guardar ====
Para guardar un documento, una vez lo tengamos montado únicamente deberemos de llamar al método ''SaveFile (string)'' de un objeto ''TiXmlDocument''.
doc.SaveFile("c:\\ejemplo.xml");
===== Lectura =====
==== Recorrer un archivo ====
Una vez recojas el primer elemento del documento obtendrás como tal un ''TiXmlNode'', a partir de este, como ya sabes, la estructura está montada en forma de árbol. Para acceder a sus nodos hijos sólo tendrás que recoger el primero con ''FirstChild'' y recorrer los elementos mediante ''NextSibling'' hasta que este método no devuelva NULL. El método ''Value'' devolvería el nombre del tag.
int countNodes (TiXmlNode* node) {
if (node == NULL)
return 0;
TiXmlNode* child = node->FirstChild();
int i = 1;
while(child != NULL) {
i += countNodes(child);
child = child->NextSibling();
}
return i;
}
int main() {
TiXmlDocument doc( "ex1.xml" );
if (!doc.LoadFile())
cout << "Carga incorrecta.\n";
cout << countNodes(&doc) << "\n";
system("pause");
return 0;
}
Para saber el tipo de elemento que es la clase ''TiXmlNode'' tiene un método que devuelve un integer comparable a las constantes dentro de esa mismaclase: ''TiXmlNode::COMMENT'', ''TiXmlNode::DECLARATION'', ''TiXmlNode::DOCUMENT'', ''TiXmlNode::ELEMENT'', ''TiXmlNode::TEXT'' o ''TiXmlNode::UNKNOW''. \\ \\
De un nodo también podemos saber el atributo padre utilizando el método ''Parent''. O sacar el valor en texto mediante ''ToText''. \\ \\
Aún pudiendo recorrerse de forma sencilla, lo mejor es utilizar el ''[[#utilizar_el_tixmlhandle|TiXmlHandle]]''.
==== Cómo tratar los atributos ====
=== Recorrer los atributos de un elemento ===
Sólo debemos coger el primer atributo de un elemento con ''FirstAttribute'' e ir recorriendolos utilizando el ''Next'' que te devuelve el siguiente o si no NULL.
TiXmlAttribute* pAttrib=pElement->FirstAttribute();
while (pAttrib) {
pAttrib=pAttrib->Next();
}
=== Recoger el nombre ===
Nada, llamas al método ''Name'' y ahí lo tienes, en un stringcito tó bonito.
=== Recoger el valor ===
Recoger un valor como string es muy sencillo, únicamente hemos de llamar al método ''Value'' y este lo devuelve sin problema alguno. \\
Para recoger el valor de un atributo en formato numérico tenemos que recoger su objeto ''TiXmlAttribute'' correspondiente y a este le llamaríamos a los métodos ''QueryIntValue(int*)'' o ''QueryDoubleValue(double*)''; lo que hacen estos métodos es recoger el valor e introducirlo en la variable (int o double) pasada por referencia, pero como no sabemos qué tipo es este método devolverá ''TIXML_SUCCESS'' si la asignación ha sido correcta.
TiXmlAttribute* pAttrib=pElement->FirstAttribute();
if (pAttrib->QueryIntValue(&ival)==TIXML_SUCCESS) printf( "valor %d", ival);
if (pAttrib->QueryDoubleValue(&dval)==TIXML_SUCCESS) printf( "valor %1.1f", dval);
===== Como... =====
==== Insertar un comentario ====
Se crea un objeto ''TiXmlComment'' y le añadimos el texto mediante su método ''SetValue''.
TiXmlComment * comment = new TiXmlComment();
comment->SetValue(" Settings for MyApp " );
root->LinkEndChild( comment );
==== Utilizar el TiXmlHandle ====
Es una forma más sencilla de acceder a los elementos permitiendo acceder directamente a sus hijos.
TiXmlHandle docHandle( &document );
TiXmlElement* child2 = docHandle.FirstChild("Document").FirstChild("Element").Child("Child", 1).ToElement();
int i=0;
while () {
TiXmlElement* child = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", i ).ToElement();
if ( !child )
break;
i++;
}
==== Enlazar una clase a un archivo .xml ====
Evidentemente puedes hacerlo manualmente, pero la forma más sencilla es utilizando [[http://sourceforge.net/projects/tinybind|TinyBind]].