| 1 | #include <libxml++/libxml++.h> |
| 2 | #include <cassert> |
| 3 | #include <iostream> |
| 4 | |
| 5 | void print_indentation(unsigned int indentation) |
| 6 | { |
| 7 | for(unsigned int i = 0; i < indentation; ++i) |
| 8 | std::cout << " "; |
| 9 | } |
| 10 | |
| 11 | |
| 12 | |
| 13 | //! get child element by id |
| 14 | /*! |
| 15 | \return pointer to element having id or null on error |
| 16 | \todo find libxmlpp pendant |
| 17 | */ |
| 18 | const xmlpp::Element* get_element_by_id(const xmlpp::Element* element, const std::string &id) |
| 19 | { |
| 20 | const xmlpp::Attribute* cid = element->get_attribute("id"); |
| 21 | if ( cid && ( cid->get_value() == id)) return element; |
| 22 | |
| 23 | //Recurse through child nodes: |
| 24 | xmlpp::Node::NodeList list = element->get_children(); |
| 25 | for(xmlpp::Node::NodeList::iterator iter = list.begin(); iter != list.end(); ++iter) |
| 26 | { |
| 27 | const xmlpp::Element* element = dynamic_cast<const xmlpp::Element*>(*iter); |
| 28 | if (element) { |
| 29 | const xmlpp::Element* match = get_element_by_id(element, id); |
| 30 | if (match) return match; |
| 31 | } |
| 32 | } |
| 33 | return NULL; |
| 34 | } |
| 35 | |
| 36 | //! get namespace by id |
| 37 | /*! |
| 38 | \return namespace name or empty string on error |
| 39 | */ |
| 40 | std::string get_namespace(const xmlpp::Element* root, const std::string &id) |
| 41 | { |
| 42 | std::string error; |
| 43 | const xmlpp::Element* element(get_element_by_id(root, id)); |
| 44 | if ((!element)||(!element->get_attribute("name"))) return error; |
| 45 | return element->get_attribute("name")->get_value(); |
| 46 | } |
| 47 | |
| 48 | //! get type by id |
| 49 | /*! |
| 50 | \return type name or empty string on error |
| 51 | */ |
| 52 | std::string get_type(const xmlpp::Element* root, const std::string &id) |
| 53 | { |
| 54 | std::string error; |
| 55 | const xmlpp::Element* element(get_element_by_id(root, id)); |
| 56 | if (!element) return error; |
| 57 | |
| 58 | // TODO: not yet complete |
| 59 | // if we recurse - when do we stop? |
| 60 | // if it is a typedef? yes? (hmm if the typedef is in the file parsed this will not work) |
| 61 | std::string tag(element->get_name()); |
| 62 | if (tag=="ReferenceType") { |
| 63 | assert(element->get_attribute("type")); |
| 64 | std::string ret(get_type(root, element->get_attribute("type")->get_value())); |
| 65 | if (ret==error) return error; |
| 66 | return ret+"&"; |
| 67 | }else if (tag=="CvQualifiedType") { |
| 68 | assert(element->get_attribute("type")); |
| 69 | std::string ret(get_type(root, element->get_attribute("type")->get_value())); |
| 70 | if (ret==error) return error; |
| 71 | return std::string("const ")+ret; |
| 72 | } |
| 73 | |
| 74 | assert(element->get_attribute("name")); |
| 75 | assert(element->get_attribute("context")); |
| 76 | return get_namespace(root, element->get_attribute("context")->get_value())+"::"+element->get_attribute("name")->get_value(); |
| 77 | } |
| 78 | |
| 79 | void parse_function(const xmlpp::Element* root, const xmlpp::Node* node, unsigned int indentation = 0) { |
| 80 | const xmlpp::Element* element = dynamic_cast<const xmlpp::Element*>(node); |
| 81 | if (!element) return; |
| 82 | |
| 83 | const xmlpp::Attribute* attributes = element->get_attribute("attributes"); |
| 84 | const xmlpp::Attribute* name = element->get_attribute("name"); |
| 85 | const xmlpp::Attribute* returns = element->get_attribute("returns"); |
| 86 | if ((!attributes)||(!name)||(!returns)) return; |
| 87 | |
| 88 | // check wether the function is marked (TODO: improve) |
| 89 | if (attributes->get_value().find("gccxml(libt2n")==std::string::npos) return; |
| 90 | |
| 91 | // TODO: extract command group |
| 92 | // something like: sed 's,gccxml(libt2n-\([a-z]*}),\1,' |
| 93 | |
| 94 | // we need the return type |
| 95 | std::string ret_type(get_type(root, returns->get_value())); |
| 96 | |
| 97 | // and the argument types |
| 98 | typedef std::map<std::string, std::string> Args; |
| 99 | Args args; |
| 100 | |
| 101 | xmlpp::Node::NodeList list = node->get_children("Argument"); |
| 102 | for(xmlpp::Node::NodeList::iterator iter = list.begin(); iter != list.end(); ++iter) |
| 103 | { |
| 104 | const xmlpp::Element* arg = dynamic_cast<const xmlpp::Element*>(*iter); |
| 105 | if ( arg ) { |
| 106 | assert(arg->get_name() == "Argument"); |
| 107 | assert(arg->get_attribute("name")); |
| 108 | assert(arg->get_attribute("type")); |
| 109 | assert(args.find(arg->get_attribute("name")->get_value())==args.end()); |
| 110 | args[arg->get_attribute("name")->get_value()]=get_type(root, arg->get_attribute("type")->get_value()); |
| 111 | } |
| 112 | } |
| 113 | |
| 114 | std::cerr << "Found marked Function: " << ret_type << " " << name->get_value() << "("; |
| 115 | for (Args::const_iterator it=args.begin();it!=args.end();++it) { |
| 116 | if (it!=args.begin()) std::cerr << ", "; |
| 117 | std::cerr << it->second << " " << it->first; |
| 118 | } |
| 119 | std::cerr << ");" << std::endl; |
| 120 | } |
| 121 | |
| 122 | void print_node(const xmlpp::Element* root, const xmlpp::Node* node = NULL, unsigned int indentation = 0) |
| 123 | { |
| 124 | if (!node) node=root; |
| 125 | std::cout << std::endl; //Separate nodes by an empty line. |
| 126 | |
| 127 | const xmlpp::ContentNode* nodeContent = dynamic_cast<const xmlpp::ContentNode*>(node); |
| 128 | const xmlpp::TextNode* nodeText = dynamic_cast<const xmlpp::TextNode*>(node); |
| 129 | const xmlpp::CommentNode* nodeComment = dynamic_cast<const xmlpp::CommentNode*>(node); |
| 130 | |
| 131 | if(nodeText && nodeText->is_white_space()) //Let's ignore the indenting - you don't always want to do this. |
| 132 | return; |
| 133 | |
| 134 | std::string nodename = node->get_name(); |
| 135 | |
| 136 | if(!nodeText && !nodeComment && !nodename.empty()) //Let's not say "name: text". |
| 137 | { |
| 138 | print_indentation(indentation); |
| 139 | // std::cout << "Node name = " << node->get_name() << std::endl; |
| 140 | // std::cout << "Node name = " << nodename << std::endl; |
| 141 | if (node->get_name() == "Function") { |
| 142 | parse_function(root, node, indentation); |
| 143 | } |
| 144 | } |
| 145 | else if(nodeText) //Let's say when it's text. - e.g. let's say what that white space is. |
| 146 | { |
| 147 | print_indentation(indentation); |
| 148 | std::cout << "Text Node" << std::endl; |
| 149 | } |
| 150 | |
| 151 | //Treat the various node types differently: |
| 152 | if(nodeText) |
| 153 | { |
| 154 | print_indentation(indentation); |
| 155 | std::cout << "text = \"" << nodeText->get_content() << "\"" << std::endl; |
| 156 | } |
| 157 | else if(nodeComment) |
| 158 | { |
| 159 | print_indentation(indentation); |
| 160 | std::cout << "comment = " << nodeComment->get_content() << std::endl; |
| 161 | } |
| 162 | else if(nodeContent) |
| 163 | { |
| 164 | print_indentation(indentation); |
| 165 | std::cout << "content = " << nodeContent->get_content() << std::endl; |
| 166 | } |
| 167 | else if(const xmlpp::Element* nodeElement = dynamic_cast<const xmlpp::Element*>(node)) |
| 168 | { |
| 169 | //A normal Element node: |
| 170 | |
| 171 | //line() works only for ElementNodes. |
| 172 | print_indentation(indentation); |
| 173 | std::cout << " line = " << node->get_line() << std::endl; |
| 174 | |
| 175 | //Print attributes: |
| 176 | const xmlpp::Element::AttributeList& attributes = nodeElement->get_attributes(); |
| 177 | for(xmlpp::Element::AttributeList::const_iterator iter = attributes.begin(); iter != attributes.end(); ++iter) |
| 178 | { |
| 179 | const xmlpp::Attribute* attribute = *iter; |
| 180 | print_indentation(indentation); |
| 181 | std::cout << " Attribute " << attribute->get_name() << " = " << attribute->get_value() << std::endl; |
| 182 | } |
| 183 | |
| 184 | const xmlpp::Attribute* attribute = nodeElement->get_attribute("title"); |
| 185 | if(attribute) |
| 186 | { |
| 187 | std::cout << "title found: =" << attribute->get_value() << std::endl; |
| 188 | |
| 189 | } |
| 190 | } |
| 191 | |
| 192 | if(!nodeContent) |
| 193 | { |
| 194 | //Recurse through child nodes: |
| 195 | xmlpp::Node::NodeList list = node->get_children(); |
| 196 | for(xmlpp::Node::NodeList::iterator iter = list.begin(); iter != list.end(); ++iter) |
| 197 | { |
| 198 | print_node(root, *iter, indentation + 2); //recursive |
| 199 | } |
| 200 | } |
| 201 | } |
| 202 | |
| 203 | int main(int argc, char* argv[]) |
| 204 | { |
| 205 | std::string filepath; |
| 206 | if(argc > 1 ) |
| 207 | filepath = argv[1]; //Allow the user to specify a different XML file to parse. |
| 208 | else |
| 209 | filepath = "example.xml"; |
| 210 | |
| 211 | try |
| 212 | { |
| 213 | xmlpp::DomParser parser; |
| 214 | // parser.set_validate(); |
| 215 | parser.set_substitute_entities(); //We just want the text to be resolved/unescaped automatically. |
| 216 | parser.parse_file(filepath); |
| 217 | if(parser) |
| 218 | { |
| 219 | //Walk the tree: |
| 220 | const xmlpp::Node* pNode = parser.get_document()->get_root_node(); //deleted by DomParser. |
| 221 | const xmlpp::Element* root = dynamic_cast<const xmlpp::Element*>(pNode); |
| 222 | assert(root); |
| 223 | print_node(root); |
| 224 | } |
| 225 | } |
| 226 | catch(const std::exception& ex) |
| 227 | { |
| 228 | std::cout << "Exception caught: " << ex.what() << std::endl; |
| 229 | } |
| 230 | |
| 231 | return 0; |
| 232 | } |