Skip to content
This repository was archived by the owner on Dec 12, 2024. It is now read-only.

Commit 5c2a1c7

Browse files
author
codyrigney92
committed
Initial Commit.
1 parent a351605 commit 5c2a1c7

9 files changed

+4012
-0
lines changed

binding.gyp

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"targets": [
3+
{
4+
"target_name": "fast-xml2js",
5+
"sources": [ "fast-xml2js.cpp", "rapidxml/rapidxml.hpp", "rapidxml/rapidxml_iterators.hpp", "rapidxml/rapidxml_print.hpp", "rapidxml/rapidxml_utils.hpp" ]
6+
},
7+
{
8+
"target_name": "action_after_build",
9+
"type": "none",
10+
"dependencies": [ "fast-xml2js" ],
11+
"copies": [
12+
{
13+
"files": [ "<(PRODUCT_DIR)/fast-xml2js.node" ],
14+
"destination": "fast-xml2js"
15+
}
16+
]
17+
}
18+
]
19+
}

fast-xml2js.cpp

+192
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
// fast-xml2js.cpp
2+
#include <node.h>
3+
#include "rapidxml/rapidxml_utils.hpp"
4+
#include <stack>
5+
#include <iostream>
6+
7+
namespace fastxml2js {
8+
9+
using v8::Function;
10+
using v8::Exception;
11+
using v8::FunctionCallbackInfo;
12+
using v8::Isolate;
13+
using v8::Local;
14+
using v8::Object;
15+
using v8::String;
16+
using v8::Number;
17+
using v8::Value;
18+
using v8::Array;
19+
20+
using namespace rapidxml;
21+
22+
void ParseString(const FunctionCallbackInfo<Value>& args) {
23+
Isolate* isolate = args.GetIsolate();
24+
25+
if(args.Length() != 2)
26+
{
27+
isolate->ThrowException(Exception::TypeError(
28+
String::NewFromUtf8(isolate, "Wrong number of arguments")));
29+
return;
30+
}
31+
32+
if(!args[0]->IsString())
33+
{
34+
isolate->ThrowException(Exception::TypeError(
35+
String::NewFromUtf8(isolate, "First argument must be a string")));
36+
return;
37+
}
38+
39+
if(!args[1]->IsFunction())
40+
{
41+
isolate->ThrowException(Exception::TypeError(
42+
String::NewFromUtf8(isolate, "Second argument must be a callback")));
43+
return;
44+
}
45+
46+
String::Utf8Value param1(args[0]->ToString());
47+
48+
char *xml = new char[param1.length() + 1];
49+
strcpy(xml, *param1);
50+
51+
xml_document<> doc;
52+
doc.parse<0>(xml);
53+
54+
Local<Object> obj = Object::New(isolate);
55+
56+
std::stack<xml_node<> *> nodeStack;
57+
std::stack<Local<Object> > objStack;
58+
59+
nodeStack.push(doc.first_node());
60+
objStack.push(obj);
61+
62+
Local<Value> errorString = Null(isolate);
63+
64+
try
65+
{
66+
67+
while(nodeStack.size() > 0)
68+
{
69+
xml_node<> *node = nodeStack.top();
70+
if(!node)
71+
{
72+
nodeStack.pop();
73+
objStack.pop();
74+
continue;
75+
}
76+
77+
Local<Object> obj = objStack.top();
78+
79+
Local<Object> newObj = Object::New(isolate);
80+
81+
bool hasChild = false;
82+
83+
//Need to reduce duplicate code here
84+
if(!node->first_node() || (node->first_node() && node->first_node()->type() != node_cdata && node->first_node()->type() != node_data))
85+
{
86+
hasChild = true;
87+
88+
Local<Array> lst;
89+
if(node != doc.first_node())
90+
{
91+
if(obj->HasOwnProperty(String::NewFromUtf8(isolate, node->name())))
92+
{
93+
lst = Local<Array>::Cast(obj->Get(String::NewFromUtf8(isolate, node->name())));
94+
lst->Set(String::NewFromUtf8(isolate, "length"), Number::New(isolate, lst->Length() + 1));
95+
}
96+
else
97+
{
98+
lst = Array::New(isolate, 1);
99+
obj->Set(String::NewFromUtf8(isolate, node->name()), lst);
100+
}
101+
102+
lst->Set(lst->Length()-1, newObj);
103+
}
104+
else
105+
{
106+
obj->Set(String::NewFromUtf8(isolate, node->name()), newObj);
107+
}
108+
}
109+
else
110+
{
111+
Local<Array> lst;
112+
if(node != doc.first_node())
113+
{
114+
if(obj->HasOwnProperty(String::NewFromUtf8(isolate, node->name())))
115+
{
116+
lst = Local<Array>::Cast(obj->Get(String::NewFromUtf8(isolate, node->name())));
117+
lst->Set(String::NewFromUtf8(isolate, "length"), Number::New(isolate, lst->Length() + 1));
118+
}
119+
else
120+
{
121+
lst = Array::New(isolate, 1);
122+
obj->Set(String::NewFromUtf8(isolate, node->name()), lst);
123+
}
124+
125+
lst->Set(lst->Length()-1, String::NewFromUtf8(isolate, node->first_node()->value()));
126+
}
127+
else
128+
{
129+
obj->Set(String::NewFromUtf8(isolate, node->name()), String::NewFromUtf8(isolate, node->first_node()->value()));
130+
}
131+
}
132+
133+
nodeStack.pop();
134+
nodeStack.push(node->next_sibling());
135+
136+
if(hasChild) {
137+
138+
if(node->first_attribute())
139+
{
140+
Local<Object> attrObj = Object::New(isolate);
141+
newObj->Set(String::NewFromUtf8(isolate, "$"), attrObj);
142+
143+
for(xml_attribute<> *attr = node->first_attribute(); attr; attr = attr->next_attribute())
144+
{
145+
attrObj->Set(String::NewFromUtf8(isolate, attr->name()), String::NewFromUtf8(isolate, attr->value()));
146+
}
147+
}
148+
149+
nodeStack.push(node->first_node());
150+
objStack.push(newObj);
151+
}
152+
153+
}
154+
155+
}
156+
catch (const std::runtime_error& e)
157+
{
158+
errorString = String::NewFromUtf8(isolate, e.what());
159+
}
160+
catch (const rapidxml::parse_error& e)
161+
{
162+
errorString = String::NewFromUtf8(isolate, e.what());
163+
}
164+
catch (const std::exception& e)
165+
{
166+
errorString = String::NewFromUtf8(isolate, e.what());
167+
}
168+
catch (const Local<Value>& e)
169+
{
170+
errorString = e;
171+
}
172+
catch (...)
173+
{
174+
errorString = String::NewFromUtf8(isolate, "An unknown error occurred while parsing.");
175+
}
176+
177+
delete[] xml;
178+
179+
Local<Function> cb = Local<Function>::Cast(args[1]);
180+
const unsigned argc = 2;
181+
Local<Value> argv[argc] = { errorString, obj };
182+
183+
cb->Call(Null(isolate), argc, argv);
184+
}
185+
186+
void init(Local<Object> exports) {
187+
NODE_SET_METHOD(exports, "parseString", ParseString);
188+
}
189+
190+
NODE_MODULE(fastxml2js, init)
191+
192+
} // namespace fastxml2js

