Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue 296 setannotation #305

Merged
merged 14 commits into from
Mar 22, 2023
Merged
1 change: 1 addition & 0 deletions examples/c++/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ foreach(example
translateL3Math
unsetAnnotation
unsetNotes
setAnnotation
validateSBML

)
Expand Down
114 changes: 114 additions & 0 deletions examples/c++/setAnnotation.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/**
* Example, reading an SBML file containing an element with provided
* meta id, reading a raw annoation from a file, and adding it to the
* element.
*
*/

#include <iostream>
#include <sbml/SBMLTypes.h>

using namespace std;

XMLNode* parseAnnotation(const std::string& annotationFile)
{
// read file into memory
FILE* file = fopen(annotationFile.c_str(), "r");
fseek(file, 0, SEEK_END);
long length = ftell(file);

fseek(file, 0, SEEK_SET);
char* data = new char[length + 1];

// fill data with zeros
memset(data, 0, length + 1);

fread(data, 1, length, file);
fclose(file);
data[length] = '\0';

// parse the string
XMLNode* xmlnode = XMLNode::convertStringToXMLNode(data);
delete[] data;
return xmlnode;
}

bool setAnnotation(const std::string& sbmlFile, const std::string& metaId,
const std::string& annotationFile, const std::string& outputFile)
{
auto *document = readSBML(sbmlFile.c_str());
if (document->getNumErrors(LIBSBML_SEV_ERROR) > 0)
{
cerr << "Encountered the following SBML errors:" << std::endl;
document->printErrors();
return false;
}

auto* element = document->getElementByMetaId(metaId);
if (!element)
{
cerr << "No element with meta id " << metaId << " found." << std::endl;
return false;
}

auto annotation = parseAnnotation(annotationFile);
if (!annotation)
{
cerr << "the annotation could not be parsed from file: " << annotationFile << "." << std::endl;
return false;
}
auto annotationString = annotation->toXMLString();
element->setAnnotation(annotation, false);

// at this point we'd expect the annotation to be set precisely to what it was
// in the file.


auto resultingAnnotation = element->getAnnotationString();

if (annotationString != resultingAnnotation)
{
cerr << "Annotation was not set correctly." << std::endl;
return false;
}

// write document to output file
writeSBMLToFile(document, outputFile.c_str());

delete document;

return true;
}

int main(int argc, char* argv[])
{
std::string sbmlFile;
std::string metaId;
std::string annotationFile;
std::string outputFile;

if (argc != 5)
{
cout << endl
<< " usage: setAnnotaion <input-filename> <element-meta-id> <annotation-file> <output-file>" << endl
<< " Adds controlled vocabulary term to a species" << endl
<< endl;
return 1;


//sbmlFile = "bm190.xml";
//annotationFile = "annotation.xml";
//metaId = "metaid_0000036";
//outputFile = "bm190_out.xml";

}
else
{
sbmlFile = argv[1];
metaId = argv[2];
annotationFile = argv[3];
outputFile = argv[4];
}

setAnnotation(sbmlFile, metaId, annotationFile, outputFile);
}
40 changes: 30 additions & 10 deletions src/sbml/SBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1249,11 +1249,23 @@ SBase::setIdAttribute (const std::string& sid)
}
}

int
SBase::setAnnotation(const XMLNode* annotation)
{
return SBase::setAnnotation(annotation, true);
}

int
SBase::setAnnotation(const std::string& annotation)
{
return SBase::setAnnotation(annotation, true);
}

