I'm writing a simple xHTML parser which parses a data without nested tags.
Example input code will look like:
<h2>Header</h2>
<p> atsatat </p>
<h2>asdsaad</2><p>s32532235</p>
I've wrote the following code:
#include <node.h>
#include <vector>
#include <string>
#include <sstream>
#include <iostream>
using namespace v8;
enum Tags {
Closing = 0,
Paragraph,
Heading
};
int tagDetect(char *ptr){
if (*ptr == '/') {
return Tags::Closing;
}
if (*ptr == 'p') {
return Tags::Paragraph;
}
if (*(ptr + 1) == '2' || *(ptr + 1) == '3')
return Tags::Heading;
return -1;
}
Handle<Value> Callback(const Arguments& args) {
HandleScope scope;
if (!args[0]->IsString() || !args[1]->IsFunction()) {
return ThrowException(Exception::TypeError(
String::New("Invalid arguments! First parameter must be [string], second must be a callback [function].")));
}
Local<Function> callback = Local<Function>::Cast(args[1]);
String::Utf8Value param1(args[0]->ToString());
std::string input = std::string(*param1);
static Persistent<String> data_symbol = NODE_PSYMBOL("data");
static Persistent<String> tag_symbol = NODE_PSYMBOL("tag");
std::string::size_type pos = 0, closePos = 0;
int openPos;
int tagID, lastTag, id = 0, lastAppended = 0, clearStartPos;
Local<Array> nodes = Array::New();
Local<Object> node_obj;
while ((pos = input.find('<', pos)) != std::string::npos) {
pos++;
switch (tagID = tagDetect(&input[pos])) {
case Tags::Closing:
tagID = tagDetect(&input[pos + 1]);
if (tagID == lastTag && (pos - openPos > 10 || lastTag != Tags::Paragraph)) {
/* Concat tags */
if (lastAppended == lastTag) {
if (lastTag == Tags::Heading) { /* Dont concat heading tags */
continue;
}
node_obj = nodes->Get(id - 1)->ToObject();
node_obj->Set(data_symbol, String::Concat(node_obj->Get(data_symbol)->ToString(), String::New(input.substr(openPos + (lastTag > 1 ? 3 : 2), pos - openPos - (lastTag > 1 ? 3 : 2) - 1).c_str())));
continue;
}
node_obj = Object::New();
node_obj->Set(data_symbol, String::New(input.substr(openPos + (lastTag > 1 ? 3 : 2), pos - openPos - (lastTag > 1 ? 3 : 2) - 1).c_str()));
node_obj->Set(tag_symbol, Integer::New(lastTag));
nodes->Set(id, node_obj);
id++;
lastAppended = lastTag;
continue;
}
/* Clear useless tags */
input.erase(pos - 1, input.find('>', pos - 1) - pos + 2);
break;
case Tags::Paragraph:
case Tags::Heading:
openPos = pos;
lastTag = tagID;
break;
default:
/* Clear useless tags */
input.erase(pos - 1, input.find('>', pos - 1) - pos + 2);
break;
}
}
/* Remove last element from array if its heading */
if (lastTag == Tags::Heading) {
nodes->Delete(id - 1);
}
const unsigned argc = 2;
Local<Value> argv[argc] = {
Local<Value>::New(Null()),
nodes
};
callback->Call(Context::GetCurrent()->Global(), argc, argv);
return Undefined();
}
void RegisterModule(Handle<Object> target) {
target->Set(String::NewSymbol("parse"),
FunctionTemplate::New(Callback)->GetFunction());
}
NODE_MODULE(smartparser, RegisterModule);
I'm using this as Native NodeJS module. Since I'm really new in the C++ world, any tips on how to optimize/improve my code will be greatly appreciated.