package.json

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{
2+
"name": "fast-xml2js",
3+
"version": "1.0.1",
4+
"description": "In-place replacement for xml2js. This is about 20x faster and makes use of the rapidxml C++ library.",
5+
"main": "fast-xml2js/fast-xml2js.node",
6+
"scripts": {
7+
"preinstall": "node-gyp configure && node-gyp build"
8+
},
9+
"repository": {
10+
"type": "git",
11+
"url": "git+https://github.com/codyrigney92/fast-xml2js.git"
12+
},
13+
"keywords": [
14+
"xml2js",
15+
"C++"
16+
],
17+
"author": {
18+
"name": "Cody Rigney"
19+
},
20+
"license": "MIT",
21+
"gypfile": true,
22+
"bugs": {
23+
"url": "https://github.com/codyrigney92/fast-xml2js/issues"
24+
},
25+
"homepage": "https://github.com/codyrigney92/fast-xml2js#readme",
26+
"readme": "ERROR: No README data found!",
27+
28+
"_shasum": "7fc66b1400e1ad73b1d6bdbba006831595cf84cd",
29+
"_from": "fast-xml2js@*"
30+
}

rapidxml/license.txt

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
Use of this software is granted under one of the following two licenses,
2+
to be chosen freely by the user.
3+
4+
1. Boost Software License - Version 1.0 - August 17th, 2003
5+
===============================================================================
6+
7+
Copyright (c) 2006, 2007 Marcin Kalicinski
8+
9+
Permission is hereby granted, free of charge, to any person or organization
10+
obtaining a copy of the software and accompanying documentation covered by
11+
this license (the "Software") to use, reproduce, display, distribute,
12+
execute, and transmit the Software, and to prepare derivative works of the
13+
Software, and to permit third-parties to whom the Software is furnished to
14+
do so, all subject to the following:
15+
16+
The copyright notices in the Software and this entire statement, including
17+
the above license grant, this restriction and the following disclaimer,
18+
must be included in all copies of the Software, in whole or in part, and
19+
all derivative works of the Software, unless such copies or derivative
20+
works are solely in the form of machine-executable object code generated by
21+
a source language processor.
22+
23+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25+
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
26+
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
27+
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
28+
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29+
DEALINGS IN THE SOFTWARE.
30+
31+
2. The MIT License
32+
===============================================================================
33+
34+
Copyright (c) 2006, 2007 Marcin Kalicinski
35+
36+
Permission is hereby granted, free of charge, to any person obtaining a copy
37+
of this software and associated documentation files (the "Software"), to deal
38+
in the Software without restriction, including without limitation the rights
39+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
40+
of the Software, and to permit persons to whom the Software is furnished to do so,
41+
subject to the following conditions:
42+
43+
The above copyright notice and this permission notice shall be included in all
44+
copies or substantial portions of the Software.
45+
46+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
47+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
48+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
49+
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
50+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
51+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
52+
IN THE SOFTWARE.

0 commit comments

Comments
 (0)