/*
* Sets the annotation of this SBML object to a copy of annotation.
*/
int
SBase::setAnnotation (const XMLNode* annotation)
SBase::setAnnotation (const XMLNode* annotation, bool parseRdf)
{
//
// (*NOTICE*)
Expand All @@ -1274,7 +1286,7 @@ SBase::setAnnotation (const XMLNode* annotation)
delete mAnnotation;

// the annotation is an rdf annotation but the object has no metaid
if (RDFAnnotationParser::hasRDFAnnotation(annotation) == true
if (parseRdf && RDFAnnotationParser::hasRDFAnnotation(annotation) == true
&& (RDFAnnotationParser::hasCVTermRDFAnnotation(annotation) == true
|| RDFAnnotationParser::hasHistoryRDFAnnotation(annotation) == true)
&& isSetMetaId() == false)
Expand Down Expand Up @@ -1342,7 +1354,7 @@ SBase::setAnnotation (const XMLNode* annotation)
}


if(mAnnotation != NULL
if(parseRdf && mAnnotation != NULL
&& RDFAnnotationParser::hasCVTermRDFAnnotation(mAnnotation))
{
// parse mAnnotation (if any) and set mCVTerms
Expand All @@ -1351,7 +1363,7 @@ SBase::setAnnotation (const XMLNode* annotation)
mCVTermsChanged = true;
}

if(getLevel() > 2 && mAnnotation != NULL
if(parseRdf && getLevel() > 2 && mAnnotation != NULL
&& RDFAnnotationParser::hasHistoryRDFAnnotation(mAnnotation))
{
// parse mAnnotation (if any) and set mHistory
Expand All @@ -1371,7 +1383,7 @@ SBase::setAnnotation (const XMLNode* annotation)
* Sets the annotation (by string) of this SBML object to a copy of annotation.
*/
int
SBase::setAnnotation (const std::string& annotation)
SBase::setAnnotation (const std::string& annotation, bool parseRdf)
{

int success = LIBSBML_OPERATION_FAILED;
Expand Down Expand Up @@ -1404,7 +1416,7 @@ SBase::setAnnotation (const std::string& annotation)

if(annt_xmln != NULL)
{
success = setAnnotation(annt_xmln);
success = setAnnotation(annt_xmln, parseRdf);
delete annt_xmln;
}
return success;
Expand Down Expand Up @@ -4272,13 +4284,21 @@ SBase::getSBMLNamespaces() const
*/
char*
SBase::toSBML ()
{
return safe_strdup( toSBMLString().c_str() );
}

/*
* @return the partial SBML that describes this SBML object.
*/
std::string SBase::toSBMLString()
{
ostringstream os;
XMLOutputStream stream(os, "UTF-8", false);
ostringstream os;
XMLOutputStream stream(os, "UTF-8", false);

write(stream);
write(stream);

return safe_strdup( os.str().c_str() );
return os.str();
}


Expand Down
115 changes: 113 additions & 2 deletions src/sbml/SBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -1229,6 +1229,54 @@ class LIBSBML_EXTERN SBase
* @see unsetAnnotation()
*/
virtual int setAnnotation (const XMLNode* annotation);

/**
* Sets the value of the "annotation" subelement of this SBML object.
*
* The content of @p annotation is copied, and any previous content of
* this object's "annotation" subelement is deleted.
*
* Whereas the SBase "notes" subelement is a container for content to be
* shown directly to humans, the "annotation" element is a container for
* optional software-generated content @em not meant to be shown to
* humans. Every object derived from SBase can have its own value for
* "annotation". The element's content type is <a target="_blank"
* href="http://www.w3.org/TR/2004/REC-xml-20040204/#elemdecls">XML type
* "any"</a>, allowing essentially arbitrary well-formed XML data
* content.
*
* SBML places a few restrictions on the organization of the content of
* annotations; these are intended to help software tools read and write
* the data as well as help reduce conflicts between annotations added by
* different tools. Please see the SBML specifications for more details.
*
* Call this method will result in any existing content of the
* "annotation" subelement to be discarded. Unless you have taken steps
* to first copy and reconstitute any existing annotations into the @p
* annotation that is about to be assigned, it is likely that performing
* such wholesale replacement is unfriendly towards other software
* applications whose annotations are discarded. An alternative may be
* to use SBase::appendAnnotation(const XMLNode* annotation) or
* SBase::appendAnnotation(const std::string& annotation).
*
* @param annotation an XML structure that is to be used as the new content
* of the "annotation" subelement of this object.
*
* @param parseRdf if true, the annotation will be parsed for RDF content.
* This should only be set, if the RDF follows the subset described in the
* SBML specification.
*
* @copydetails doc_returns_one_success_code
* @li @sbmlconstant{LIBSBML_OPERATION_SUCCESS, OperationReturnValues_t}
*
* @see getAnnotationString()
* @see isSetAnnotation()
* @see setAnnotation(const std::string& annotation)
* @see appendAnnotation(const XMLNode* annotation)
* @see appendAnnotation(const std::string& annotation)
* @see unsetAnnotation()
*/
virtual int setAnnotation(const XMLNode* annotation, bool parseRdf);


/**
Expand Down Expand Up @@ -1262,6 +1310,55 @@ class LIBSBML_EXTERN SBase
*
* @param annotation an XML string that is to be used as the content
* of the "annotation" subelement of this object.
*
* @copydetails doc_returns_success_code
* @li @sbmlconstant{LIBSBML_OPERATION_SUCCESS, OperationReturnValues_t}
* @li @sbmlconstant{LIBSBML_OPERATION_FAILED, OperationReturnValues_t}
*
* @see getAnnotationString()
* @see isSetAnnotation()
* @see setAnnotation(const XMLNode* annotation)
* @see appendAnnotation(const XMLNode* annotation)
* @see appendAnnotation(const std::string& annotation)
* @see unsetAnnotation()
*/
virtual int setAnnotation(const std::string& annotation);

/**
* Sets the value of the "annotation" subelement of this SBML object.
*
* The content of @p annotation is copied, and any previous content of
* this object's "annotation" subelement is deleted.
*
* Whereas the SBase "notes" subelement is a container for content to be
* shown directly to humans, the "annotation" element is a container for
* optional software-generated content @em not meant to be shown to
* humans. Every object derived from SBase can have its own value for
* "annotation". The element's content type is <a target="_blank"
* href="http://www.w3.org/TR/2004/REC-xml-20040204/#elemdecls">XML type
* "any"</a>, allowing essentially arbitrary well-formed XML data
* content.
*
* SBML places a few restrictions on the organization of the content of
* annotations; these are intended to help software tools read and write
* the data as well as help reduce conflicts between annotations added by
* different tools. Please see the SBML specifications for more details.
*
* Call this method will result in any existing content of the
* "annotation" subelement to be discarded. Unless you have taken steps
* to first copy and reconstitute any existing annotations into the @p
* annotation that is about to be assigned, it is likely that performing
* such wholesale replacement is unfriendly towards other software
* applications whose annotations are discarded. An alternative may be
* to use SBase::appendAnnotation(const XMLNode* annotation) or
* SBase::appendAnnotation(const std::string& annotation).
*
* @param annotation an XML string that is to be used as the content
* of the "annotation" subelement of this object.
*
* @param parseRdf if true, the annotation will be parsed for RDF content.
* This should only be set, if the RDF follows the subset described in the
* SBML specification.
*
* @copydetails doc_returns_success_code
* @li @sbmlconstant{LIBSBML_OPERATION_SUCCESS, OperationReturnValues_t}
Expand All @@ -1274,7 +1371,7 @@ class LIBSBML_EXTERN SBase
* @see appendAnnotation(const std::string& annotation)
* @see unsetAnnotation()
*/
virtual int setAnnotation (const std::string& annotation);
virtual int setAnnotation (const std::string& annotation, bool parseRdf);


/**
Expand Down Expand Up @@ -2313,7 +2410,9 @@ s.setNotes("<body xmlns='http://www.w3.org/1999/xhtml'><p>here is my note</p></b

/**
* Returns a string consisting of a partial SBML corresponding to just
* this object.
* this object.
*
* The string is owned by the caller and has to be freed manualy.
*
* @return the partial SBML that describes this SBML object.
*
Expand All @@ -2323,6 +2422,18 @@ s.setNotes("<body xmlns='http://www.w3.org/1999/xhtml'><p>here is my note</p></b
*/
char* toSBML();

/**
* Returns a string consisting of a partial SBML corresponding to just
* this object.
*
* @return the partial SBML that describes this SBML object.
*
* @warning <span class="warning">This is primarily provided for testing
* and debugging purposes. It may be removed in a future version of
* libSBML.</span>
*/
std::string toSBMLString();


/**
* Returns this element as an XMLNode.
Expand Down