From d6571e5a9b8fc2bed416ff4798e3a29136004ff5 Mon Sep 17 00:00:00 2001 From: Tim Redfern Date: Thu, 9 Jan 2014 16:50:51 +0000 Subject: beginnng json output --- NT/src/factory.cpp | 186 ++++++++++++++- NT/src/factory.h | 15 +- NT/src/nodes.h | 20 +- NT/src/rotor.cpp | 12 +- NT/src/rotor.h | 41 +++- NT/src/xmlIO.cpp | 673 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 922 insertions(+), 25 deletions(-) create mode 100644 NT/src/xmlIO.cpp (limited to 'NT/src') diff --git a/NT/src/factory.cpp b/NT/src/factory.cpp index 6888a19..db50919 100644 --- a/NT/src/factory.cpp +++ b/NT/src/factory.cpp @@ -5,7 +5,185 @@ using namespace Rotor; Node_factory::Node_factory(){ //for now, statically load prototype map in constructor - add_type("time",new Time(),"nodes"); - add_type("multiply",new Multiply(),"nodes"); - add_type("print",new Print(),"nodes"); -} \ No newline at end of file + add_type(new Time(),"nodes"); + add_type(new Multiply(),"nodes"); + add_type(new Print(),"nodes"); +} +bool Node_factory::list_node(const string &t,xmlIO XML){ + for (auto& type: type_map) { + if (type.first==t) { + list_node(type.second,XML); + return true; + } + } + XML.addValue("error","Node /"+t+"/ not found"); + return false; +}; +bool Node_factory::list_node(const string &t,Json::Value &JSON){ + for (auto& type: type_map) { + if (type.first==t) { + JSON["node"]=list_node(type.second); + return true; + } + } + JSON["error"]="Node /"+t+"/ not found"; + return false; +}; +Json::Value Node_factory::list_node(Rotor::Node* _node){ + Json::Value node; + node["node_type"]=_node->node_type; + node["title"]=_node->title; + node["output_type"]=_node->output_type; + node["description"]=_node->description; + node["node_id"]=_node->node_id; + node["ui_type"]=_node->ui_type; + + if (_node->vars.size()){ + node["vars"]=Json::arrayValue; + for (auto& var: _node->vars) { + Json::Value newvar; + newvar["type"]=var.second->get_type(); + newvar["connectable"]=var.second->connectable?"yes":"no"; + node["vars"].append(newvar); + } + } +/* + if (_node->inputs.size()){ + node["signal_inputs"]=Json::arrayValue; + for (auto& input: _node->inputs) { + Json::Value signal_input; + signal_input["title"]=input->title; + signal_input["description"]=input->description; + node["signal_inputs"].append(signal_input); + } + } + if (dynamic_cast (_node)!=nullptr) { + if ((dynamic_cast(_node))->image_inputs.size()){ + node["image_inputs"]=Json::arrayValue; + for (auto& input: (dynamic_cast(_node))->image_inputs) { + Json::Value image_input; + image_input["title"]=input->title; + image_input["description"]=input->description; + node["image_inputs"].append(image_input); + } + } + } + if (_node->parameters.size()){ + node["parameters"]=Json::arrayValue; + for (auto& param: _node->parameters) { + Json::Value parameter; + parameter["name"]=param.first; + parameter["type"]=param.second->type; + parameter["title"]=param.second->title; + parameter["description"]=param.second->description; + parameter["value"]=param.second->value; + parameter["min"]=param.second->min; + parameter["max"]=param.second->max; + parameter["step"]=param.second->step; + node["parameters"].append(parameter); + } + } + if (_node->attributes.size()){ + node["attributes"]=Json::arrayValue; + for (auto& attr: _node->attributes) { + Json::Value attribute; + attribute["name"]=attr.first; + attribute["title"]=attr.second->title; + attribute["description"]=attr.second->description; + if (attr.second->vals.size()){ //document attribute enumeration + attribute["value"]=attr.second->value; + attribute["type"]="enum"; + attribute["options"]=Json::arrayValue; + for (auto val: attr.second->vals){ + attribute["options"].append(val); + } + } + else { + attribute["type"]=attr.second->type; + if (attr.second->type=="array"){ + attribute["value"]=Json::arrayValue; + } + else attribute["value"]=attr.second->value; + } + node["attributes"].append(attribute); + } + } +*/ + return node; +} + +void Node_factory::list_node(Rotor::Node* type,xmlIO XML,int i){ + XML.addTag("node"); + XML.addAttribute("node","output_type",type->output_type,i); + XML.addAttribute("node","node_type",type->node_type,i); + XML.addAttribute("node","title",type->title,i); + XML.addAttribute("node","description",type->description,i); + XML.addAttribute("node","node_id",type->node_id,i); + XML.addAttribute("node","ui_type",type->ui_type,i); + XML.pushTag("node",i); +/* + //if (type->description!="") { + // XML.addTag("description"); + // XML.setValue("description",type->description,0); + //} + int j=0; + for (auto& input: type->inputs) { + XML.addTag("signal_input"); + XML.addAttribute("signal_input","title",input->title,j); + XML.addAttribute("signal_input","description",input->description,j); + j++; + } + j=0; + if (dynamic_cast (type)!=nullptr) { + for (auto& input: (dynamic_cast(type))->image_inputs) { + XML.addTag("image_input"); + XML.addAttribute("image_input","title",input->title,j); + XML.addAttribute("image_input","description",input->description,j); + j++; + } + } + j=0; + for (auto& parameter: type->parameters) { + XML.addTag("parameter"); + XML.addAttribute("parameter","name",parameter.first,j); + XML.addAttribute("parameter","type",parameter.second->type,j); + XML.addAttribute("parameter","title",parameter.second->title,j); + XML.addAttribute("parameter","description",parameter.second->description,j); + XML.addAttribute("parameter","value",parameter.second->value,j); + XML.addAttribute("parameter","min",parameter.second->min,j); + XML.addAttribute("parameter","max",parameter.second->max,j); + XML.addAttribute("parameter","step",parameter.second->step,j); + j++; + } + j=0; + for (auto& attribute: type->attributes) { + XML.addTag("attribute"); + XML.addAttribute("attribute","name",attribute.first,j); + XML.addAttribute("attribute","title",attribute.second->title,j); + XML.addAttribute("attribute","description",attribute.second->description,j); + if (attribute.second->vals.size()){ //document attribute enumeration + XML.addAttribute("attribute","value",attribute.second->value,j); + XML.addAttribute("attribute","type","enum",j); + XML.pushTag("attribute",j); + int k=0; + for (auto val: attribute.second->vals){ + XML.addTag("option"); + XML.addAttribute("option","value",val,k); + k++; + } + XML.popTag(); + } + else { + XML.addAttribute("attribute","type",attribute.second->type,j); + if (attribute.second->type=="array"){ + XML.pushTag("attribute",j); + XML.addTag("value"); + XML.popTag(); + } + else XML.addAttribute("attribute","value",attribute.second->value,j); + } + j++; + } +*/ + XML.popTag(); +} diff --git a/NT/src/factory.h b/NT/src/factory.h index ac204a0..8c44507 100644 --- a/NT/src/factory.h +++ b/NT/src/factory.h @@ -12,19 +12,18 @@ namespace Rotor { ~Node_factory(){ for (auto t:type_map) delete t.second; } - void add_type(std::string type,Node* proto){ - type_map[type]=proto; - type_map[type]->type=type; + void add_type(Node* proto){ + type_map[proto->node_type]=proto; }; - void add_type(std::string type,Node* proto,std::string category){ - add_type(type,proto); + void add_type(Node* proto,std::string category){ + add_type(proto); if (category_map.find(category)==category_map.end()) category_map[category]=vector(); category_map[category].push_back(proto); }; Node *create(std::map &settings){ - if (settings.find("type")!=settings.end()) { - if (type_map.find(settings["type"])!=type_map.end()) { - return type_map[settings["type"]]->clone(settings); + if (settings.find("node_type")!=settings.end()) { + if (type_map.find(settings["node_type"])!=type_map.end()) { + return type_map[settings["node_type"]]->clone(settings); } } return NULL; diff --git a/NT/src/nodes.h b/NT/src/nodes.h index a32408e..da24292 100644 --- a/NT/src/nodes.h +++ b/NT/src/nodes.h @@ -6,9 +6,13 @@ using namespace std; namespace Rotor{ - class Time: public Node_type { + class Double_node: public Node_type { public: - Time(){}; + Double_node(){output_type="double";}; + }; + class Time: public Double_node { + public: + Time(){node_type="time";}; Time(map &settings):Time() { init(settings); }; @@ -20,11 +24,12 @@ namespace Rotor{ private: double value; }; - class Multiply: public Node_type { + class Multiply: public Double_node { public: Multiply(){ inlet=create_inlet("inlet"); value=create_inlet("value"); + node_type="multiply"; } Multiply(map &settings):Multiply() { init(settings); @@ -39,10 +44,15 @@ namespace Rotor{ Variable_type *value; double result; }; - class Print: public Node_type { + class String_node: public Node_type { + public: + String_node(){output_type="string";}; + }; + class Print: public String_node { public: Print(){ - inlet=create_inlet("inlet"); + inlet=create_inlet("inlet"); + node_type="print"; } Print(map &settings):Print() { init(settings); diff --git a/NT/src/rotor.cpp b/NT/src/rotor.cpp index 677fae0..c08734c 100644 --- a/NT/src/rotor.cpp +++ b/NT/src/rotor.cpp @@ -11,12 +11,13 @@ using namespace Rotor; int main(){ Node_factory f; - map settings={{"type","time"}}; +/* + map settings={{"node_type","time"}}; Node *t=f.create(settings); - settings={{"value","2"},{"type","multiply"}}; + settings={{"value","2"},{"node_type","multiply"}}; Node *m=f.create(settings); if (!m->connect("inlet",t)) printf("not connected...\n"); - settings={{"type","print"}}; + settings={{"node_type","print"}}; Node *p=f.create(settings); if (!p->connect("inlet",m)) printf("not connected...\n"); for (double t=0;t<10.0;t+=0.765){ @@ -26,4 +27,9 @@ int main(){ delete t; delete m; delete p; +*/ +Json::Value js; +f.list_node("multiply",js); +Json::StyledWriter writer; +cerr<> value; } + std::string get_type(){ //need this to output node templates + return "unknown"; + } bool connect(Node* target){ if (connectable){ if (dynamic_cast*>(target)){ @@ -77,6 +81,27 @@ namespace Rotor { } T value; }; + template class Variable_array: public Variable_type { + public: + Variable_array(){}; + void add(int num=1){ + for (int i=0;iwhich){ + return values[which].connect(target); + } + return false; + } + const T& get(int which,const Frame_parameters &frame){ + if (values.size()>which){ + return values[which].get(frame); + } + return value; + } + std::vector> values; + T value; + }; //don't forget the dupliicate inlets //it needs to be a property of a var //vars need to be: @@ -104,11 +129,13 @@ namespace Rotor { return false; } virtual Node* clone(std::map &_settings)=0; - std::string type; - std::string type; - std::string type; - std::string type; - protected: + std::string node_type; + std::string node_id; + std::string id; + std::string description; + std::string title; + std::string ui_type; + std::string output_type; std::unordered_map vars; }; template class Node_type : public Node { @@ -130,6 +157,10 @@ namespace Rotor { vars[name]=new Variable_type(false); return (dynamic_cast*>(vars[name])); } + template Variable_array* create_array(std::string name){ + vars[name]=new Variable_array(); + return (dynamic_cast*>(vars[name])); + } }; } diff --git a/NT/src/xmlIO.cpp b/NT/src/xmlIO.cpp new file mode 100644 index 0000000..be5efc0 --- /dev/null +++ b/NT/src/xmlIO.cpp @@ -0,0 +1,673 @@ +#include "xmlIO.h" + +#include +#include +#include + +//---------------------------------------- +// a pretty useful tokenization system: +static vector tokenize(const string & str, const string & delim); +static vector tokenize(const string & str, const string & delim) +{ + vector tokens; + + size_t p0 = 0, p1 = string::npos; + while(p0 != string::npos) + { + p1 = str.find_first_of(delim, p0); + if(p1 != p0) + { + string token = str.substr(p0, p1 - p0); + tokens.push_back(token); + } + p0 = str.find_first_not_of(delim, p1); + } + return tokens; +} +//---------------------------------------- + +//---------------------------------------- +xmlIO::xmlIO(): + storedHandle(NULL) +{ + level = 0; + //we do this so that we have a valid handle + //without the need for loadFile + storedHandle = TiXmlHandle(&doc); +} + +//---------------------------------------- +xmlIO::xmlIO(const string& xmlFile): + storedHandle(NULL) +{ + level = 0; + //we do this so that we have a valid handle + //without the need for loadFile + storedHandle = TiXmlHandle(&doc); + loadFile(xmlFile); +} + +//--------------------------------------------------------- +xmlIO::~xmlIO() +{ +} + +//--------------------------------------------------------- +void xmlIO::setVerbose(bool _verbose){ +} + +//--------------------------------------------------------- +void xmlIO::clear(){ + //we clear from our root level + //this is usually the document + //but if we are pushed - it could + //be all the tags inside of the pushed + //node - including the node itself! + + storedHandle.ToNode()->Clear(); +} + +//--------------------------------------------------------- +bool xmlIO::loadFile(const string& xmlFile){ + + //string fullXmlFile = toDataPath(xmlFile); + + bool loadOkay = doc.LoadFile(xmlFile); + + //theo removed bool check as it would + //return false if the file exists but was + //empty + + //our push pop level should be set to 0! + level = 0; + + storedHandle = TiXmlHandle(&doc); + return loadOkay; +} + +//--------------------------------------------------------- +bool xmlIO::saveFile(const string& xmlFile){ + + //string fullXmlFile = toDataPath(xmlFile); + return doc.SaveFile(xmlFile); +} + +//--------------------------------------------------------- +bool xmlIO::saveFile(){ + return doc.SaveFile(); +} + +//--------------------------------------------------------- +void xmlIO::clearTagContents(const string& tag, int which){ + //we check it first to see if it exists + //otherwise setValue will make a new empty tag + if( tagExists(tag, which) )setValue(tag, "", which); +} + +//--------------------------------------------------------- +void xmlIO::removeTag(const string& tag, int which){ + + vector tokens = tokenize(tag,":"); + + //no tags so we return + if( tokens.size() == 0 ) return; + + //grab the handle from the level we are at + //normally this is the doc but could be a pushed node + TiXmlHandle tagHandle = storedHandle; + + if(which < 0) which = 0; + + for(int x=0;x<(int)tokens.size();x++){ + + //we only support multi tags + //with same name at root level + if(x > 0) which = 0; + + TiXmlHandle isRealHandle = tagHandle.ChildElement( tokens.at(x), which); + + if ( !isRealHandle.ToNode() ) break; + else{ + if (x == (int)tokens.size()-1){ + //if we are at the last tag and it exists + //we use its parent to remove it - haha + tagHandle.ToNode()->RemoveChild( isRealHandle.ToNode() ); + } + tagHandle = isRealHandle; + } + } +} + +//--------------------------------------------------------- +int xmlIO::getValue(const string& tag, int defaultValue, int which){ + TiXmlHandle valHandle(NULL); + if (readTag(tag, valHandle, which)){ + return toInt(valHandle.ToText()->Value()); + } + return defaultValue; +} + +//--------------------------------------------------------- +double xmlIO::getValue(const string& tag, double defaultValue, int which){ + TiXmlHandle valHandle(NULL); + if (readTag(tag, valHandle, which)){ + return toFloat(valHandle.ToText()->Value()); + } + return defaultValue; +} + +//--------------------------------------------------------- +string xmlIO::getValue(const string& tag, const string& defaultValue, int which){ + TiXmlHandle valHandle(NULL); + if (readTag(tag, valHandle, which)){ + return valHandle.ToText()->ValueStr(); + } + return defaultValue; +} + +//--------------------------------------------------------- +bool xmlIO::readTag(const string& tag, TiXmlHandle& valHandle, int which){ + + vector tokens = tokenize(tag,":"); + + TiXmlHandle tagHandle = storedHandle; + for(int x=0;x<(int)tokens.size();x++){ + if(x == 0)tagHandle = tagHandle.ChildElement(tokens.at(x), which); + else tagHandle = tagHandle.FirstChildElement( tokens.at(x) ); + } + + // once we've walked, let's get that value... + valHandle = tagHandle.Child( 0 ); + return (valHandle.ToText() != NULL); +} + + +//--------------------------------------------------------- +bool xmlIO::pushTag(const string& tag, int which){ + + int pos = tag.find(":"); + + // Either find the tag specified, or the first tag if colon-seperated. + string tagToFind((pos > 0) ? tag.substr(0,pos) :tag); + + //we only allow to push one tag at a time. + TiXmlHandle isRealHandle = storedHandle.ChildElement(tagToFind, which); + + if( isRealHandle.ToNode() ){ + storedHandle = isRealHandle; + level++; + return true; + }else{ + //ofLog( OF_LOG_ERROR, "pushTag - <" + tag + "> tag not found"); + } + + return false; +} + +//--------------------------------------------------------- +int xmlIO::popTag(){ + + if(level >= 1){ + TiXmlHandle parent( (storedHandle.ToNode() )->Parent() ); + storedHandle = parent; + level--; + }else{ + storedHandle = TiXmlHandle(&doc); + level = 0; + } + + return level; +} + +//--------------------------------------------------------- +int xmlIO::getPushLevel(){ + return level; +} + +//--------------------------------------------------------- +bool xmlIO::tagExists(const string& tag, int which){ + + vector tokens = tokenize(tag,":"); + + bool found = false; + + //grab the handle from the level we are at + //normally this is the doc but could be a pushed node + TiXmlHandle tagHandle = storedHandle; + + if(which < 0) which = 0; + + for(int x=0;x<(int)tokens.size();x++){ + + //we only support multi tags + //with same name at root level + if(x > 0) which = 0; + + TiXmlHandle isRealHandle = tagHandle.ChildElement( tokens.at(x), which); + + //as soon as we find a tag that doesn't exist + //we return false; + if ( !isRealHandle.ToNode() ){ + found = false; + break; + } + else{ + found = true; + tagHandle = isRealHandle; + } + } + + return found; +} + + +//--------------------------------------------------------- +int xmlIO::getNumTags(const string& tag){ + //this only works for tags at the current root level + + int pos = tag.find(":"); + + // Either find the tag specified, or the first tag if colon-seperated. + string tagToFind((pos > 0) ? tag.substr(0,pos) :tag); + + //grab the handle from the level we are at + //normally this is the doc but could be a pushed node + //TiXmlHandle tagHandle = storedHandle; + + int count = 0; + + //ripped from tinyXML as doing this ourselves once is a LOT! faster + //than having this called n number of times in a while loop - we go from n*n iterations to n iterations + + TiXmlElement* child = ( storedHandle.FirstChildElement( tagToFind ) ).ToElement(); + for (count = 0; child; child = child->NextSiblingElement( tagToFind ), ++count){ + //nothing + } + + return count; +} + + + +//--------------------------------------------------------- +int xmlIO::writeTag(const string& tag, const string& valueStr, int which){ + + vector tokens = tokenize(tag,":"); + + // allocate on the stack + vector elements; + elements.reserve(tokens.size()); + for(int x=0;x<(int)tokens.size();x++) + elements.push_back(tokens.at(x)); + + + TiXmlText Value(valueStr); + + // search our way up - do these tags exist? + // find the first that DOESNT exist, then move backwards... + TiXmlHandle tagHandle = storedHandle; + + bool addNewTag = false; + if(which == -1)addNewTag = true; + + for(int x=0;x<(int)tokens.size();x++){ + + if( x > 0 ){ + //multi tags of same name + //only for the root level + which = 0; + addNewTag = false; + } + + TiXmlHandle isRealHandle = tagHandle.ChildElement( tokens.at(x), which); + + if ( !isRealHandle.ToNode() || addNewTag){ + + for(int i=(int)tokens.size()-1;i>=x;i--){ + if (i == (int)tokens.size()-1){ + elements[i].InsertEndChild(Value); + } else { + elements[i].InsertEndChild(elements[i+1]); + } + } + + tagHandle.ToNode()->InsertEndChild(elements[x]); + + break; + + } else { + tagHandle = isRealHandle; + if (x == (int)tokens.size()-1){ + // what we want to change : TiXmlHandle valHandle = tagHandle.Child( 0 ); + tagHandle.ToNode()->Clear(); + tagHandle.ToNode()->InsertEndChild(Value); + } + } + } + + + //lets count how many tags with our name exist so we can return an index + + //ripped from tinyXML as doing this ourselves once is a LOT! faster + //than having this called n number of times in a while loop - we go from n*n iterations to n iterations + int numSameTags; + TiXmlElement* child = ( storedHandle.FirstChildElement( tokens.at(0) ) ).ToElement(); + for (numSameTags = 0; child; child = child->NextSiblingElement( tokens.at(0) ), ++numSameTags){ + //nothing + } + + return numSameTags; +} + +//--------------------------------------------------------- +int xmlIO::setValue(const string& tag, int value, int which){ + int tagID = writeTag(tag, toString(value).c_str(), which) -1; + return tagID; +} + +//--------------------------------------------------------- +int xmlIO::setValue(const string& tag, double value, int which){ + int tagID = writeTag(tag, toString(value).c_str(), which) -1; + return tagID; +} + +//--------------------------------------------------------- +int xmlIO::setValue(const string& tag, const string& value, int which){ + int tagID = writeTag(tag, value, which) -1; + return tagID; +} + +//--------------------------------------------------------- +int xmlIO::addValue(const string& tag, int value){ + int tagID = writeTag(tag, toString(value).c_str(), -1) -1; + return tagID; +} + +//--------------------------------------------------------- +int xmlIO::addValue(const string& tag, double value){ + int tagID = writeTag(tag, toString(value).c_str(), -1) -1; + return tagID; +} + +//--------------------------------------------------------- +int xmlIO::addValue(const string& tag, const string& value){ + int tagID = writeTag(tag, value, -1) -1; + return tagID; +} + +//--------------------------------------------------------- +int xmlIO::addTag(const string& tag){ + int tagID = writeTag(tag, "", -1) -1; + return tagID; +} + +/******************* +* Attribute addons * +*******************/ + +//--------------------------------------------------------- +int xmlIO::addAttribute(const string& tag, const string& attribute, int value, int which){ + int tagID = writeAttribute(tag, attribute, toString(value).c_str(), which) -1; + return tagID; +} + +//--------------------------------------------------------- +int xmlIO::addAttribute(const string& tag, const string& attribute, int value){ + return addAttribute(tag,attribute,value,-1); +} + +//--------------------------------------------------------- +int xmlIO::addAttribute(const string& tag, const string& attribute, double value, int which){ + int tagID = writeAttribute(tag, attribute, toString(value).c_str(), which) -1; + return tagID; +} + +//--------------------------------------------------------- +int xmlIO::addAttribute(const string& tag, const string& attribute, double value){ + return addAttribute(tag,attribute,value,-1); +} + +//--------------------------------------------------------- +int xmlIO::addAttribute(const string& tag, const string& attribute, const string& value, int which){ + int tagID = writeAttribute(tag, attribute, value, which) -1; + return tagID; +} + +//--------------------------------------------------------- +int xmlIO::addAttribute(const string& tag, const string& attribute, const string& value){ + return addAttribute(tag,attribute,value,-1); +} + +//--------------------------------------------------------- +void xmlIO::removeAttribute(const string& tag, const string& attribute, int which){ + vector tokens = tokenize(tag,":"); + TiXmlHandle tagHandle = storedHandle; + for (int x = 0; x < (int)tokens.size(); x++) { + if (x == 0) + tagHandle = tagHandle.ChildElement(tokens.at(x), which); + else + tagHandle = tagHandle.FirstChildElement(tokens.at(x)); + } + + if (tagHandle.ToElement()) { + TiXmlElement* elem = tagHandle.ToElement(); + elem->RemoveAttribute(attribute); + } +} + +//--------------------------------------------------------- +void xmlIO::clearTagAttributes(const string& tag, int which){ + vector names; + getAttributeNames( tag, names, which ); + for (vector::iterator i = names.begin(); i != names.end(); i++) + removeAttribute(tag, *i, which); +} + +//--------------------------------------------------------- +int xmlIO::getNumAttributes(const string& tag, int which){ + vector tokens = tokenize(tag,":"); + TiXmlHandle tagHandle = storedHandle; + for (int x = 0; x < (int)tokens.size(); x++) { + if (x == 0) + tagHandle = tagHandle.ChildElement(tokens.at(x), which); + else + tagHandle = tagHandle.FirstChildElement(tokens.at(x)); + } + + if (tagHandle.ToElement()) { + TiXmlElement* elem = tagHandle.ToElement(); + + // Do stuff with the element here + TiXmlAttribute* first = elem->FirstAttribute(); + if (first) { + int count = 1; + for (TiXmlAttribute* curr = first; curr != elem->LastAttribute(); curr = curr->Next()) + count++; + return count; + } + } + return 0; +} + +//--------------------------------------------------------- +bool xmlIO::attributeExists(const string& tag, const string& attribute, int which){ + vector tokens = tokenize(tag,":"); + TiXmlHandle tagHandle = storedHandle; + for (int x = 0; x < (int)tokens.size(); x++) { + if (x == 0) + tagHandle = tagHandle.ChildElement(tokens.at(x), which); + else + tagHandle = tagHandle.FirstChildElement(tokens.at(x)); + } + + if (tagHandle.ToElement()) { + TiXmlElement* elem = tagHandle.ToElement(); + + // Do stuff with the element here + for (TiXmlAttribute* a = elem->FirstAttribute(); a; a = a->Next()) { + if (a->Name() == attribute) + return true; + } + } + return false; +} + +//--------------------------------------------------------- +bool xmlIO::getAttributeNames(const string& tag, vector& outNames, int which){ + vector tokens = tokenize(tag,":"); + TiXmlHandle tagHandle = storedHandle; + for (int x = 0; x < (int)tokens.size(); x++) { + if (x == 0) + tagHandle = tagHandle.ChildElement(tokens.at(x), which); + else + tagHandle = tagHandle.FirstChildElement(tokens.at(x)); + } + + if (tagHandle.ToElement()) { + TiXmlElement* elem = tagHandle.ToElement(); + + // Do stuff with the element here + for (TiXmlAttribute* a = elem->FirstAttribute(); a; a = a->Next()) + outNames.push_back( string(a->Name()) ); + } + return !outNames.empty(); +} + +//--------------------------------------------------------- +int xmlIO::getAttribute(const string& tag, const string& attribute, int defaultValue, int which){ + int value = defaultValue; + readIntAttribute(tag, attribute, value, which); + return value; +} + +//--------------------------------------------------------- +double xmlIO::getAttribute(const string& tag, const string& attribute, double defaultValue, int which){ + double value = defaultValue; + readDoubleAttribute(tag, attribute, value, which); + return value; +} + +//--------------------------------------------------------- +string xmlIO::getAttribute(const string& tag, const string& attribute, const string& defaultValue, int which){ + string value = defaultValue; + readStringAttribute(tag, attribute, value, which); + return value; +} + +//--------------------------------------------------------- +int xmlIO::setAttribute(const string& tag, const string& attribute, int value, int which){ + char valueStr[255]; + sprintf(valueStr, "%i", value); + int tagID = writeAttribute(tag, attribute, valueStr, which) -1; + return tagID; +} + +//--------------------------------------------------------- +int xmlIO::setAttribute(const string& tag, const string& attribute, double value, int which){ + char valueStr[255]; + sprintf(valueStr, "%lf", value); + int tagID = writeAttribute(tag, attribute, valueStr, which) -1; + return tagID; +} + +//--------------------------------------------------------- +int xmlIO::setAttribute(const string& tag, const string& attribute, const string& value, int which){ + int tagID = writeAttribute(tag, attribute, value, which) -1; + return tagID; +} + +//--------------------------------------------------------- +TiXmlElement* xmlIO::getElementForAttribute(const string& tag, int which){ + vector tokens = tokenize(tag,":"); + TiXmlHandle tagHandle = storedHandle; + for (int x = 0; x < (int)tokens.size(); x++) { + if (x == 0) + tagHandle = tagHandle.ChildElement(tokens.at(x), which); + else + tagHandle = tagHandle.FirstChildElement(tokens.at(x)); + } + return tagHandle.ToElement(); +} + +//--------------------------------------------------------- +bool xmlIO::readIntAttribute(const string& tag, const string& attribute, int& outValue, int which){ + + TiXmlElement* elem = getElementForAttribute(tag, which); + if (elem) + return (elem->QueryIntAttribute(attribute, &outValue) == TIXML_SUCCESS); + return false; +} + +//--------------------------------------------------------- +bool xmlIO::readDoubleAttribute(const string& tag, const string& attribute, double& outValue, int which){ + + TiXmlElement* elem = getElementForAttribute(tag, which); + if (elem) + return (elem->QueryDoubleAttribute(attribute, &outValue) == TIXML_SUCCESS); + return false; +} + +//--------------------------------------------------------- +bool xmlIO::readStringAttribute(const string& tag, const string& attribute, string& outValue, int which){ + + TiXmlElement* elem = getElementForAttribute(tag, which); + if (elem) + { + const string* value = elem->Attribute(attribute); + if (value) + { + outValue = *value; + return true; + } + } + return false; +} + +//--------------------------------------------------------- +int xmlIO::writeAttribute(const string& tag, const string& attribute, const string& valueString, int which){ + vector tokens = tokenize(tag,":"); + TiXmlHandle tagHandle = storedHandle; + for (int x = 0; x < (int)tokens.size(); x++) { + if (x == 0) + tagHandle = tagHandle.ChildElement(tokens.at(x), which); + else + tagHandle = tagHandle.FirstChildElement(tokens.at(x)); + } + + int ret = 0; + if (tagHandle.ToElement()) { + TiXmlElement* elem = tagHandle.ToElement(); + elem->SetAttribute(attribute, valueString); + + // Do we really need this? We could just ignore this and remove the 'addAttribute' functions... + // Now, just get the ID. + int numSameTags; + TiXmlElement* child = ( storedHandle.FirstChildElement( tokens.at(0) ) ).ToElement(); + for (numSameTags = 0; child; child = child->NextSiblingElement( tokens.at(0) ), ++numSameTags) { + // nothing + } + ret = numSameTags; + } + return ret; +} + +//--------------------------------------------------------- +bool xmlIO::loadFromBuffer( string buffer ) +{ + + int size = buffer.size(); + + bool loadOkay = doc.ReadFromMemory( buffer.c_str(), size);//, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING); + + return loadOkay; + +} +//--------------------------------------------------------- +void xmlIO::copyXmlToString(string & str) +{ + TiXmlPrinter printer; + doc.Accept(&printer); + + str = printer.CStr(); +} + -- cgit v1.2.3