====== 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]].