1 /**
2 * @file rngvalidator.cpp
3 * @brief Example creating a rng validator to be called during validation
4 * @author Frank T. Bergmann
5 *
6 * <!--------------------------------------------------------------------------
7 * This sample program is distributed under a different license than the rest
8 * of libSBML. This program uses the open-source MIT license, as follows:
9 *
10 * Copyright (c) 2013-2018 by the California Institute of Technology
11 * (California, USA), the European Bioinformatics Institute (EMBL-EBI, UK)
12 * and the University of Heidelberg (Germany), with support from the National
13 * Institutes of Health (USA) under grant R01GM070923. All rights reserved.
14 *
15 * Permission is hereby granted, free of charge, to any person obtaining a
16 * copy of this software and associated documentation files (the "Software"),
17 * to deal in the Software without restriction, including without limitation
18 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
19 * and/or sell copies of the Software, and to permit persons to whom the
20 * Software is furnished to do so, subject to the following conditions:
21 *
22 * The above copyright notice and this permission notice shall be included in
23 * all copies or substantial portions of the Software.
24 *
25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
28 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
30 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
31 * DEALINGS IN THE SOFTWARE.
32 *
33 * Neither the name of the California Institute of Technology (Caltech), nor
34 * of the European Bioinformatics Institute (EMBL-EBI), nor of the University
35 * of Heidelberg, nor the names of any contributors, may be used to endorse
36 * or promote products derived from this software without specific prior
37 * written permission.
38 * ------------------------------------------------------------------------ -->
39 */
40
41 #include <iostream>
42 #include <sbml/SBMLTypes.h>
43 #include <sbml/SBMLError.h>
44
45 #include <sbml/validator/SBMLValidator.h>
46
47 #include <libxml/xmlmemory.h>
48 #include <libxml/parser.h>
49 #include <libxml/relaxng.h>
50 #include <stdarg.h>
51 #include <util.h>
52
53 using namespace std;
54 LIBSBML_CPP_NAMESPACE_USE
55
56 std::vector<std::string> warnings;
57 std::vector<std::string> errors;
58
logWarning(void * ctx,const char * msg,...)59 void logWarning(void *ctx, const char *msg, ...)
60 {
61 char buffer[1000];
62 va_list args;
63 va_start (args, msg);
64 vsprintf (buffer,msg, args);
65 va_end (args);
66
67 warnings.push_back(buffer);
68 }
logError(void * ctx,const char * msg,...)69 void logError(void *ctx, const char *msg, ...)
70 {
71 char buffer[1000];
72 va_list args;
73 va_start (args, msg);
74 vsprintf (buffer,msg, args);
75 va_end (args);
76
77 errors.push_back(buffer);
78 }
79
80 /**
81 * Declares a custom validator to be called. This allows you to validate
82 * any aspect of an SBML Model that you want to be notified about. You could
83 * use this to notify your application that a model contains an unsupported
84 * feature of SBML (either as warning).
85 *
86 * In this example the validator will go through the model and test for the
87 * presence of 'fast' reactions and algebraic rules. If either is used a
88 * warning will be added to the error log.
89 */
90 class RNGValidator : public SBMLValidator
91 {
92 private:
93 std::string mSchema;
94
95 public:
96
setSchema(const std::string & schemaFile)97 void setSchema(const std::string& schemaFile)
98 {
99 mSchema =schemaFile;
100 }
101
getSchema() const102 const std::string& getSchema() const { return mSchema; }
103
RNGValidator()104 RNGValidator() : SBMLValidator(), mSchema() {}
105
RNGValidator(const std::string & schema)106 RNGValidator(const std::string& schema) : SBMLValidator(), mSchema(schema) {}
107
RNGValidator(const RNGValidator & orig)108 RNGValidator(const RNGValidator& orig) : SBMLValidator(orig), mSchema(orig.mSchema) {
109 }
~RNGValidator()110 virtual ~RNGValidator() {}
111
clone() const112 virtual SBMLValidator* clone() const { return new RNGValidator(*this); }
113
validate()114 virtual unsigned int validate() {
115 // if we don't have a model we don't apply this validator.
116 if (getDocument() == NULL || getModel() == NULL)
117 return 0;
118
119 // we dont' have a schema, so don't report
120 if (mSchema.empty())
121 return 0;
122
123 // if we have no rules and reactions we don't apply this validator either
124 if (getModel()->getNumReactions() == 0 && getModel()->getNumRules() == 0)
125 return 0;
126
127 // get document
128
129 std::string sbmlDoc = writeSBMLToString(getDocument());
130 warnings.clear();
131 errors.clear();
132
133 xmlDoc *doc;
134 xmlRelaxNGPtr schema;
135 xmlRelaxNGValidCtxtPtr validctxt;
136 xmlRelaxNGParserCtxtPtr rngparser;
137
138 doc = xmlParseMemory(sbmlDoc.c_str(), (int)(sbmlDoc.length()));
139
140 rngparser = xmlRelaxNGNewParserCtxt(mSchema.c_str());
141 schema = xmlRelaxNGParse(rngparser);
142 validctxt = xmlRelaxNGNewValidCtxt(schema);
143
144
145 xmlRelaxNGSetParserErrors (rngparser,
146 &logError,
147 &logWarning,
148 (void *) getErrorLog());
149 xmlRelaxNGSetValidErrors (validctxt,
150 &logError,
151 &logWarning,
152 (void *) getErrorLog());
153
154 xmlRelaxNGValidateDoc(validctxt, doc);
155
156 xmlRelaxNGFree(schema);
157 xmlRelaxNGFreeValidCtxt(validctxt);
158 xmlRelaxNGFreeParserCtxt(rngparser);
159 xmlFreeDoc(doc);
160
161 unsigned int numErrors = 0;
162
163 for (size_t i = 0; i < warnings.size(); ++i)
164 {
165
166 getErrorLog()->add(SBMLError(99999, 3, 1,
167 warnings[i],
168 0, 0,
169 LIBSBML_SEV_WARNING, // or LIBSBML_SEV_ERROR if you want to stop
170 LIBSBML_CAT_SBML // or whatever category you prefer
171 ));
172 }
173
174 for (size_t i = 0; i < errors.size(); ++i)
175 {
176
177 getErrorLog()->add(SBMLError(99999, 3, 1,
178 errors[i],
179 0, 0,
180 LIBSBML_SEV_ERROR, // or LIBSBML_SEV_ERROR if you want to stop
181 LIBSBML_CAT_SBML // or whatever category you prefer
182 ));
183 numErrors ++;
184 }
185
186 return numErrors;
187 }
188
189
190 };
191
192
193 int
main(int argc,char * argv[])194 main (int argc, char *argv[])
195 {
196 if (argc < 2)
197 {
198 cout << endl << "Usage: rngvalidator filename [schema]" << endl << endl;
199 return 1;
200 }
201
202 const char* filename = argv[1];
203
204 const char* schema = argc > 2 ? argv[2] : NULL;
205
206 // read the file name
207 SBMLDocument* document = readSBML(filename);
208
209 // add a custom validator if given
210 if (schema != NULL)
211 document->addValidator(new RNGValidator(schema));
212
213 unsigned long long start, stop;
214
215 start = getCurrentMillis();
216
217 // check consistency like before
218 int numErrors = document->checkConsistency();
219
220 stop = getCurrentMillis();
221
222 cout << " validation time (ms): " << stop - start << endl<< endl;
223
224
225 // print errors and warnings
226 document->printErrors();
227
228 // return number of errors
229 return numErrors;
230
231 }
232