@@ -15,11 +15,15 @@ Napi::Object Libxml::Init(Napi::Env env, Napi::Object exports)
1515 InstanceMethod (" loadXml" , &Libxml::loadXml),
1616 InstanceMethod (" loadXmlFromString" , &Libxml::loadXmlFromString),
1717 InstanceMethod (" loadDtds" , &Libxml::loadDtds),
18+ InstanceMethod (" loadSchemas" , &Libxml::loadSchemas),
1819 InstanceMethod (" validateAgainstDtds" , &Libxml::validateAgainstDtds),
20+ InstanceMethod (" validateAgainstSchemas" , &Libxml::validateAgainstSchemas),
1921 InstanceMethod (" xpathSelect" , &Libxml::xpathSelect),
2022 InstanceMethod (" getDtd" , &Libxml::getDtd),
2123 InstanceMethod (" freeXml" , &Libxml::freeXml),
22- InstanceMethod (" freeDtds" , &Libxml::freeDtds)
24+ InstanceMethod (" freeDtds" , &Libxml::freeDtds),
25+ InstanceMethod (" freeSchemas" , &Libxml::freeSchemas),
26+ InstanceMethod (" clearAll" , &Libxml::clearAll)
2327 });
2428
2529 // Create a peristent reference to the class constructor. This will allow
@@ -163,6 +167,57 @@ Napi::Value Libxml::loadDtds(const Napi::CallbackInfo& info) {
163167 return env.Undefined ();
164168}
165169
170+ Napi::Value Libxml::loadSchemas (const Napi::CallbackInfo& info) {
171+ Napi::Env env = info.Env ();
172+ if (info.Length () < 1 ){
173+ Napi::TypeError::New (env, " loadSchemas requires at least 1 argument, an array of Schemas" ).ThrowAsJavaScriptException ();
174+ return env.Undefined ();
175+ }
176+ if (!info[0 ].IsArray ()){
177+ Napi::TypeError::New (env, " loadSchemas requires an array" ).ThrowAsJavaScriptException ();
178+ return env.Undefined ();
179+ }
180+ Napi::EscapableHandleScope scope (env);
181+ Napi::Array schemasPathsLocal = info[0 ].As <Napi::Array>();
182+ // set up error handlers
183+ Napi::Array errors = Napi::Array::New (env);
184+ xmlResetLastError ();
185+ XmlSyntaxError::env = &env;
186+ xmlSetStructuredErrorFunc (reinterpret_cast <void *>(&errors),
187+ XmlSyntaxError::PushToArray);
188+ for (unsigned int i = 0 ; i < schemasPathsLocal.Length (); i++){
189+ // Handle value if string and drop it silently otherwise
190+ if (schemasPathsLocal.Get (i).IsString ()) {
191+ Napi::String value = schemasPathsLocal.Get (i).As <Napi::String>();
192+ string pathStr (value.Utf8Value ());
193+ const char * path (pathStr.c_str ());
194+ xmlSchemaParserCtxtPtr pctxt;
195+ xmlSchemaPtr schema;
196+ // If cannot create Parse schema, just continue
197+ if ((pctxt = xmlSchemaNewParserCtxt (path)) == NULL ) {
198+ XmlSyntaxError::PushToArray (errors, path);
199+ continue ;
200+ }
201+ // Loading XML Schema content
202+ schema = xmlSchemaParse (pctxt);
203+ xmlSchemaFreeParserCtxt (pctxt);
204+ if (schema == nullptr ) {
205+ XmlSyntaxError::PushToArray (errors, path);
206+ continue ;
207+ }
208+ this ->schemasPaths .push_back (schema);
209+ }
210+ }
211+ xmlSetStructuredErrorFunc (NULL , NULL );
212+ // We set dtdLoadedErrors property for js side
213+ if (errors.Length ()){
214+ this ->Value ().Set (" schemasLoadedErrors" , errors);
215+ } else {
216+ this ->Value ().Delete (" schemasLoadedErrors" );
217+ }
218+ return env.Undefined ();
219+ }
220+
166221Napi::Value Libxml::validateAgainstDtds (const Napi::CallbackInfo& info) {
167222 Napi::Env env = info.Env ();
168223
@@ -234,6 +289,74 @@ Napi::Value Libxml::validateAgainstDtds(const Napi::CallbackInfo& info) {
234289 }
235290}
236291
292+ Napi::Value Libxml::validateAgainstSchemas (const Napi::CallbackInfo& info) {
293+ Napi::Env env = info.Env ();
294+
295+ if (this ->schemasPaths .empty ()){
296+ return env.Null ();;
297+ }
298+
299+ if (info[0 ].IsNumber ()){
300+ XmlSyntaxError::ChangeMaxNumberOfError (info[0 ].ToNumber ().Int32Value ());
301+ }
302+ // Setting context of validation
303+ const char * schemaValidationErrorsPath;
304+ bool oneOfTheSchemaValidate = false ;
305+ string schemaValidateName;
306+
307+
308+ // If length 0, return null; to implement
309+ // Local<Object> errorsValidations = Nan::New<Object>();
310+ Napi::Object errorsValidations = Napi::Object::New (env);
311+
312+ for (vector<xmlSchemaPtr>::iterator xsd = this ->schemasPaths .begin (); xsd != this ->schemasPaths .end () ; ++xsd){
313+ // set up error handling
314+ Napi::Array errors = Napi::Array::New (env);
315+ xmlResetLastError ();
316+ XmlSyntaxError::env = &env;
317+ xmlSetStructuredErrorFunc (reinterpret_cast <void *>(&errors),
318+ XmlSyntaxError::PushToArray);
319+
320+ const char * xsdName = (const char *)(*xsd)->doc ->URL ;
321+ // Local<String> urlSchema = Nan::New<String>(xsdName).ToLocalChecked();
322+ Napi::String urlSchema = Napi::String::New (env, xsdName);
323+ // Creating the validation context
324+ xmlSchemaValidCtxtPtr vctxt;
325+ if ((vctxt = xmlSchemaNewValidCtxt (*xsd)) == nullptr ) {
326+ continue ;
327+ }
328+ // Instead we could set this to disable output : xmlSetStructuredErrorFunc(vctxt,errorsHandler);
329+ // xmlSchemaSetValidErrors(vctxt, (xmlSchemaValidityErrorFunc) Libxml::errorsHandler, (xmlSchemaValidityWarningFunc) Libxml::errorsHandler, (void *) Libxml::errorsHandler);
330+ xmlSchemaSetValidErrors (vctxt, nullptr , nullptr , nullptr );
331+ int result = xmlSchemaValidateDoc (vctxt, this ->docPtr );
332+ // Stop listening for errors
333+ xmlSetStructuredErrorFunc (nullptr , nullptr );
334+ xmlSchemaFreeValidCtxt (vctxt);
335+ if (result == 0 ){
336+ oneOfTheSchemaValidate = true ;
337+ schemaValidateName = xsdName;
338+ break ;
339+ }
340+ errorsValidations.Set (urlSchema, errors);
341+ schemaValidationErrorsPath = xsdName;
342+ }
343+ if (oneOfTheSchemaValidate){
344+ this ->Value ().Delete (" validationSchemaErrors" );
345+ if (schemaValidateName.length ()){
346+ // info.GetReturnValue().Set(Nan::New<v8::String>(schemaValidateName).ToLocalChecked());
347+ return Napi::String::New (env, schemaValidateName);
348+ }else {
349+ // info.GetReturnValue().Set(Nan::True());
350+ return Napi::Boolean::New (env, true );
351+ }
352+ }else {
353+ // info.Holder()->Set(Nan::New<v8::String>("validationSchemaErrors").ToLocalChecked(), errorsValidations);
354+ // info.GetReturnValue().Set(Nan::False());
355+ this ->Value ().Set (" validationSchemaErrors" , errorsValidations);
356+ return Napi::Boolean::New (env, false );
357+ }
358+ }
359+
237360Napi::Value Libxml::xpathSelect (const Napi::CallbackInfo& info) {
238361 Napi::Env env = info.Env ();
239362 if (info.Length () < 1 ){
@@ -328,15 +451,15 @@ void Libxml::freeXml(const Napi::CallbackInfo& info) {
328451 this ->docPtr = nullptr ;
329452}
330453
331- Napi::Value Libxml::freeDtds (const Napi::CallbackInfo& info) {
454+ void Libxml::freeDtds (const Napi::CallbackInfo& info) {
332455 Napi::Env env = info.Env ();
333456 Napi::HandleScope scope (env);
334457 // Delete Javascript property
335458 this ->Value ().Delete (" dtdsLoadedErrors" );
336459 this ->Value ().Delete (" validationDtdErrors" );
337460 // If dtds is already empty, just stop here
338461 if (this ->dtdsPaths .empty ()){
339- return env. Undefined () ;
462+ return ;
340463 }
341464 for (vector<xmlDtdPtr>::iterator dtd = this ->dtdsPaths .begin (); dtd != this ->dtdsPaths .end () ; ++dtd){
342465 if (*dtd != nullptr ){
@@ -347,7 +470,39 @@ Napi::Value Libxml::freeDtds(const Napi::CallbackInfo& info) {
347470 }
348471 // clear the vector of dtds
349472 this ->dtdsPaths .clear ();
350- return env.Undefined ();
473+ return ;
474+ }
475+
476+ void Libxml::freeSchemas (const Napi::CallbackInfo& info) {
477+ Napi::Env env = info.Env ();
478+ Napi::HandleScope scope (env);
479+ // Libxml* libxml = Nan::ObjectWrap::Unwrap<Libxml>(info.Holder());
480+ // Delete Javascript property
481+ // bool deletedLoaded = Nan::Delete(info.Holder(), Nan::New<v8::String>("schemasLoadedErrors").ToLocalChecked()).FromMaybe(false);
482+ // bool deleted = Nan::Delete(info.Holder(), Nan::New<v8::String>("validationSchemasErrors").ToLocalChecked()).FromMaybe(false);
483+ this ->Value ().Delete (" schemasLoadedErrors" );
484+ this ->Value ().Delete (" validationSchemasErrors" );
485+ // If dtds is already empty, just stop here
486+ if (this ->schemasPaths .empty ()){
487+ return ;
488+ }
489+ for (vector<xmlSchemaPtr>::iterator xsd = this ->schemasPaths .begin (); xsd != this ->schemasPaths .end () ; ++xsd){
490+ if (*xsd != nullptr ){
491+ // Force clear memory xsd loaded
492+ xmlSchemaFree (*xsd);
493+ *xsd = nullptr ;
494+ }
495+ }
496+ // clear the vector of dtds
497+ this ->schemasPaths .clear ();
498+ //
499+ }
500+
501+ void Libxml::clearAll (const Napi::CallbackInfo& info) {
502+ this ->freeXml (info);
503+ this ->freeDtds (info);
504+ this ->freeSchemas (info);
505+ xmlCleanupParser ();
351506}
352507
353508// Initialize native add-on
0 commit comments