Skip to content

Commit 33eb15b

Browse files
committed
Comments: Add initial support and tests
* This commit makes it possible to create XML commment nodes in nodejs. * A new XmlComment class is introduced which exports a method text() to get and set the comment content. * This patch also includes tests to assert comment creation and the getting and setting of comment content through the text() function.
1 parent fccac11 commit 33eb15b

7 files changed

Lines changed: 203 additions & 0 deletions

File tree

binding.gyp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
'src/xml_attribute.cc',
88
'src/xml_document.cc',
99
'src/xml_element.cc',
10+
'src/xml_comment.cc',
1011
'src/xml_namespace.cc',
1112
'src/xml_node.cc',
1213
'src/xml_sax_parser.cc',

index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ module.exports.libxml_debug_enabled = bindings.libxml_debug_enabled;
2121
// lib exports
2222
module.exports.Document = Document;
2323
module.exports.Element = require('./lib/element');
24+
module.exports.Comment = require('./lib/comment');
2425

2526
// Compatibility synonyms
2627
Document.fromXmlString = Document.fromXml;

lib/comment.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
var bindings = require('./bindings');
2+
3+
var Document = require('./document');
4+
5+
/// create a new comment on the given document
6+
/// @param doc the Document to create the comment for
7+
/// @param {String} [content] comment content
8+
/// @constructor
9+
var Comment = function(doc, content) {
10+
if (!doc) {
11+
throw new Error('document argument required');
12+
} else if (! (doc instanceof bindings.Document)) {
13+
throw new Error('document argument must be an ' +
14+
'instance of Document');
15+
}
16+
17+
var comm = new bindings.Comment(doc, content);
18+
return comm;
19+
};
20+
21+
Comment.prototype = bindings.Comment.prototype;
22+
23+
module.exports = Comment;
24+

src/xml_comment.cc

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
#include <node.h>
2+
3+
#include <cstring>
4+
5+
#include "libxmljs.h"
6+
7+
#include "xml_comment.h"
8+
#include "xml_document.h"
9+
#include "xml_attribute.h"
10+
#include "xml_xpath_context.h"
11+
12+
namespace libxmljs {
13+
14+
v8::Persistent<v8::FunctionTemplate> XmlComment::constructor_template;
15+
16+
// doc, content
17+
v8::Handle<v8::Value>
18+
XmlComment::New(const v8::Arguments& args) {
19+
v8::HandleScope scope;
20+
21+
// if we were created for an existing xml node, then we don't need
22+
// to create a new node on the document
23+
if (args.Length() == 0)
24+
{
25+
return scope.Close(args.Holder());
26+
}
27+
28+
XmlDocument* document = ObjectWrap::Unwrap<XmlDocument>(args[0]->ToObject());
29+
assert(document);
30+
31+
v8::Handle<v8::Value> contentOpt;
32+
if(args[1]->IsString()) {
33+
contentOpt = args[1];
34+
}
35+
v8::String::Utf8Value contentRaw(contentOpt);
36+
const char* content = (contentRaw.length()) ? *contentRaw : NULL;
37+
38+
xmlChar* encoded = content ? xmlEncodeSpecialChars(document->xml_obj, (const xmlChar*)content) : NULL;
39+
xmlNode* comm = xmlNewDocComment(document->xml_obj,
40+
encoded);
41+
if (encoded)
42+
xmlFree(encoded);
43+
44+
XmlComment* comment = new XmlComment(comm);
45+
comm->_private = comment;
46+
comment->Wrap(args.Holder());
47+
48+
// this prevents the document from going away
49+
args.Holder()->Set(v8::String::NewSymbol("document"), args[0]);
50+
51+
return scope.Close(args.Holder());
52+
}
53+
54+
v8::Handle<v8::Value>
55+
XmlComment::Text(const v8::Arguments& args) {
56+
v8::HandleScope scope;
57+
XmlComment *comment = ObjectWrap::Unwrap<XmlComment>(args.Holder());
58+
assert(comment);
59+
60+
if (args.Length() == 0) {
61+
return scope.Close(comment->get_content());
62+
} else {
63+
comment->set_content(*v8::String::Utf8Value(args[0]));
64+
}
65+
66+
return scope.Close(args.Holder());
67+
}
68+
69+
void
70+
XmlComment::set_content(const char* content) {
71+
xmlChar *encoded = xmlEncodeSpecialChars(xml_obj->doc, (const xmlChar*)content);
72+
xmlNodeSetContent(xml_obj, encoded);
73+
xmlFree(encoded);
74+
}
75+
76+
v8::Handle<v8::Value>
77+
XmlComment::get_content() {
78+
xmlChar* content = xmlNodeGetContent(xml_obj);
79+
if (content) {
80+
v8::Handle<v8::String> ret_content =
81+
v8::String::New((const char *)content);
82+
xmlFree(content);
83+
return ret_content;
84+
}
85+
86+
return v8::String::Empty();
87+
}
88+
89+
90+
v8::Handle<v8::Object>
91+
XmlComment::New(xmlNode* node)
92+
{
93+
if (node->_private) {
94+
return static_cast<XmlNode*>(node->_private)->handle_;
95+
}
96+
97+
XmlComment* comment = new XmlComment(node);
98+
v8::Local<v8::Object> obj = constructor_template->GetFunction()->NewInstance();
99+
comment->Wrap(obj);
100+
return obj;
101+
}
102+
103+
XmlComment::XmlComment(xmlNode* node)
104+
: XmlNode(node)
105+
{
106+
}
107+
108+
void
109+
XmlComment::Initialize(v8::Handle<v8::Object> target)
110+
{
111+
v8::HandleScope scope;
112+
v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(New);
113+
constructor_template = v8::Persistent<v8::FunctionTemplate>::New(t);
114+
constructor_template->Inherit(XmlNode::constructor_template);
115+
constructor_template->InstanceTemplate()->SetInternalFieldCount(1);
116+
117+
NODE_SET_PROTOTYPE_METHOD(constructor_template,
118+
"text",
119+
XmlComment::Text);
120+
121+
target->Set(v8::String::NewSymbol("Comment"),
122+
constructor_template->GetFunction());
123+
}
124+
125+
} // namespace libxmljs

