Skip to content

Commit 83a9cc6

Browse files
committed
imp: readding xpathSelect function
1 parent 456bbc1 commit 83a9cc6

File tree

3 files changed

+80
-30
lines changed

3 files changed

+80
-30
lines changed

libxml.cpp

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ Napi::Object Libxml::Init(Napi::Env env, Napi::Object exports)
1616
InstanceMethod("loadXmlFromString", &Libxml::loadXmlFromString),
1717
InstanceMethod("loadDtds", &Libxml::loadDtds),
1818
InstanceMethod("validateAgainstDtds", &Libxml::validateAgainstDtds),
19+
InstanceMethod("xpathSelect", &Libxml::xpathSelect),
1920
InstanceMethod("getDtd", &Libxml::getDtd),
2021
InstanceMethod("freeXml", &Libxml::freeXml),
2122
InstanceMethod("freeDtds", &Libxml::freeDtds)
@@ -233,6 +234,54 @@ Napi::Value Libxml::validateAgainstDtds(const Napi::CallbackInfo& info) {
233234
}
234235
}
235236

237+
Napi::Value Libxml::xpathSelect(const Napi::CallbackInfo& info) {
238+
Napi::Env env = info.Env();
239+
if (info.Length() < 1){
240+
Napi::TypeError::New(env, "xpathSelect requires at least 1 argument").ThrowAsJavaScriptException();
241+
return env.Undefined();
242+
}
243+
Napi::EscapableHandleScope scope(env);
244+
Napi::Value res;
245+
Napi::String val = info[0].ToString();
246+
//Need to keep string in memory and get its const char* casted version for libxml2
247+
std::string xpathStr = val.Utf8Value();
248+
const char* xpathToGet(xpathStr.c_str());
249+
xmlChar * xpathExpr = xmlCharStrdup(xpathToGet);
250+
xmlXPathContextPtr xpathCtx;
251+
xmlXPathObjectPtr xpathObj;
252+
/* Create xpath evaluation context */
253+
xpathCtx = xmlXPathNewContext(this->docPtr);
254+
if(xpathCtx == nullptr) {
255+
Napi::Error::New(env, "Error: unable to create new XPath context").ThrowAsJavaScriptException();
256+
return env.Undefined();
257+
}
258+
/* Evaluate xpath expression */
259+
xpathObj = xmlXPathEvalExpression(xpathExpr, xpathCtx);
260+
if(xpathObj == nullptr) {
261+
xmlXPathFreeContext(xpathCtx);
262+
return Napi::Boolean::New(env, false);
263+
}
264+
else if(xpathObj) {
265+
switch (xpathObj->type) {
266+
case XPATH_BOOLEAN:
267+
res = Napi::Boolean::New(env, xpathObj->boolval);
268+
break;
269+
case XPATH_NUMBER:
270+
res = Napi::Number::New(env, xpathObj->floatval);
271+
break;
272+
case XPATH_STRING:
273+
res = Napi::String::New(env, (const char *)xpathObj->stringval);
274+
break;
275+
default:
276+
res = env.Null();
277+
break;
278+
}
279+
}
280+
xmlXPathFreeObject(xpathObj);
281+
xmlXPathFreeContext(xpathCtx);
282+
return scope.Escape(res);
283+
}
284+
236285
Napi::Value Libxml::getDtd(const Napi::CallbackInfo& info) {
237286
Napi::Env env = info.Env();
238287
Napi::HandleScope scope(env);

libxml.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ class Libxml : public Napi::ObjectWrap<Libxml>
4545
// static Napi::Value loadSchemas(const Napi::CallbackInfo& info);
4646
Napi::Value validateAgainstDtds(const Napi::CallbackInfo& info);
4747
// static Napi::Value validateAgainstSchemas(const Napi::CallbackInfo& info);
48-
// static Napi::Value xpathSelect(const Napi::CallbackInfo& info);
48+
Napi::Value xpathSelect(const Napi::CallbackInfo& info);
4949
Napi::Value getDtd(const Napi::CallbackInfo& info);
5050
void freeXml(const Napi::CallbackInfo& info);
5151
Napi::Value freeDtds(const Napi::CallbackInfo& info);

test/libxml-test.js

Lines changed: 30 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -111,36 +111,37 @@ describe('Node-Libxml', function () {
111111
expect(currentDtd).to.have.property('systemId', 'mydoctype.dtd');
112112
libxml.freeXml();
113113
});
114-
// it('Shoud return correct xpath values', function () {
115-
// let libxml = new Libxml(),
116-
// xmlfile = libxml.loadXml('test/data/test-default.xml'),
117-
// info = libxml.xpathSelect('string(//infos)'),
118-
// infodust = libxml.xpathSelect('number(//infosdust)'),
119-
// attrib = libxml.xpathSelect('string(//infos/@attrib)'),
120-
// infoExist = libxml.xpathSelect('boolean(//infos)'),
121-
// info23NotExist = libxml.xpathSelect('boolean(//infos23)'),
122-
// xpathToMyExist = libxml.xpathSelect('boolean(/xpath/to/my)'),
123-
// nbElementsInMy = libxml.xpathSelect('count(//my//*)'),
124-
// nbElementsInXpath = libxml.xpathSelect('count(/xpath//*)');
114+
it('Should return correct xpath values', function () {
115+
let libxml = new Libxml();
116+
let xmlfile = libxml.loadXml('test/data/test-default.xml');
117+
expect(xmlfile).to.be.true;
118+
let info = libxml.xpathSelect('string(//infos)'),
119+
infodust = libxml.xpathSelect('number(//infosdust)'),
120+
attrib = libxml.xpathSelect('string(//infos/@attrib)'),
121+
infoExist = libxml.xpathSelect('boolean(//infos)'),
122+
info23NotExist = libxml.xpathSelect('boolean(//infos23)'),
123+
xpathToMyExist = libxml.xpathSelect('boolean(/xpath/to/my)'),
124+
nbElementsInMy = libxml.xpathSelect('count(//my//*)'),
125+
nbElementsInXpath = libxml.xpathSelect('count(/xpath//*)');
125126

126-
// expect(info).to.be.a.string;
127-
// expect(info).to.have.string('trezaq');
128-
// expect(infodust).to.be.a('number');
129-
// expect(infodust).to.equal(23);
130-
// expect(attrib).to.be.a.string;
131-
// expect(attrib).to.have.string('example');
132-
// expect(infoExist).to.be.a('boolean');
133-
// expect(infoExist).to.be.true;
134-
// expect(info23NotExist).to.be.a('boolean');
135-
// expect(info23NotExist).to.be.false;
136-
// expect(xpathToMyExist).to.be.a('boolean');
137-
// expect(xpathToMyExist).to.be.true;
138-
// expect(nbElementsInMy).to.be.a('number');
139-
// expect(nbElementsInMy).to.equal(2);
140-
// expect(nbElementsInXpath).to.be.a('number');
141-
// expect(nbElementsInXpath).to.equal(4);
142-
// libxml.freeXml();
143-
// });
127+
expect(info).to.be.a.string;
128+
expect(info).to.have.string('trezaq');
129+
expect(infodust).to.be.a('number');
130+
expect(infodust).to.equal(23);
131+
expect(attrib).to.be.a.string;
132+
expect(attrib).to.have.string('example');
133+
expect(infoExist).to.be.a('boolean');
134+
expect(infoExist).to.be.true;
135+
expect(info23NotExist).to.be.a('boolean');
136+
expect(info23NotExist).to.be.false;
137+
expect(xpathToMyExist).to.be.a('boolean');
138+
expect(xpathToMyExist).to.be.true;
139+
expect(nbElementsInMy).to.be.a('number');
140+
expect(nbElementsInMy).to.equal(2);
141+
expect(nbElementsInXpath).to.be.a('number');
142+
expect(nbElementsInXpath).to.equal(4);
143+
libxml.freeXml();
144+
});
144145
// // // ABOVE IS ALL THE SAME WITH MEMORY MANUAL MANADGEMENT
145146
it('should free XML memory & infos when asked in manual mod On not wellformed xml', function () {
146147
let libxml = new Libxml(true);

0 commit comments

Comments
 (0)