Validator Web API: Fully Validate your SBML Anytime

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:

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:

  1. #!/bin/sh
  2. ##
  3. ##usage: validateSBML.sh [-h] [-d opt1[,opt2,...]] [-o output] filename.xml
  4. ## validateSBML.sh [-h] [-d opt1[,opt2,...]] [-o output] http://.../filename.xml
  5. ##
  6. ## Validates the SBML document given by filename.xml using the
  7. ## SBML.org Online Validator.
  8. ##
  9. # Print the usage statement at the top of this program and available options.
  10. usage() {
  11. synopsis=`grep "^##" $0 | sed 's/##//'`
  12. cat << EOF
  13. $synopsis
  14. options:
  15. -o output
  16. Specify an output format.
  17. text : plain text (Default)
  18. xml : XML
  19. xhtml : XHTML
  20. json : JavaScript Object Notation
  21. -d opt1[,opt2,...]
  22. Disable the given consistency check options.
  23. The options are given as comma-separated characters.
  24. Each character is one of the followings:
  25. u : disable the units consistency check
  26. g : disable the overall SBML consistency check
  27. i : disable the identifier consistency check
  28. m : disable the MathML consistency check
  29. s : disable the SBO consistency check
  30. o : disable the overdetermined model check
  31. p : disable the modeling practice check
  32. -h Print this usage.
  33. EOF
  34. }
  35. validator_url='http://sbml.org/validator/'
  36. output='text'
  37. # Parse the command-line arguments.
  38. while getopts d:o:h opt
  39. do
  40. case $opt in
  41. d)
  42. offcheck="-F offcheck=$OPTARG"
  43. ;;
  44. o)
  45. output=$OPTARG
  46. ;;
  47. *)
  48. usage
  49. exit
  50. ;;
  51. esac
  52. done
  53. shift `expr $OPTIND - 1`
  54. # Exit if no SBML file given.
  55. if [ $# -lt 1 ]; then
  56. usage
  57. exit
  58. fi
  59. filename=$1
  60. if echo $filename | grep -q '^http://'; then
  61. src="url=${filename}"
  62. else
  63. src="file=@${filename}"
  64. fi
  65. 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):

  1. Copy validateSBML.sh from the Command Line Tutorial to a directory on your local machine (e.g. ~/emacs)

  2. 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:

  1. import random, string
  2. def encode (parameters, filename=None):
  3. """encode(parameters, filename=None) -> (boundary, data)
  4. Encodes the contents of validator parameters (a Python dictionary)
  5. and filename (assumed to XML) into a format suitable for uploading
  6. to the SBML.org validator via an HTTP POST.
  7. Adapted from the Python Cookbook:
  8. - http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/146306
  9. """
  10. boundary = '<<' + ''.join([random.choice(string.digits) for n in range(30)])
  11. lines = [ ]
  12. if filename is not None:
  13. format = 'Content-Disposition: form-data; name="file"; filename="%s"'
  14. lines.append('--' + boundary)
  15. lines.append(format % filename)
  16. lines.append('Content-Type: text/xml')
  17. lines.append('')
  18. stream = open(filename)
  19. lines.extend( map(string.rstrip, stream.readlines()) )
  20. stream.close()
  21. if parameters is not None:
  22. for (name, value) in parameters.items():
  23. lines.append('--' + boundary)
  24. lines.append('Content-Disposition: form-data; name="%s"' % name)
  25. lines.append('')
  26. lines.append( str(value) )
  27. lines.append('--' + boundary + '--')
  28. lines.append('')
  29. 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.

  1. import httplib
  2. def validateSBML (filename, parameters=None):
  3. """validateSBML(filename, parameters=None) -> string
  4. Validates the given SBML filename (or http:// URL) by calling the
  5. SBML.org online validator. The results are returned as a string
  6. whose format may be controlled by setting parameters['output'] to
  7. one of: 'xml', 'xhtml', 'json', 'text' (default: xml).
  8. """
  9. if parameters is None:
  10. parameters = { }
  11. if filename.startswith('http://'):
  12. parameters['url'] = filename
  13. filename = None
  14. parameters.setdefault('output', 'xml')
  15. (boundary, body) = encode(parameters, filename)
  16. headers = { 'Content-Type': 'multipart/form-data; boundary=%s' % boundary }
  17. http = httplib.HTTPConnection(HOST)
  18. http.request('POST', URL, body, headers)
  19. 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:

  1. import java.net.URL;
  2. import java.net.URLConnection;
  3. import java.io.File;
  4. import java.io.FileInputStream;
  5. import java.io.InputStream;
  6. import java.io.OutputStream;
  7. import java.io.IOException;
  8. import java.util.Random;
  9. /**
  10. * Performs a Multipart HTTP post to the given URL. A post operation
  11. * is started with the creation of a MultipartPost object. Post
  12. * parameters are sent with writeParameter() and may be eithier
  13. * strings or the contents of an XML file. A post is finished by
  14. * calling done() which returns an InputStream for reading the servers
  15. * response.
  16. *
  17. * NOTE: This class is meant to communicate with the SBML.org online
  18. * validator. As such, it assumes uploaded files are XML and always
  19. * sends a Content-Type: text/xml.
  20. */
  21. class MultipartPost
  22. {
  23. public MultipartPost (String url) throws IOException
  24. {
  25. Random random = new Random();
  26. connection = ( new URL(url) ).openConnection();
  27. boundary = "<<" + Long.toString(random.nextLong(), 30);
  28. String type = "multipart/form-data; boundary=" + boundary;
  29. connection.setDoOutput(true);
  30. connection.setRequestProperty("Content-Type", type);
  31. stream = connection.getOutputStream();
  32. }
  33. public InputStream done () throws IOException
  34. {
  35. writeln("--" + boundary + "--");
  36. writeln();
  37. stream.close();
  38. return connection.getInputStream();
  39. }
  40. public void writeParameter (String name, String value) throws IOException
  41. {
  42. writeln("--" + boundary);
  43. writeln("Content-Disposition: form-data; name=\"" + name + "\"");
  44. writeln();
  45. writeln(value);
  46. }
  47. public void writeParameter (String name, File file) throws IOException
  48. {
  49. String prefix = "Content-Disposition: form-data; name=\"file\"; filename=";
  50. writeln("--" + boundary);
  51. writeln(prefix + '"' + file.getName() + '"');
  52. writeln("Content-Type: text/xml");
  53. writeln();
  54. InputStream source = new FileInputStream(file);
  55. copy(source, stream);
  56. stream.flush();
  57. source.close();
  58. }
  59. void copy (InputStream source, OutputStream destination) throws IOException
  60. {
  61. byte[] buffer = new byte[8192];
  62. int nbytes = 0;
  63. while ((nbytes = source.read(buffer, 0, buffer.length)) >= 0)
  64. {
  65. destination.write(buffer, 0, nbytes);
  66. }
  67. }
  68. void writeln (String s) throws IOException
  69. {
  70. write(s);
  71. writeln();
  72. }
  73. void writeln () throws IOException
  74. {
  75. write('\r');
  76. write('\n');
  77. }
  78. void write (char c) throws IOException
  79. {
  80. stream.write(c);
  81. }
  82. void write (String s) throws IOException
  83. {
  84. stream.write(s.getBytes());
  85. }
  86. URLConnection connection;
  87. OutputStream stream;
  88. String boundary;
  89. }

