Skip to content

Commit

Permalink
Support XPath expressions that yield attributes
Browse files Browse the repository at this point in the history
XPath expressions like '@attr' evaluate to a nodeset containing
attributes.  This would sometimes work in libxmljs (when the libxml
xmlNode for an attribute already had a _private pointing to a libxmljs
attribute wrapper).  But in other cases you could end up with a libxmljs
element wrapper wrapping a libxmljs xmlAttr.  This makes it work in
general.
  • Loading branch information
David Wragg committed Jul 5, 2012
1 parent 7bddc0d commit 6376863
Show file tree
Hide file tree
Showing 6 changed files with 50 additions and 5 deletions.
2 changes: 2 additions & 0 deletions src/xml_attribute.cc
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ XmlAttribute::New(xmlNode* xml_obj, const xmlChar* name, const xmlChar* value)
v8::Handle<v8::Object> v8::Handle<v8::Object>
XmlAttribute::New(xmlAttr* attr) XmlAttribute::New(xmlAttr* attr)
{ {
assert(attr->type == XML_ATTRIBUTE_NODE);

if (attr->_private) { if (attr->_private) {
return static_cast<XmlNode*>(attr->_private)->handle_; return static_cast<XmlNode*>(attr->_private)->handle_;
} }
Expand Down
2 changes: 1 addition & 1 deletion src/xml_element.cc
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -370,7 +370,7 @@ XmlElement::get_child_nodes() {


uint32_t i = 0; uint32_t i = 0;
do { do {
children->Set(i, XmlElement::New(child)); children->Set(i, XmlNode::New(child));
} while ((child = child->next) && ++i < len); } while ((child = child->next) && ++i < len);


return scope.Close(children); return scope.Close(children);
Expand Down
22 changes: 19 additions & 3 deletions src/xml_node.cc
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -163,6 +163,22 @@ XmlNode::Clone(const v8::Arguments& args) {
return scope.Close(node->clone(recurse)); return scope.Close(node->clone(recurse));
} }


v8::Handle<v8::Value>
XmlNode::New(xmlNode* node)
{
switch (node->type) {
case XML_ATTRIBUTE_NODE:
return XmlAttribute::New(reinterpret_cast<xmlAttr *>(node));

default:
// if we don't know how to convert to specific libxmljs wrapper,
// wrap in an XmlElement. There should probably be specific
// wrapper types for text nodes etc., but this is what existing
// code expects.
return XmlElement::New(node);
}
}

XmlNode::XmlNode(xmlNode* node) : xml_obj(node) { XmlNode::XmlNode(xmlNode* node) : xml_obj(node) {
xml_obj->_private = this; xml_obj->_private = this;


Expand Down Expand Up @@ -259,7 +275,7 @@ v8::Handle<v8::Value>
XmlNode::get_prev_sibling() { XmlNode::get_prev_sibling() {
v8::HandleScope scope; v8::HandleScope scope;
if (xml_obj->prev) { if (xml_obj->prev) {
return scope.Close(XmlElement::New(xml_obj->prev)); return scope.Close(XmlNode::New(xml_obj->prev));
} }


return v8::Null(); return v8::Null();
Expand All @@ -269,7 +285,7 @@ v8::Handle<v8::Value>
XmlNode::get_next_sibling() { XmlNode::get_next_sibling() {
v8::HandleScope scope; v8::HandleScope scope;
if (xml_obj->next) { if (xml_obj->next) {
return scope.Close(XmlElement::New(xml_obj->next)); return scope.Close(XmlNode::New(xml_obj->next));
} }


return v8::Null(); return v8::Null();
Expand All @@ -279,7 +295,7 @@ v8::Handle<v8::Value>
XmlNode::clone(bool recurse) { XmlNode::clone(bool recurse) {
v8::HandleScope scope; v8::HandleScope scope;


return scope.Close(XmlElement::New(xmlCopyNode(xml_obj, recurse))); return scope.Close(XmlNode::New(xmlCopyNode(xml_obj, recurse)));
} }


v8::Handle<v8::Value> v8::Handle<v8::Value>
Expand Down
3 changes: 3 additions & 0 deletions src/xml_node.h
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ class XmlNode : public node::ObjectWrap {
static void Initialize(v8::Handle<v8::Object> target); static void Initialize(v8::Handle<v8::Object> target);
static v8::Persistent<v8::FunctionTemplate> constructor_template; static v8::Persistent<v8::FunctionTemplate> constructor_template;


// create new XmlElement, XmlAttribute, etc. to wrap a libxml xmlNode
static v8::Handle<v8::Value> New(xmlNode* node);

protected: protected:


static v8::Handle<v8::Value> Doc(const v8::Arguments& args); static v8::Handle<v8::Value> Doc(const v8::Arguments& args);
Expand Down
2 changes: 1 addition & 1 deletion src/xml_xpath_context.cc
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ XmlXpathContext::evaluate(const xmlChar* xpath) {
v8::Handle<v8::Array> nodes = v8::Array::New(result->nodesetval->nodeNr); v8::Handle<v8::Array> nodes = v8::Array::New(result->nodesetval->nodeNr);
for (int i = 0; i != result->nodesetval->nodeNr; ++i) { for (int i = 0; i != result->nodesetval->nodeNr; ++i) {
xmlNode* node = result->nodesetval->nodeTab[i]; xmlNode* node = result->nodesetval->nodeTab[i];
nodes->Set(i, XmlElement::New(node)); nodes->Set(i, XmlNode::New(node));
} }


xmlXPathFreeObject(result); xmlXPathFreeObject(result);
Expand Down
24 changes: 24 additions & 0 deletions test/searching.js
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -14,6 +14,30 @@ module.exports.get = function(assert) {
assert.done(); assert.done();
}; };


module.exports.get_attr = function(assert) {
var doc = libxml.Document();
var root = doc.node('root');
var child = root.node('child');
child.attr('attr', 'val');
var attr = child.attr('attr');

// on document
assert.equal(attr, doc.get('//@attr'));
assert.equal('val', doc.get('//@attr').value());

// nested
assert.equal(attr, doc.get('child').get('@attr'));
assert.equal('val', doc.get('child').get('@attr').value());

// check again after re-parsign the doc
doc = libxml.parseXmlString(doc.toString())
assert.equal('val', doc.get('//@attr').value());
assert.equal('val', doc.get('child').get('@attr').value());
assert.equal(doc.get('child'), doc.get('//@attr').node());

assert.done();
};

module.exports.find = function(assert) { module.exports.find = function(assert) {
var children = []; var children = [];
var doc = libxml.Document(); var doc = libxml.Document();
Expand Down

0 comments on commit 6376863

Please sign in to comment.