diff --git a/lib/document.js b/lib/document.js index 0c063906..d249c049 100644 --- a/lib/document.js +++ b/lib/document.js @@ -68,6 +68,11 @@ Document.prototype.encoding = function(encoding) { return this._encoding(encoding); } +/// @return whether the XmlDocument is valid +Document.prototype.validate = function(xsd) { + return this._validate(xsd); +} + module.exports = Document; /// parse a string into a html document diff --git a/src/xml_document.cc b/src/xml_document.cc index 9c85e7c8..64a60ccd 100644 --- a/src/xml_document.cc +++ b/src/xml_document.cc @@ -3,6 +3,7 @@ #include #include +#include #include "xml_document.h" #include "xml_element.h" @@ -196,6 +197,40 @@ XmlDocument::FromXmlString(const v8::Arguments& args) return scope.Close(doc_handle); } +v8::Handle +XmlDocument::Validate(const v8::Arguments& args) +{ + v8::HandleScope scope; + + v8::Local errors = v8::Array::New(); + xmlResetLastError(); + xmlSetStructuredErrorFunc(reinterpret_cast(*errors), + XmlSyntaxError::PushToArray); + + XmlDocument* document = ObjectWrap::Unwrap(args.Holder()); + XmlDocument* documentSchema = ObjectWrap::Unwrap(args[0]->ToObject()); + + xmlSchemaParserCtxtPtr parser_ctxt = xmlSchemaNewDocParserCtxt(documentSchema->xml_obj); + if (parser_ctxt == NULL) { + return v8::ThrowException(v8::Exception::Error( + v8::String::New("Could not create context for schema parser"))); + } + xmlSchemaPtr schema = xmlSchemaParse(parser_ctxt); + if (schema == NULL) { + return v8::ThrowException(v8::Exception::Error( + v8::String::New("Invalid XSD schema"))); + } + xmlSchemaValidCtxtPtr valid_ctxt = xmlSchemaNewValidCtxt(schema); + if (valid_ctxt == NULL) { + return v8::ThrowException(v8::Exception::Error( + v8::String::New("Unable to create a validation context for the schema"))); + } + bool valid = xmlSchemaValidateDoc(valid_ctxt, document->xml_obj) == 0; + + return scope.Close(v8::Boolean::New(valid)); +} + + /// this is a blank object with prototype methods /// not exposed to the user and not called from js v8::Handle @@ -252,6 +287,10 @@ XmlDocument::Initialize(v8::Handle target) "_toString", XmlDocument::ToString); + NODE_SET_PROTOTYPE_METHOD(constructor_template, + "_validate", + XmlDocument::Validate); + NODE_SET_METHOD(target, "fromXmlString", XmlDocument::FromXmlString); NODE_SET_METHOD(target, "fromHtmlString", XmlDocument::FromHtmlString); diff --git a/src/xml_document.h b/src/xml_document.h index ab513380..eeb0c4cf 100644 --- a/src/xml_document.h +++ b/src/xml_document.h @@ -50,6 +50,7 @@ class XmlDocument : public node::ObjectWrap { static v8::Handle Doc(const v8::Arguments& args); static v8::Handle Errors(const v8::Arguments& args); static v8::Handle ToString(const v8::Arguments& args); + static v8::Handle Validate(const v8::Arguments& args); }; } // namespace libxmljs diff --git a/test/document.js b/test/document.js index d993e7e9..81d413a5 100644 --- a/test/document.js +++ b/test/document.js @@ -138,3 +138,18 @@ module.exports.cloned_node = function(assert) { assert.equal(doc1_string, doc2.toString()); //doc2 should be the same as doc1 str assert.done(); }; + +module.exports.validate = function(assert) { + var xsd = ''; + var xml_valid = 'A comment'; + var xml_invalid = 'A comment'; + + var xsdDoc = libxml.parseXmlString(xsd); + var xmlDocValid = libxml.parseXmlString(xml_valid); + var xmlDocInvalid = libxml.parseXmlString(xml_invalid); + + assert.equal(xmlDocValid.validate(xsdDoc), true); + assert.equal(xmlDocInvalid.validate(xsdDoc), false); + + assert.done(); +}