Permalink
Browse files

Support XPath expressions that don't yield nodesets

When an XPath expression evaluates to a boolean, number or string
it gets turned into the corresponding JS value.
  • Loading branch information...
David Wragg
David Wragg committed Jul 5, 2012
1 parent 6376863 commit 3ec67904359ddee7943d1adebb7f46d0eaa0e9a7
Showing with 50 additions and 19 deletions.
  1. +1 −1 lib/document.js
  2. +6 −1 lib/element.js
  3. +31 −16 src/xml_xpath_context.cc
  4. +1 −1 src/xml_xpath_context.h
  5. +11 −0 test/searching.js
View
@@ -37,7 +37,7 @@ Document.prototype.find = function(xpath, ns_uri) {
/// xpath search
/// @return first element matching
Document.prototype.get = function(xpath, ns_uri) {
- return this.find(xpath, ns_uri)[0];
+ return this.root().get(xpath, ns_uri);
};
/// @return a given child
View
@@ -64,7 +64,12 @@ Element.prototype.cdata = function(content) {
};
Element.prototype.get = function() {
- return this.find.apply(this, arguments)[0];
+ var res = this.find.apply(this, arguments);
+ if (res instanceof Array) {
+ return res[0];
+ } else {
+ return res;
+ }
};
Element.prototype.defineNamespace = function(prefix, href) {
View
@@ -23,30 +23,45 @@ XmlXpathContext::register_ns(const xmlChar* prefix,
xmlXPathRegisterNs(ctxt, prefix, uri);
}
-v8::Handle<v8::Array>
+v8::Handle<v8::Value>
XmlXpathContext::evaluate(const xmlChar* xpath) {
v8::HandleScope scope;
- xmlXPathObject* result = xmlXPathEval(xpath, ctxt);
+ xmlXPathObject* xpathobj = xmlXPathEval(xpath, ctxt);
+ v8::Handle<v8::Value> res;
- if (!result) {
- return scope.Close(v8::Array::New(0));
- }
+ if (xpathobj) {
+ switch (xpathobj->type) {
+ case XPATH_NODESET: {
+ v8::Handle<v8::Array> nodes = v8::Array::New(xpathobj->nodesetval->nodeNr);
+ for (int i = 0; i != xpathobj->nodesetval->nodeNr; ++i) {
+ nodes->Set(i, XmlNode::New(xpathobj->nodesetval->nodeTab[i]));
+ }
- if (result->type != XPATH_NODESET || !result->nodesetval) {
- xmlXPathFreeObject(result);
+ res = nodes;
+ break;
+ }
- return scope.Close(v8::Array::New(0));
- }
+ case XPATH_BOOLEAN:
+ res = v8::Boolean::New(xpathobj->boolval);
+ break;
- v8::Handle<v8::Array> nodes = v8::Array::New(result->nodesetval->nodeNr);
- for (int i = 0; i != result->nodesetval->nodeNr; ++i) {
- xmlNode* node = result->nodesetval->nodeTab[i];
- nodes->Set(i, XmlNode::New(node));
- }
+ case XPATH_NUMBER:
+ res = v8::Number::New(xpathobj->floatval);
+ break;
- xmlXPathFreeObject(result);
+ case XPATH_STRING:
+ res = v8::String::New((const char *)xpathobj->stringval,
+ xmlStrlen(xpathobj->stringval));
+ break;
+
+ default:
+ res = v8::Null();
+ break;
+ }
+ }
- return scope.Close(nodes);
+ xmlXPathFreeObject(xpathobj);
+ return scope.Close(res);
}
} // namespace libxmljs
View
@@ -15,7 +15,7 @@ class XmlXpathContext {
~XmlXpathContext();
void register_ns(const xmlChar* prefix, const xmlChar* uri);
- v8::Handle<v8::Array> evaluate(const xmlChar* xpath);
+ v8::Handle<v8::Value> evaluate(const xmlChar* xpath);
xmlXPathContext *ctxt;
};
View
@@ -38,6 +38,17 @@ module.exports.get_attr = function(assert) {
assert.done();
};
+module.exports.get_non_nodeset = function(assert) {
+ var doc = libxml.Document();
+ var root = doc.node('root');
+
+ assert.equal(true, doc.get('true()'));
+ assert.equal(false, doc.get('false()'));
+ assert.equal('Hello, world!', doc.get('"Hello, world!"'));
+ assert.equal(1.23, doc.get('1.23'));
+ assert.done();
+};
+
module.exports.find = function(assert) {
var children = [];
var doc = libxml.Document();

0 comments on commit 3ec6790

Please sign in to comment.