All that's left is to write a function that uses MultipartPost to make an HTTP POST request to the validator:

  1. import java.io.File;
  2. import java.io.InputStream;
  3. import java.io.IOException;
  4. import java.util.HashMap;
  5. import java.util.Iterator;
  6. import java.util.Map;
  7. import java.util.NoSuchElementException;
  8. /**
  9. * SBMLValidator is simply a container for the static method
  10. * validateSBML(filename, parameters).
  11. */
  12. class SBMLValidator
  13. {
  14. /**
  15. * Validates the given SBML filename (or http:// URL) by calling the
  16. * SBML.org online validator. The results are returned as an
  17. * InputStream whose format may be controlled by setting
  18. * parameters.put("output", ...) to one of: "xml", "xhtml", "json",
  19. * "text" (default: xml).
  20. *
  21. * @return an InputStream containing the validation results.
  22. */
  23. public static InputStream validateSBML (String filename, Map parameters)
  24. throws IOException
  25. {
  26. if (parameters.get("output") == null)
  27. {
  28. parameters.put("output", "xml");
  29. }
  30. MultipartPost post = new MultipartPost("http://sbml.org/validator/");
  31. InputStream result = null;
  32. if (filename.startsWith("http://"))
  33. {
  34. post.writeParameter("url", filename);
  35. }
  36. else
  37. {
  38. post.writeParameter("file", new File(filename));
  39. }
  40. try
  41. {
  42. Iterator iter = parameters.keySet().iterator();
  43. while ( iter.hasNext() )
  44. {
  45. String name = (String) iter.next();
  46. String value = (String) parameters.get(name);
  47. post.writeParameter(name, value);
  48. }
  49. }
  50. catch (NoSuchElementException e)
  51. {
  52. e.printStackTrace();
  53. }
  54. return post.done();
  55. }
  56. }

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:

Problem severities range from zero to three:

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.