src/xml_comment.h

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#ifndef SRC_XML_COMMENT_H_
2+
#define SRC_XML_COMMENT_H_
3+
4+
#include "libxmljs.h"
5+
#include "xml_node.h"
6+
7+
namespace libxmljs {
8+
9+
class XmlComment : public XmlNode {
10+
public:
11+
12+
explicit XmlComment(xmlNode* node);
13+
14+
static void Initialize(v8::Handle<v8::Object> target);
15+
16+
static v8::Persistent<v8::FunctionTemplate> constructor_template;
17+
18+
// create new xml comment to wrap the node
19+
static v8::Handle<v8::Object> New(xmlNode* node);
20+
21+
protected:
22+
23+
static v8::Handle<v8::Value> New(const v8::Arguments& args);
24+
static v8::Handle<v8::Value> Text(const v8::Arguments& args);
25+
26+
void set_content(const char* content);
27+
v8::Handle<v8::Value> get_content();
28+
};
29+
30+
} // namespace libxmljs
31+
32+
#endif // SRC_XML_COMMENT_H_

src/xml_node.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "xml_document.h"
99
#include "xml_namespace.h"
1010
#include "xml_element.h"
11+
#include "xml_comment.h"
1112
#include "xml_attribute.h"
1213

1314
namespace libxmljs {
@@ -451,6 +452,7 @@ XmlNode::Initialize(v8::Handle<v8::Object> target) {
451452
XmlNode::ToString);
452453

453454
XmlElement::Initialize(target);
455+
XmlComment::Initialize(target);
454456
XmlAttribute::Initialize(target);
455457
}
456458
} // namespace libxmljs

test/comment.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
var libxml = require('../index');
2+
3+
module.exports.new = function(assert) {
4+
var doc = libxml.Document();
5+
var comm = libxml.Comment(doc, 'comment1');
6+
doc.root(comm);
7+
assert.equal('comment1', comm.text());
8+
assert.done();
9+
};
10+
11+
module.exports.text = function(assert) {
12+
var doc = libxml.Document();
13+
var comm = libxml.Comment(doc);
14+
comm.text('comment2');
15+
assert.equal('comment2', comm.text());
16+
assert.done();
17+
};
18+

0 commit comments

Comments
 (0)