by Ben Bornstein (updated by Akiya Jouraku)
In addition to using the SBML Online Validator web interface, you can also call
the validator over the web from your own program or script. There are
a number of reasons you might want to do this. Since "always on"
Internet connectivity is becoming ubiquitous (especially in academic
settings), remote validation may be the quickest and easiest way for
your simulator to check an SBML model for syntax and consistency.
Even if you choose not to call the validator every time your program
reads an SBML file, it might be nice to give your users the option.
In another scenario, you may want to run the validator over a large
set of SBML files in batch mode. If for some reason, you cannot or do
not wish to run the validator remotely, you can bundle it in your own
program by using libSBML.
The Online Validator is called by submitting either an HTTP GET or
POST command directly to the URL http://sbml.org/validator/. This
isn't as complicated as it may sound. It's much simpler than
using so-called "web service" protocols like SOAP or XML-RPC. When
calling the validator you can specify that validation results be
returned in one of several formats, including:
- XML
- XHTML
- Javascript Object Notation (JSON)
- Plain text
In the tutorials below, we provide full example programs that show you
how to call the Online Validator from:
We'll start by calling the Online Validator from the command-line
with a program called curl. Since Curl is a high-level tool, it hides
a few of the details we need to worry about in Python and Java.
The Command Line
The curl program is a
command-line tool for transferring files to and from URLs. It
supports many protocols including Telnet, FTP, and HTTP. Most Linux,
Mac OS X (Tiger, Leopard), and Windows (Cygwin) systems come with curl already
installed. For our purposes the curl syntax is straightforward:
curl -F file=@filename.xml -F output=xml -F offcheck=u http://sbml.org/validator/
This calls the SBML validator by setting three form variables (the
-F option): file, output, and offcheck.
The at symbol (@) instructs curl to read the value of the variable from the filename
that follows. The output parameter indicates the format of the validation results
and the offcheck parameter indicates which consistency check will be disabled
('u' disables the units check).
You can ask the validator to validate files located anywhere on
the Internet by passing a URL instead of a file. For example, try the
following:
curl -F url=http://sbml.org/validator/api/sample-01.xml -F output=xml -F offcheck=u http://sbml.org/validator/
The validator will indicate there were no error (i.e. the SBML
file is valid) by returning the following XML:
<?xml version='1.0' encoding='UTF-8'?>
<validation-results>
<file filename='sample-01.xml'/>
<option name='check_units_consistency' status='off'/>
<option name='check_overall_sbml_consistency' status='on'/>
<option name='check_identifier_consistency' status='on'/>
<option name='check_mathml_consistency' status='on'/>
<option name='check_sbo_consistency' status='on'/>
<option name='check_overdetermined_model' status='on'/>
<option name='check_modeling_practice' status='on'/>
<no-errors/>
</validation-results>
Note: If instead you see:
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>301 Moved Permanently</title>
</head><body>
<h1>Moved Permanently</h1>
<p>The document has moved <a href="http://sbml.org/validator/">here</a>.</p>
</body></html>
Make sure the validator URL ends in a slash (/):
http://sbml.org/validator/.
Let's validate an SBML file with some errors:
curl -F url=http://sbml.org/validator/api/sample-02.xml -F output=xml -F offcheck=u http://sbml.org/validator/
<?xml version='1.0' encoding='UTF-8'?>
<validation-results>
<file filename='sample-02.xml'/>
<option name='check_units_consistency' status='off'/>
<option name='check_overall_sbml_consistency' status='on'/>
<option name='check_identifier_consistency' status='on'/>
<option name='check_mathml_consistency' status='on'/>
<option name='check_sbo_consistency' status='on'/>
<option name='check_overdetermined_model' status='on'/>
<option name='check_modeling_practice' status='on'/>
<error/>
<problem category='General SBML consistency' code='20505' severity='Error'>
<location line='15' column='24'/>
<message lang='en_US'>
<![CDATA[(SBML Validation Rule #20505) A <compartment> may not enclose itself
through a chain of references involving the 'outside' field. This means
that a compartment cannot have its own identifier as the value of 'outside',
nor can it point to another compartment whose 'outside' field points directly
or indirectly to the compartment. (References: L2V1 erratum 11; L2V2 Section
4.7.7.) Compartment 'e' encloses itself. ]]>
</message>
<excerpt><![CDATA[ <compartment id="e" outside="e"/>]]></excerpt>
</problem>
<problem category='General SBML consistency' code='20505' severity='Error'>
<location line='16' column='24'/>
<message lang='en_US'>
<![CDATA[(SBML Validation Rule #20505) A <compartment> may not enclose itself
through a chain of references involving the 'outside' field. This means
that a compartment cannot have its own identifier as the value of 'outside',
nor can it point to another compartment whose 'outside' field points directly
or indirectly to the compartment. (References: L2V1 erratum 11; L2V2 Section
4.7.7.) Compartment 'a' encloses itself via 'a' -> 'b' -> 'c' -> 'd' -> 'a'.
]]>
</message>
<excerpt><![CDATA[ <compartment id="a" outside="b"/>]]></excerpt>
</problem>
</validation-results>
Although the XML has been wrapped for readability, this output is
still a bit hard to read. Let's ask the validator to distill it to
plain text:
curl -F url=http://sbml.org/validator/api/sample-02.xml -F output=text -F offcheck=u http://sbml.org/validator/
File: sample-02.xml
Options:
Units consistency checking: off
Identifier consistency checking: on
MathML consistency checking: on
SBO consistency checking: on
Overdetermined model checking: on
Modeling practices checking: on
Overall SBML consistency checking: on
Results: This document is not valid SBML!
2 Errors
Error: line 15: (SBML Validation Rule #20505) A <compartment> may not enclose itself
through a chain of references involving the 'outside' field.
This means that a compartment cannot have its own identifier as
the value of 'outside', nor can it point to another compartment
whose 'outside' field points directly or indirectly to the
compartment. (References: L2V1 erratum 11; L2V2 Section 4.7.7.)
Compartment 'e' encloses itself.
Error: line 16: (SBML Validation Rule #20505) A <compartment> may not enclose itself
through a chain of references involving the 'outside' field.
This means that a compartment cannot have its own identifier as
the value of 'outside', nor can it point to another compartment
whose 'outside' field points directly or indirectly to the
compartment. (References: L2V1 erratum 11; L2V2 Section 4.7.7.)
Compartment 'a' encloses itself via 'a' -> 'b' -> 'c' -> 'd' -> 'a'.
This output (still wrapped for web page display) is more
readable. There are two errors, one on line 15 and the other on line
16. Compare the XML and text outputs to the XHTML output.
As described in the first example, you can choose which consistency checks will be disabled.
To disable one or more consistency checks, pass the comma-separated characters to the offcheck parameter.
Available characters are as follows:
u --> Disable checking the consistency of measurement units associated
with quantities (SBML L2V3 rules 105nn)
i --> Disable checking the correctness and consistency of identifiers
used for model entities (SBML L2V3 rules 103nn)
m --> Disable checking the syntax of MathML mathematical expressions
(SBML L2V3 rules 102nn)
s --> Disable checking the validity of SBO identifiers (if any) used in
the model (SBML L2V3 rules 107nn)
o --> Disable static analysis of whether the model is overdetermined
p --> Disable additional checks for recommended good modeling practices
g --> Disable all other general SBML consistency checks
(SBML L2v3 rules 2nnnn)
For example, the following command will disable unit consistency check (u), modeling practices check (p),
and SBO consistency check (s).
curl -F file=@filename.xml -F output=text -F offcheck=u,p,s http://sbml.org/validator/
That's all there is too it! Here are some more curl commands to
experiment with:
curl -F url=http://sbml.org/validator/api/sample-03.xml -F output=xml http://sbml.org/validator/
curl -F url=http://sbml.org/validator/api/sample-03.xml -F output=text http://sbml.org/validator/
curl -F url=http://sbml.org/validator/api/sample-03.xml -F output=json http://sbml.org/validator/
curl -F url=http://sbml.org/validator/api/sample-03.xml -F output=xhtml http://sbml.org/validator/
Finally, you can use curl to write a validateSBML.sh shell script:
- #!/bin/sh
- ##
- ##usage: validateSBML.sh [-h] [-d opt1[,opt2,...]] [-o output] filename.xml
- ## validateSBML.sh [-h] [-d opt1[,opt2,...]] [-o output] http://.../filename.xml
- ##
- ## Validates the SBML document given by filename.xml using the
- ## SBML.org Online Validator.
- ##
- # Print the usage statement at the top of this program and available options.
- usage() {
- synopsis=`grep "^##" $0 | sed 's/##//'`
- cat << EOF
- $synopsis
- options:
- -o output
- Specify an output format.
- text : plain text (Default)
- xml : XML
- xhtml : XHTML
- json : JavaScript Object Notation
- -d opt1[,opt2,...]
- Disable the given consistency check options.
- The options are given as comma-separated characters.
- Each character is one of the followings:
- u : disable the units consistency check
- g : disable the overall SBML consistency check
- i : disable the identifier consistency check
- m : disable the MathML consistency check
- s : disable the SBO consistency check
- o : disable the overdetermined model check
- p : disable the modeling practice check
- -h Print this usage.
- EOF
- }
- validator_url='http://sbml.org/validator/'
- output='text'
- # Parse the command-line arguments.
- while getopts d:o:h opt
- do
- case $opt in
- d)
- offcheck="-F offcheck=$OPTARG"
- ;;
- o)
- output=$OPTARG
- ;;
- *)
- usage
- exit
- ;;
- esac
- done
- shift `expr $OPTIND - 1`
- # Exit if no SBML file given.
- if [ $# -lt 1 ]; then
- usage
- exit
- fi
- filename=$1
- if echo $filename | grep -q '^http://'; then
- src="url=${filename}"
- else
- src="file=@${filename}"
- fi
- curl -F output=${output} -F ${src} ${offcheck} ${validator_url}
GNU Emacs
Most modern GNU Emacs installations come with PSGML
mode for editing XML files. When this mode is active (e.g. when
you load an XML file), you can validate the XML by issuing the command
M-x sgml-validate (C-c C-v). To validate
SBML files, simply override the PSGML validate command to call the
Online Validator (the validator's plain text output format is
understood by Emacs):
-
Copy validateSBML.sh from
the Command Line Tutorial to a directory on
your local machine (e.g. ~/emacs)
-
Add the following to your .emacs initialization file:
(setq sgml-validate-command "~/emacs/validateSBML.sh")
Python
If you've already read through the Command Line
Tutorial, you're in good shape. Things are only slightly more
complicated in Python (and Java). Both languages provide libraries
for communicating with web servers, but you need to do a little work
to send data to the server in the correct multipart post format.
Fortunately, we've done the work for you. The Python function
encode() encodes both a dictionary of name-value pairs
and the contents of a file in the appropriate format:
- import random, string
- def encode (parameters, filename=None):
- """encode(parameters, filename=None) -> (boundary, data)
- Encodes the contents of validator parameters (a Python dictionary)
- and filename (assumed to XML) into a format suitable for uploading
- to the SBML.org validator via an HTTP POST.
- Adapted from the Python Cookbook:
- - http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/146306
- """
- boundary = '<<' + ''.join([random.choice(string.digits) for n in range(30)])
- lines = [ ]
- if filename is not None:
- format = 'Content-Disposition: form-data; name="file"; filename="%s"'
- lines.append('--' + boundary)
- lines.append(format % filename)
- lines.append('Content-Type: text/xml')
- lines.append('')
- stream = open(filename)
- lines.extend( map(string.rstrip, stream.readlines()) )
- stream.close()
- if parameters is not None:
- for (name, value) in parameters.items():
- lines.append('--' + boundary)
- lines.append('Content-Disposition: form-data; name="%s"' % name)
- lines.append('')
- lines.append( str(value) )
- lines.append('--' + boundary + '--')
- lines.append('')
- return (boundary, string.join(lines, '\r\n'))
All that's left is to write a function that uses
encode() and Python's httplib to make an HTTP POST
request to the validator.
- import httplib
- def validateSBML (filename, parameters=None):
- """validateSBML(filename, parameters=None) -> string
- Validates the given SBML filename (or http:// URL) by calling the
- SBML.org online validator. The results are returned as a string
- whose format may be controlled by setting parameters['output'] to
- one of: 'xml', 'xhtml', 'json', 'text' (default: xml).
- """
- if parameters is None:
- parameters = { }
- if filename.startswith('http://'):
- parameters['url'] = filename
- filename = None
- parameters.setdefault('output', 'xml')
- (boundary, body) = encode(parameters, filename)
- headers = { 'Content-Type': 'multipart/form-data; boundary=%s' % boundary }
- http = httplib.HTTPConnection(HOST)
- http.request('POST', URL, body, headers)
- return http.getresponse().read()
You can download validateSBML.py
which includes both encode() and
validateSBML() along with some additional code to run the
Python script from the command-line.
Java
If you've already read through the Command Line
Tutorial, you're in good shape. Things are only slightly more
complicated in Java (and Python). Both languages provide libraries
for communicating with web servers, but you need to do a little work
to send data to the server in the correct multipart post format.
Fortunately, we've done the work for you with the Java class
MulitpartPost:
- import java.net.URL;
- import java.net.URLConnection;
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.InputStream;
- import java.io.OutputStream;
- import java.io.IOException;
- import java.util.Random;
- /**
- * Performs a Multipart HTTP post to the given URL. A post operation
- * is started with the creation of a MultipartPost object. Post
- * parameters are sent with writeParameter() and may be eithier
- * strings or the contents of an XML file. A post is finished by
- * calling done() which returns an InputStream for reading the servers
- * response.
- *
- * NOTE: This class is meant to communicate with the SBML.org online
- * validator. As such, it assumes uploaded files are XML and always
- * sends a Content-Type: text/xml.
- */
- class MultipartPost
- {
- public MultipartPost (String url) throws IOException
- {
- Random random = new Random();
- connection = ( new URL(url) ).openConnection();
- boundary = "<<" + Long.toString(random.nextLong(), 30);
- String type = "multipart/form-data; boundary=" + boundary;
- connection.setDoOutput(true);
- connection.setRequestProperty("Content-Type", type);
- stream = connection.getOutputStream();
- }
- public InputStream done () throws IOException
- {
- writeln("--" + boundary + "--");
- writeln();
- stream.close();
- return connection.getInputStream();
- }
- public void writeParameter (String name, String value) throws IOException
- {
- writeln("--" + boundary);
- writeln("Content-Disposition: form-data; name=\"" + name + "\"");
- writeln();
- writeln(value);
- }
- public void writeParameter (String name, File file) throws IOException
- {
- String prefix = "Content-Disposition: form-data; name=\"file\"; filename=";
- writeln("--" + boundary);
- writeln(prefix + '"' + file.getName() + '"');
- writeln("Content-Type: text/xml");
- writeln();
- InputStream source = new FileInputStream(file);
- copy(source, stream);
- stream.flush();
- source.close();
- }
- void copy (InputStream source, OutputStream destination) throws IOException
- {
- byte[] buffer = new byte[8192];
- int nbytes = 0;
- while ((nbytes = source.read(buffer, 0, buffer.length)) >= 0)
- {
- destination.write(buffer, 0, nbytes);
- }
- }
- void writeln (String s) throws IOException
- {
- write(s);
- writeln();
- }
- void writeln () throws IOException
- {
- write('\r');
- write('\n');
- }
- void write (char c) throws IOException
- {
- stream.write(c);
- }
- void write (String s) throws IOException
- {
- stream.write(s.getBytes());
- }
- URLConnection connection;
- OutputStream stream;
- String boundary;
- }
All that's left is to write a function that uses
MultipartPost to make an HTTP POST
request to the validator:
- import java.io.File;
- import java.io.InputStream;
- import java.io.IOException;
- import java.util.HashMap;
- import java.util.Iterator;
- import java.util.Map;
- import java.util.NoSuchElementException;
- /**
- * SBMLValidator is simply a container for the static method
- * validateSBML(filename, parameters).
- */
- class SBMLValidator
- {
- /**
- * Validates the given SBML filename (or http:// URL) by calling the
- * SBML.org online validator. The results are returned as an
- * InputStream whose format may be controlled by setting
- * parameters.put("output", ...) to one of: "xml", "xhtml", "json",
- * "text" (default: xml).
- *
- * @return an InputStream containing the validation results.
- */
- public static InputStream validateSBML (String filename, Map parameters)
- throws IOException
- {
- if (parameters.get("output") == null)
- {
- parameters.put("output", "xml");
- }
- MultipartPost post = new MultipartPost("http://sbml.org/validator/");
- InputStream result = null;
- if (filename.startsWith("http://"))
- {
- post.writeParameter("url", filename);
- }
- else
- {
- post.writeParameter("file", new File(filename));
- }
- try
- {
- Iterator iter = parameters.keySet().iterator();
- while ( iter.hasNext() )
- {
- String name = (String) iter.next();
- String value = (String) parameters.get(name);
- post.writeParameter(name, value);
- }
- }
- catch (NoSuchElementException e)
- {
- e.printStackTrace();
- }
- return post.done();
- }
- }
You can download validateSBML.java which includes
both MultipartPost and
SBMLValidator.validateSBML() along with some additional
code to run the Java program from the command-line.
Validator XML Output
The XML output produced by the Online Validator is its most basic
format. All other output formats (XHTML, JSON, and plain text) are
derived from the XML through XSLT scripts. The format is:
<?xml version='1.0' encoding='UTF-8'?>
<validation-results>
<file filename='%s'/>
<option name='%s' status='%s'/>
...
...
<option name='%s' status='%s'/>
<!--
One of:
<no-errors/>
<warning/>
<error/>
<file-not-readable/>
<out-of-memory/>
<segmentation-fault/>
<internal-error/>
and when <warning/> or <error/> issued, one or more of:
<problem category='%s' code='%u' severity='%s'>
<location line='%u' column='%u'/>
<message lang='en_US'> <![CDATA[ ... ]]> </message>
<excerpt> <![CDATA[ ... ]]> </excerpt>
</problem>
-->
</validation-results>
The C printf-style format specifiers denote: %s -
string, %u - unsigned
integer. The SBML filename that was validated (sans any directory or
path information) and the satuts of validation options are always given.
Next the status of the validation result is given. The status is either
'no-errors', 'warning', 'error', or a single
critical error.
When the status is a 'warning' or 'error', one or more
corresponding problems are reported.
Below we briefly explain each status of the validation result:
| <no-errors/> |
No errors were encountered, i.e. the document is valid SBML. |
<warning/> |
No errors were encountered, i.e. the document is valid SBML.
However, one or more warnings were encountered. |
| <error/> |
One ore more errors were encounterd, i.e. the document is invalid SBML. |
| <file-not-readable/> |
You should never encounter this error. It is meant for
those testing the validator on the server. |
| <out-of-memory/> |
The validator ran out of memory. This error is rare but
technically possible. |
| <segmentation-fault/> |
The validator crashed during validation. This error is rare but
technically possible. |
| <internal-error/> |
The validator terminated due to the unexpected internal error.
This error shouldn't happen under normal circumstances. |
Problems :
<problem category='%s' code='%u' severity='%s'>
<location line='%u' column='%u'/>
<message lang='en_US'> <![CDATA[ ... ]]> </message>
<excerpt> <![CDATA[ ... ]]> </excerpt>
</problem>
Each <problem> has a category, a code, and a
severity that uniquely identify it. The category is one of the
following strings:
- Internal
- System
- XML
- SBML
- SBML Level 1 compatibility
- SBML Level 2 Version 1 compatibility
- SBML Level 2 Version 2 compatibility
- SBML Level 2 Version 3 compatibility
- General SBML consistency
- Identifier consistency
- Units consistency
- MathML consistency
- SBO consistency
- Overdetermined model
- Modeling practice
Problem severities range from zero to three:
- 0. Advisory
- 1. Warning
- 2. Error
- 3. Fatal
The position of a problem within a document is located by line and
column (starting at 1). The <message> element
contains the message itself and <excerpt>
quotes the line within the document where the problem occurred. Since
both of these elements may contain content that could be
misinterpreted as XML (e.g. <, >,
', ", etc.) they are always
escaped by <![CDATA[ ... ]]> sections.