1 /**
2 * @file SBase.cpp
3 * @brief Implementation of SBase, the base object of all SBML objects.
4 * @author Ben Bornstein
5 *
6 * <!--------------------------------------------------------------------------
7 * This file is part of libSBML. Please visit http://sbml.org for more
8 * information about SBML, and the latest version of libSBML.
9 *
10 * Copyright (C) 2020 jointly by the following organizations:
11 * 1. California Institute of Technology, Pasadena, CA, USA
12 * 2. University of Heidelberg, Heidelberg, Germany
13 * 3. University College London, London, UK
14 *
15 * Copyright (C) 2019 jointly by the following organizations:
16 * 1. California Institute of Technology, Pasadena, CA, USA
17 * 2. University of Heidelberg, Heidelberg, Germany
18 *
19 * Copyright (C) 2013-2018 jointly by the following organizations:
20 * 1. California Institute of Technology, Pasadena, CA, USA
21 * 2. EMBL European Bioinformatics Institute (EMBL-EBI), Hinxton, UK
22 * 3. University of Heidelberg, Heidelberg, Germany
23 *
24 * Copyright (C) 2009-2013 jointly by the following organizations:
25 * 1. California Institute of Technology, Pasadena, CA, USA
26 * 2. EMBL European Bioinformatics Institute (EMBL-EBI), Hinxton, UK
27 *
28 * Copyright (C) 2006-2008 by the California Institute of Technology,
29 * Pasadena, CA, USA
30 *
31 * Copyright (C) 2002-2005 jointly by the following organizations:
32 * 1. California Institute of Technology, Pasadena, CA, USA
33 * 2. Japan Science and Technology Agency, Japan
34 *
35 * This library is free software; you can redistribute it and/or modify it
36 * under the terms of the GNU Lesser General Public License as published by
37 * the Free Software Foundation. A copy of the license agreement is provided
38 * in the file named "LICENSE.txt" included with this software distribution
39 * and also available online as http://sbml.org/software/libsbml/license.html
40 * ---------------------------------------------------------------------- -->*/
41
42 #include <sstream>
43
44 #include <sbml/xml/XMLError.h>
45 #include <sbml/xml/XMLErrorLog.h>
46 #include <sbml/xml/XMLOutputStream.h>
47 #include <sbml/xml/XMLInputStream.h>
48 #include <sbml/xml/XMLToken.h>
49 #include <sbml/xml/XMLNode.h>
50
51 #include <sbml/util/util.h>
52
53 #include <sbml/annotation/RDFAnnotation.h>
54
55 #include <sbml/KineticLaw.h>
56 #include <sbml/SBMLError.h>
57 #include <sbml/SBMLErrorLog.h>
58 #include <sbml/SBMLDocument.h>
59 #include <sbml/Model.h>
60 #include <sbml/ListOf.h>
61 #include <sbml/SBase.h>
62
63 #include <sbml/util/IdList.h>
64 #include <sbml/util/IdentifierTransformer.h>
65 #include <sbml/extension/SBasePlugin.h>
66 #include <sbml/extension/ISBMLExtensionNamespaces.h>
67 #include <sbml/extension/SBMLExtensionRegistry.h>
68 #include <sbml/extension/SBMLExtensionException.h>
69 #include <sbml/util/CallbackRegistry.h>
70
71 /** @cond doxygenIgnored */
72 using namespace std;
73 /** @endcond */
74
75 LIBSBML_CPP_NAMESPACE_BEGIN
76
77 #ifdef __cplusplus
78
79 /** @cond doxygenLibsbmlInternal */
80 /*
81 * Used by the Destructor to delete each item in mPlugins.
82 */
83 struct DeletePluginEntity : public unary_function<SBasePlugin*, void>
84 {
operator ()DeletePluginEntity85 void operator() (SBasePlugin* sb) { delete sb; }
86 };
87
88
89 /*
90 * Used by the Copy Constructor to clone each item in mPlugins.
91 */
92 struct ClonePluginEntity : public unary_function<SBasePlugin*, SBasePlugin*>
93 {
operator ()ClonePluginEntity94 SBasePlugin* operator() (SBasePlugin* sb) {
95 if (!sb) return NULL;
96 return sb->clone();
97 }
98 };
99 /** @endcond */
100
101
102 SBase*
getElementBySId(const std::string & id)103 SBase::getElementBySId(const std::string& id)
104 {
105 if (id.empty()) return NULL;
106 return getElementFromPluginsBySId(id);
107 }
108
109 const SBase*
getElementBySId(const std::string & id) const110 SBase::getElementBySId(const std::string& id) const
111 {
112 SBase* thus = const_cast<SBase*>(this);
113 return thus->getElementBySId(id);
114 }
115
116
117 SBase*
getElementByMetaId(const std::string & metaid)118 SBase::getElementByMetaId(const std::string& metaid)
119 {
120 if (metaid.empty()) return NULL;
121 return getElementFromPluginsByMetaId(metaid);
122 }
123
124 const SBase*
getElementByMetaId(const std::string & metaid) const125 SBase::getElementByMetaId(const std::string& metaid) const
126 {
127 SBase* thus = const_cast<SBase*>(this);
128 return thus->getElementByMetaId(metaid);
129 }
130
131 List*
getAllElements(ElementFilter * filter)132 SBase::getAllElements(ElementFilter *filter)
133 {
134 return getAllElementsFromPlugins(filter);
135 }
136
137 void
renameSIdRefs(const std::string & oldid,const std::string & newid)138 SBase::renameSIdRefs(const std::string& oldid, const std::string& newid)
139 {
140 //No SIdRefs in SBase, but plugins might have some.
141 for (unsigned int p = 0; p < getNumPlugins(); p++)
142 {
143 getPlugin(p)->renameSIdRefs(oldid, newid);
144 }
145 }
146
147 void
renameMetaIdRefs(const std::string & oldid,const std::string & newid)148 SBase::renameMetaIdRefs(const std::string& oldid, const std::string& newid)
149 {
150 //The only thing in core that uses metaids is the annotation element. If the metaid of an SBase object is changed, and the annotation was in the 'sbml-official' form, the rdf:about will be changed automatically, so this function doesn't need to do anything. However, we do need the function itself so that packages can extend it for their own purposes (such as comp, with its 'metaIdRef' attributes, and annot, which one would imagine would use something similar).
151
152 //The following code is here in case you want a hacky solution for your own package:
153 /*
154 if (oldid == newid) return;
155 if (isSetAnnotation()) {
156 string oldrdfabout = "rdf:about=\"#" + oldid;
157 string newrdfabout = "rdf:about=\"#" + newid;
158 string annot = getAnnotationString();
159 size_t place = annot.find(oldrdfabout);
160 while (place != string::npos) {
161 annot.replace(place, oldrdfabout.size(), newrdfabout);
162 place = annot.find(oldrdfabout);
163 }
164 }
165 */
166 //We also need to check the plugins:
167 for (unsigned int p = 0; p < getNumPlugins(); p++)
168 {
169 getPlugin(p)->renameMetaIdRefs(oldid, newid);
170 }
171 }
172
173 void
renameUnitSIdRefs(const std::string & oldid,const std::string & newid)174 SBase::renameUnitSIdRefs(const std::string& oldid, const std::string& newid)
175 {
176 //No UnitSIdRefs in SBase, either. But check the plugins.
177 for (unsigned int p = 0; p < getNumPlugins(); p++)
178 {
179 getPlugin(p)->renameUnitSIdRefs(oldid, newid);
180 }
181 }
182
183 /** @cond doxygenLibsbmlInternal */
184 SBase*
getElementFromPluginsBySId(std::string id)185 SBase::getElementFromPluginsBySId(std::string id)
186 {
187 for (size_t i=0; i < mPlugins.size(); i++)
188 {
189 SBase* subObj = mPlugins[i]->getElementBySId(id);
190 if (subObj != NULL) return subObj;
191 }
192 return NULL;
193 }
194 /** @endcond */
195
196
197 /** @cond doxygenLibsbmlInternal */
198 SBase*
getElementFromPluginsByMetaId(std::string metaid)199 SBase::getElementFromPluginsByMetaId(std::string metaid)
200 {
201 for (size_t i=0; i < mPlugins.size(); i++)
202 {
203 SBase* subObj = mPlugins[i]->getElementByMetaId(metaid);
204 if (subObj != NULL) return subObj;
205 }
206 return NULL;
207 }
208 /** @endcond */
209
210
211 /** @cond doxygenLibsbmlInternal */
hasNonstandardIdentifierBeginningWith(const std::string &)212 bool SBase::hasNonstandardIdentifierBeginningWith(const std::string&)
213 {
214 return false;
215 }
216 /** @endcond */
217
218
219 /** @cond doxygenLibsbmlInternal */
220 int
prependStringToAllIdentifiers(const std::string & prefix)221 SBase::prependStringToAllIdentifiers(const std::string& prefix)
222 {
223 int ret;
224
225 if (isSetMetaId())
226 {
227 ret = setMetaId(prefix + getMetaId());
228 if (ret != LIBSBML_OPERATION_SUCCESS)
229 {
230 return ret;
231 }
232 }
233
234 for (unsigned int p = 0; p < getNumPlugins(); p++)
235 {
236 ret = getPlugin(p)->prependStringToAllIdentifiers(prefix);
237 if (ret != LIBSBML_OPERATION_SUCCESS)
238 {
239 return ret;
240 }
241 }
242
243
244 // Must use 'IdAttribute' functions since some elements like rules
245 // return a different value for 'Id' functions alone.
246
247 if (isSetIdAttribute())
248 {
249 ret = setIdAttribute(prefix + getIdAttribute());
250 if (ret != LIBSBML_OPERATION_SUCCESS)
251 {
252 return ret;
253 }
254 }
255
256 return LIBSBML_OPERATION_SUCCESS;
257 }
258 /** @endcond */
259
260
261 /** @cond doxygenLibsbmlInternal */
262 int
transformIdentifiers(IdentifierTransformer * idTransformer)263 SBase::transformIdentifiers(IdentifierTransformer* idTransformer)
264 {
265 int ret = LIBSBML_OPERATION_SUCCESS;
266
267 // call plugins
268 for (unsigned int p = 0; p < getNumPlugins(); ++p)
269 {
270 ret = getPlugin(p)->transformIdentifiers(idTransformer);
271 if (ret != LIBSBML_OPERATION_SUCCESS)
272 {
273 return ret;
274 }
275 }
276
277 // call transformer
278 if (idTransformer != NULL)
279 {
280 ret = idTransformer->transform(this);
281 if (ret != LIBSBML_OPERATION_SUCCESS)
282 {
283 return ret;
284 }
285 }
286
287 return ret;
288 }
289 /** @endcond */
290
291 List*
getAllElementsFromPlugins(ElementFilter * filter)292 SBase::getAllElementsFromPlugins(ElementFilter *filter)
293 {
294 List* ret = new List();
295 for (size_t i=0; i < mPlugins.size(); i++)
296 {
297 List* sublist = mPlugins[i]->getAllElements(filter);
298 if (sublist != NULL)
299 {
300 if (sublist->getSize() > 0)
301 ret->transferFrom(sublist);
302 delete sublist;
303 }
304 }
305 return ret;
306 }
307
308
309 /** @cond doxygenLibsbmlInternal */
310 /*
311 * Creates a new SBase object with the given level and version.
312 * Only subclasses may create SBase objects.
313 */
SBase(unsigned int level,unsigned int version)314 SBase::SBase (unsigned int level, unsigned int version) :
315 mId ( "" )
316 , mName ( "" )
317 , mMetaId ( "" )
318 , mNotes ( NULL )
319 , mAnnotation( NULL )
320 , mSBML ( NULL )
321 , mSBMLNamespaces (NULL)
322 , mUserData(NULL)
323 , mSBOTerm ( -1 )
324 , mLine ( 0 )
325 , mColumn ( 0 )
326 , mParentSBMLObject (NULL)
327 , mCVTerms ( NULL )
328 , mHistory ( NULL )
329 , mHasBeenDeleted (false)
330 , mEmptyString ("")
331 , mURI("")
332 , mHistoryChanged (false)
333 , mCVTermsChanged (false)
334 , mAttributesOfUnknownPkg()
335 , mAttributesOfUnknownDisabledPkg()
336 , mElementsOfUnknownPkg()
337 , mElementsOfUnknownDisabledPkg()
338 {
339 mSBMLNamespaces = new SBMLNamespaces(level, version);
340
341 //
342 // Sets the XMLNS URI of corresponding SBML Level/Version to
343 // the element namespace (mURI) of this object.
344 //
345 // (NOTES) Package developers must (1) override the mSBMLNamespaces of this
346 // object with the corresponding SBMLExtensionNamespaces (template)
347 // class in their packages and (2) override the element namespace (mURI)
348 // of this object with the corresponding package's URI in the constructor
349 // of SBase derived class in thier packages.
350 //
351 setElementNamespace(mSBMLNamespaces->getURI());
352 }
353
354
355
356 /*
357 * Creates a new SBase object with the given SBMLNamespaces.
358 * Only subclasses may create SBase objects.
359 */
SBase(SBMLNamespaces * sbmlns)360 SBase::SBase (SBMLNamespaces *sbmlns) :
361 mId ( "" )
362 , mName ( "" )
363 , mMetaId ( "" )
364 , mNotes ( NULL )
365 , mAnnotation( NULL )
366 , mSBML ( NULL )
367 , mSBMLNamespaces (NULL)
368 , mUserData(NULL)
369 , mSBOTerm ( -1 )
370 , mLine ( 0 )
371 , mColumn ( 0 )
372 , mParentSBMLObject (NULL)
373 , mCVTerms ( NULL )
374 , mHistory ( NULL )
375 , mHasBeenDeleted (false)
376 , mEmptyString ("")
377 , mURI("")
378 , mHistoryChanged (false)
379 , mCVTermsChanged (false)
380 , mAttributesOfUnknownPkg()
381 , mAttributesOfUnknownDisabledPkg()
382 , mElementsOfUnknownPkg()
383 , mElementsOfUnknownDisabledPkg()
384 {
385 if (!sbmlns)
386 {
387 std::string err("SBase::SBase(SBMLNamespaces*, SBaseExtensionPoint*) : SBMLNamespaces is null");
388 throw SBMLConstructorException(err);
389 }
390 mSBMLNamespaces = sbmlns->clone();
391
392 //
393 // Sets the XMLNS URI of corresponding SBML Level/Version to
394 // the element namespace (mURI) of this object.
395 //
396 // (NOTES) Package developers must override the element namespace (mURI)
397 // of this object with the corresponding package's URI in the constructor
398 // of SBase derived class in thier packages.
399 //
400
401 #if 0
402 cout << "[DEBUG] SBase::SBase(SBMLNamespaces*,...) " << static_cast<SBMLNamespaces>(*mSBMLNamespaces).getURI() << endl;
403 #endif
404
405 setElementNamespace(static_cast<SBMLNamespaces>(*mSBMLNamespaces).getURI());
406 }
407 /** @endcond */
408
409
410 /** @cond doxygenLibsbmlInternal */
411 /*
412 * Copy constructor. Creates a copy of this SBase object.
413 */
SBase(const SBase & orig)414 SBase::SBase(const SBase& orig)
415 : mId (orig.mId)
416 , mName (orig.mName)
417 , mMetaId (orig.mMetaId)
418 , mNotes (NULL)
419 , mAnnotation (NULL)
420 , mSBML (NULL)
421 , mSBMLNamespaces(NULL)
422 , mUserData(orig.mUserData)
423 , mSBOTerm(orig.mSBOTerm)
424 , mLine(orig.mLine)
425 , mColumn(orig.mColumn)
426 , mParentSBMLObject(NULL)
427 , mCVTerms(NULL)
428 , mHistory(NULL)
429 , mHasBeenDeleted(false)
430 , mEmptyString()
431 , mPlugins(orig.mPlugins.size())
432 , mDisabledPlugins()
433 , mURI(orig.mURI)
434 , mHistoryChanged(orig.mHistoryChanged)
435 , mCVTermsChanged(orig.mCVTermsChanged)
436 , mAttributesOfUnknownPkg (orig.mAttributesOfUnknownPkg)
437 , mAttributesOfUnknownDisabledPkg (orig.mAttributesOfUnknownDisabledPkg)
438 , mElementsOfUnknownPkg (orig.mElementsOfUnknownPkg)
439 , mElementsOfUnknownDisabledPkg (orig.mElementsOfUnknownDisabledPkg)
440 {
441 if(orig.mNotes != NULL)
442 this->mNotes = new XMLNode(*const_cast<SBase&>(orig).getNotes());
443
444 if(orig.mAnnotation != NULL)
445 this->mAnnotation = new XMLNode(*const_cast<SBase&>(orig).mAnnotation);
446
447 if(orig.getSBMLNamespaces() != NULL)
448 this->mSBMLNamespaces =
449 new SBMLNamespaces(*const_cast<SBase&>(orig).getSBMLNamespaces());
450
451 if(orig.mCVTerms != NULL)
452 {
453 this->mCVTerms = new List();
454 unsigned int i,iMax = orig.mCVTerms->getSize();
455 for(i = 0; i < iMax; ++i)
456 {
457 this->mCVTerms
458 ->add(static_cast<CVTerm*>(orig.mCVTerms->get(i))->clone());
459 }
460 }
461
462 if (orig.mHistory != NULL)
463 {
464 this->mHistory = orig.mHistory->clone();
465 }
466
467 transform( orig.mPlugins.begin(), orig.mPlugins.end(),
468 mPlugins.begin(), ClonePluginEntity() );
469 for (size_t i=0; i < mPlugins.size(); ++i)
470 {
471 mPlugins[i]->connectToParent(this);
472 }
473
474 }
475 /** @endcond */
476
477
478 /*
479 * Destroy this SBase object.
480 */
~SBase()481 SBase::~SBase ()
482 {
483 if (mNotes != NULL) delete mNotes;
484 if (mAnnotation != NULL) delete mAnnotation;
485 if (mSBMLNamespaces != NULL) delete mSBMLNamespaces;
486 if (mCVTerms != NULL)
487 {
488 unsigned int size = mCVTerms->getSize();
489 while (size > 0)
490 {
491 delete static_cast<CVTerm*>( mCVTerms->remove(0) );
492 size--;
493 }
494 delete mCVTerms;
495 }
496 if (mHistory != NULL) delete mHistory;
497 mHasBeenDeleted = true;
498
499 for_each( mPlugins.begin(), mPlugins.end(), DeletePluginEntity() );
500 deleteDisabledPlugins(false);
501 }
502
503 /*
504 * Assignment operator
505 */
operator =(const SBase & rhs)506 SBase& SBase::operator=(const SBase& rhs)
507 {
508 if(&rhs!=this)
509 {
510 this->mId = rhs.mId;
511 this->mName = rhs.mName;
512 this->mMetaId = rhs.mMetaId;
513
514 delete this->mNotes;
515
516 if(rhs.mNotes != NULL)
517 this->mNotes = new XMLNode(*const_cast<SBase&>(rhs).getNotes());
518 else
519 this->mNotes = NULL;
520
521 delete this->mAnnotation;
522
523 if(rhs.mAnnotation != NULL)
524 this->mAnnotation = new XMLNode(*const_cast<SBase&>(rhs).mAnnotation);
525 else
526 this->mAnnotation = NULL;
527
528 this->mSBML = rhs.mSBML;
529 this->mSBOTerm = rhs.mSBOTerm;
530 this->mLine = rhs.mLine;
531 this->mColumn = rhs.mColumn;
532 this->mParentSBMLObject = rhs.mParentSBMLObject;
533 this->mUserData = rhs.mUserData;
534 this->mAttributesOfUnknownPkg = rhs.mAttributesOfUnknownPkg;
535 this->mAttributesOfUnknownDisabledPkg = rhs.mAttributesOfUnknownDisabledPkg;
536 this->mElementsOfUnknownPkg = rhs.mElementsOfUnknownPkg;
537 this->mElementsOfUnknownDisabledPkg = rhs.mElementsOfUnknownDisabledPkg;
538
539 delete this->mSBMLNamespaces;
540
541 if(rhs.mSBMLNamespaces != NULL)
542 this->mSBMLNamespaces =
543 new SBMLNamespaces(*const_cast<SBase&>(rhs).mSBMLNamespaces);
544 else
545 this->mSBMLNamespaces = NULL;
546
547
548 if(this->mCVTerms != NULL)
549 {
550 unsigned int size = this->mCVTerms->getSize();
551 while (size--) delete static_cast<CVTerm*>( this->mCVTerms->remove(0) );
552 delete this->mCVTerms;
553 }
554
555 if(rhs.mCVTerms != NULL)
556 {
557 this->mCVTerms = new List();
558 unsigned int i,iMax = rhs.mCVTerms->getSize();
559 for(i = 0; i < iMax; ++i)
560 {
561 this->mCVTerms
562 ->add(static_cast<CVTerm*>(rhs.mCVTerms->get(i))->clone());
563 }
564 }
565 else
566 {
567 this->mCVTerms = NULL;
568 }
569
570 delete this->mHistory;
571 if (rhs.mHistory != NULL)
572 {
573 this->mHistory = rhs.mHistory->clone();
574 }
575 else
576 {
577 this->mHistory = NULL;
578 }
579
580 this->mHasBeenDeleted = rhs.mHasBeenDeleted;
581 this->mURI = rhs.mURI;
582 this->mHistoryChanged = rhs.mHistoryChanged;
583 this->mCVTermsChanged = rhs.mCVTermsChanged;
584
585 for_each( mPlugins.begin(), mPlugins.end(), DeletePluginEntity() );
586 mPlugins.resize( rhs.mPlugins.size() );
587 transform( rhs.mPlugins.begin(), rhs.mPlugins.end(),
588 mPlugins.begin(), ClonePluginEntity() );
589 }
590
591 return *this;
592 }
593
594
595 /** @cond doxygenLibsbmlInternal */
596 /*
597 * Loads SBasePlugin derived objects corresponding to the URIs contained
598 * in the given SBMLNamespaces (if any) for package extension.
599 */
600 void
loadPlugins(SBMLNamespaces * sbmlns)601 SBase::loadPlugins(SBMLNamespaces *sbmlns)
602 {
603 if (!sbmlns) return;
604
605 //
606 // (EXTENSION)
607 //
608 XMLNamespaces *xmlns = sbmlns->getNamespaces();
609
610 if (xmlns)
611 {
612 int numxmlns= xmlns->getLength();
613 SBaseExtensionPoint extPoint(getPackageName(), getTypeCode(), getElementName());
614 SBaseExtensionPoint genericPoint("all", SBML_GENERIC_SBASE);
615
616 for (int i=0; i < numxmlns; i++)
617 {
618 const std::string &uri = xmlns->getURI(i);
619 const SBMLExtension* sbmlext = SBMLExtensionRegistry::getInstance().getExtensionInternal(uri);
620
621 if (sbmlext && sbmlext->isEnabled())
622 {
623 #if 0
624 cout << "[DEBUG] SBase::loadPlugins() " << uri
625 << " is registered in "
626 << SBMLTypeCode_toString(getTypeCode(), getPackageName().c_str())
627 << endl;
628 #endif
629 const std::string &prefix = xmlns->getPrefix(i);
630 const SBasePluginCreatorBase* sbPluginCreator = sbmlext->getSBasePluginCreator(extPoint);
631
632 if (sbPluginCreator == NULL)
633 {
634 sbPluginCreator = sbmlext->getSBasePluginCreator(genericPoint);
635 }
636
637 if (sbPluginCreator)
638 {
639 // (debug)
640 //cout << "sbPluginCreator " << sbPluginCreator << endl;
641 //sbPluginCreator->createPlugin(uri,prefix);
642 // (debug)
643 SBasePlugin* entity = sbPluginCreator->createPlugin(uri,prefix,xmlns);
644 entity->connectToParent(this);
645 mPlugins.push_back(entity);
646 }
647 #if 0
648 else
649 {
650 cout << "[DEBUG] SBase::loadPlugins() " << uri
651 << " is not registered in "
652 << SBMLTypeCode_toString(getTypeCode(), getPackageName().c_str())
653 << endl;
654 }
655 #endif
656 }
657 else
658 {
659 //
660 // (NOTE)
661 //
662 // SBMLExtensionException should be thrown if the corresponding package
663 // extension is not loaded.
664 // However, currently, no idea how to check if the uri belongs to extension
665 // package or not (e.g. XHTML namespace or other namespace can be given).
666 //
667 #if 0
668 std::ostringstream errMsg;
669
670 if (sbmlext)
671 {
672 errMsg << "Package \"" << sbmlext->getName() << "\" (" << uri << ") for \"<"
673 << SBMLTypeCode_toString(getTypeCode(), getPackageName().c_str())
674 << ">\" element is disabled.";
675 }
676 else
677 {
678 errMsg << "Package \"" << uri << "\" for \"<"
679 << SBMLTypeCode_toString(getTypeCode(), getPackageName().c_str())
680 << ">\" element is not supported.";
681 }
682
683 throw SBMLExtensionException(errMsg.str());
684 #endif
685 }
686 }
687 }
688 }
689 /** @endcond */
690
691
692 /*
693 * @return the metaid of this SBML object.
694 */
695 const string&
getMetaId() const696 SBase::getMetaId () const
697 {
698 return mMetaId;
699 }
700
701
702 /*
703 * @return the metaid of this SBML object.
704 */
705 string&
getMetaId()706 SBase::getMetaId ()
707 {
708 return mMetaId;
709 }
710
711
712 /*
713 * @return the id of this SBML object.
714 */
715 const string&
getId() const716 SBase::getId () const
717 {
718 if (getLevel() == 3 && getVersion() > 1)
719 {
720 return mId;
721 }
722 else
723 {
724 return mEmptyString;
725 }
726 }
727
728
729
730 /*
731 * @return the name of this SBML object.
732 */
733 const string&
getName() const734 SBase::getName () const
735 {
736 if (getLevel() == 3 && getVersion() > 1)
737 {
738 return mName;
739 }
740 else
741 {
742 return mEmptyString;
743 }
744 }
745
746 const string&
getIdAttribute() const747 SBase::getIdAttribute () const
748 {
749 return mId;
750 }
751
752
753 /*
754 * @return the notes of this SBML object.
755 */
756 XMLNode*
getNotes()757 SBase::getNotes()
758 {
759 return mNotes;
760 }
761
762
763 XMLNode*
getNotes() const764 SBase::getNotes() const
765 {
766 return mNotes;
767 }
768
769
770 /*
771 * @return the notes of this SBML object by string.
772 */
773 std::string
getNotesString()774 SBase::getNotesString()
775 {
776 return XMLNode::convertXMLNodeToString(mNotes);
777 }
778
779
780 std::string
getNotesString() const781 SBase::getNotesString() const
782 {
783 return XMLNode::convertXMLNodeToString(mNotes);
784 }
785
786
787 /*
788 * @return the annotation of this SBML object.
789 */
790 XMLNode*
getAnnotation()791 SBase::getAnnotation ()
792 {
793 syncAnnotation();
794
795 return mAnnotation;
796 }
797
798
799 XMLNode*
getAnnotation() const800 SBase::getAnnotation () const
801 {
802 return const_cast<SBase *>(this)->getAnnotation();
803 }
804
805
806 /*
807 * @return the annotation of this SBML object by string.
808 */
809 std::string
getAnnotationString()810 SBase::getAnnotationString ()
811 {
812 return XMLNode::convertXMLNodeToString(getAnnotation());
813 }
814
815
816 std::string
getAnnotationString() const817 SBase::getAnnotationString () const
818 {
819 return XMLNode::convertXMLNodeToString(getAnnotation());
820 }
821
822
823 /** @cond doxygenLibsbmlInternal */
824 std::string
getURI() const825 SBase::getURI() const
826 {
827 const string &package = getPackageName();
828 const SBMLDocument* doc = getSBMLDocument();
829
830 if (doc == NULL)
831 return getElementNamespace();
832
833 SBMLNamespaces* sbmlns = doc->getSBMLNamespaces();
834
835 if (sbmlns == NULL)
836 return getElementNamespace();
837
838 if (package == "" || package == "core")
839 return getElementNamespace();
840
841 string packageURI = sbmlns->getNamespaces()->getURI(package);
842 if (!packageURI.empty())
843 return packageURI;
844
845 return getElementNamespace();
846 }
847 /** @endcond */
848
849
850 /** @cond doxygenLibsbmlInternal */
851 /*
852 * This function does nothing itself--subclasses with ASTNode subelements must override this function.
853 */
854 void
replaceSIDWithFunction(const std::string &,const ASTNode *)855 SBase::replaceSIDWithFunction(const std::string&, const ASTNode*)
856 {
857 }
858 /** @endcond */
859
860 /** @cond doxygenLibsbmlInternal */
861 /*
862 * This function does nothing itself--subclasses with ASTNode subelements must override this function.
863 */
864 void
divideAssignmentsToSIdByFunction(const std::string &,const ASTNode *)865 SBase::divideAssignmentsToSIdByFunction(const std::string&, const ASTNode*)
866 {
867 }
868 /** @endcond */
869
870 /** @cond doxygenLibsbmlInternal */
871 void
multiplyAssignmentsToSIdByFunction(const std::string &,const ASTNode *)872 SBase::multiplyAssignmentsToSIdByFunction(const std::string&, const ASTNode*)
873 {
874 }
875 /** @endcond */
876
877 void *
getUserData() const878 SBase::getUserData() const
879 {
880 return this->mUserData;
881 }
882
883
884 int
setUserData(void * userData)885 SBase::setUserData(void *userData)
886 {
887 this->mUserData = userData;
888 if (userData == NULL && mUserData == NULL)
889 {
890 return LIBSBML_OPERATION_SUCCESS;
891 }
892 else if (mUserData != NULL)
893 {
894 return LIBSBML_OPERATION_SUCCESS;
895 }
896 else
897 {
898 return LIBSBML_OPERATION_FAILED;
899 }
900 }
901
902 bool
isSetUserData() const903 SBase::isSetUserData() const
904 {
905 if (mUserData != NULL)
906 {
907 return true;
908 }
909 else
910 {
911 return false;
912 }
913 }
914
915 int
unsetUserData()916 SBase::unsetUserData()
917 {
918 this->mUserData = NULL;
919 if (mUserData == NULL)
920 {
921 return LIBSBML_OPERATION_SUCCESS;
922 }
923 else
924 {
925 return LIBSBML_OPERATION_FAILED;
926 }
927 }
928
929 /*
930 * @return the Namespaces associated with this SBML object
931 */
932 XMLNamespaces*
getNamespaces() const933 SBase::getNamespaces() const
934 {
935 if (mSBML != NULL)
936 return mSBML->getSBMLNamespaces()->getNamespaces();
937 if (mSBMLNamespaces != NULL)
938 return mSBMLNamespaces->getNamespaces();
939 return NULL;
940 }
941
942
943 /*
944 * @return the parent SBMLDocument of this SBML object.
945 */
946 const SBMLDocument*
getSBMLDocument() const947 SBase::getSBMLDocument () const
948 {
949 if (mSBML != NULL)
950 {
951 // if the doc object has been deleted the pointer is
952 // still valid but points to nothing
953 try
954 {
955 if (mSBML->getHasBeenDeleted())
956 {
957 return NULL;
958 }
959 else
960 {
961 return mSBML;
962 }
963 }
964 catch ( ... )
965 {
966 return NULL;
967 }
968 }
969
970 return mSBML;
971 }
972
973 /*
974 * @return the parent SBMLDocument of this SBML object.
975 */
976 SBMLDocument*
getSBMLDocument()977 SBase::getSBMLDocument ()
978 {
979 if (mSBML != NULL)
980 {
981 // if the doc object has been deleted the pointer is
982 // still valid but points to nothing
983 try
984 {
985 if (mSBML->getHasBeenDeleted())
986 {
987 return NULL;
988 }
989 else
990 {
991 return mSBML;
992 }
993 }
994 catch ( ... )
995 {
996 return NULL;
997 }
998 }
999 return mSBML;
1000 }
1001 SBase*
getParentSBMLObject()1002 SBase::getParentSBMLObject ()
1003 {
1004 if (mParentSBMLObject != NULL)
1005 {
1006 // if the parent object has been deleted the pointer is
1007 // still valid but points to nothing
1008 try
1009 {
1010 if (mParentSBMLObject->getHasBeenDeleted())
1011 {
1012 return NULL;
1013 }
1014 else
1015 {
1016 return mParentSBMLObject;
1017 }
1018 }
1019 catch ( ... )
1020 {
1021 return NULL;
1022 }
1023 }
1024
1025 return mParentSBMLObject;
1026 }
1027
1028 const SBase*
getParentSBMLObject() const1029 SBase::getParentSBMLObject () const
1030 {
1031 if (mParentSBMLObject != NULL)
1032 {
1033 // if the parent object has been deleted the pointer is
1034 // still valid but points to nothing
1035 try
1036 {
1037 if (mParentSBMLObject->getHasBeenDeleted())
1038 {
1039 return NULL;
1040 }
1041 else
1042 {
1043 return mParentSBMLObject;
1044 }
1045 }
1046 catch ( ... )
1047 {
1048 return NULL;
1049 }
1050 }
1051
1052 return mParentSBMLObject;
1053 }
1054
1055 /*
1056 * @return the sboTerm as an integer. If not set,
1057 * sboTerm will be -1.
1058 */
1059 int
getSBOTerm() const1060 SBase::getSBOTerm () const
1061 {
1062 return mSBOTerm;
1063 }
1064
1065
1066 /*
1067 * @return the sboTerm as a string. If not set,
1068 * return an empty string.
1069 */
1070 std::string
getSBOTermID() const1071 SBase::getSBOTermID () const
1072 {
1073 return SBO::intToString(mSBOTerm);
1074 }
1075
1076
1077 /*
1078 * @return the sboTerm as a identoifoers.org url. If not set,
1079 * return an empty string.
1080 */
1081 std::string
getSBOTermAsURL() const1082 SBase::getSBOTermAsURL () const
1083 {
1084 std::string result = "";
1085
1086 if ( SBO::checkTerm(mSBOTerm) )
1087 {
1088 ostringstream stream;
1089 stream << "http://identifiers.org/biomodels.sbo/SBO:";
1090 stream << setw(7) << setfill('0') << mSBOTerm;
1091 result = stream.str();
1092 }
1093
1094 return result;
1095 }
1096
1097
1098 /*
1099 * @return the line number of this SBML object.
1100 */
1101 unsigned int
getLine() const1102 SBase::getLine () const
1103 {
1104 return mLine;
1105 }
1106
1107
1108 /*
1109 * @return the column number of this SBML object.
1110 */
1111 unsigned int
getColumn() const1112 SBase::getColumn () const
1113 {
1114 return mColumn;
1115 }
1116
1117
1118 ModelHistory*
getModelHistory() const1119 SBase::getModelHistory() const
1120 {
1121 return mHistory;
1122 }
1123
1124 ModelHistory*
getModelHistory()1125 SBase::getModelHistory()
1126 {
1127 return mHistory;
1128 }
1129
1130
1131 /*
1132 * @return @c true if the metaid of this SBML object is set, false
1133 * otherwise.
1134 */
1135 bool
isSetMetaId() const1136 SBase::isSetMetaId () const
1137 {
1138 return (mMetaId.empty() == false);
1139 }
1140
1141
1142 /*
1143 * NOTE: THIS IS FOR BACKWARD COMPATABILITY REASONS
1144 *
1145 * @return @c true if the id of this SBML object is set, false
1146 * otherwise.
1147 */
1148 bool
isSetId() const1149 SBase::isSetId () const
1150 {
1151 return (getId().empty() == false);
1152 }
1153
1154
1155 /*
1156 * NOTE: THIS IS FOR BACKWARD COMPATABILITY REASONS
1157 *
1158 * @return @c true if the name of this SBML object is set, false
1159 * otherwise.
1160 */
1161 bool
isSetName() const1162 SBase::isSetName () const
1163 {
1164 return (getName().empty() == false);
1165 }
1166
1167
1168 bool
isSetIdAttribute() const1169 SBase::isSetIdAttribute () const
1170 {
1171 return (mId.empty() == false);
1172 }
1173
1174
1175 /*
1176 * @return @c true if the notes of this SBML object is set, false
1177 * otherwise.
1178 */
1179 bool
isSetNotes() const1180 SBase::isSetNotes () const
1181 {
1182 return (mNotes != NULL);
1183 }
1184
1185
1186 /*
1187 * @return @c true if the annotation of this SBML object is set,
1188 * false otherwise.
1189 */
1190 bool
isSetAnnotation() const1191 SBase::isSetAnnotation () const
1192 {
1193 const_cast <SBase *> (this)->syncAnnotation();
1194 return (mAnnotation != NULL);
1195 }
1196
1197
1198 /*
1199 * @return @c true if the sboTerm is set, false
1200 * otherwise.
1201 */
1202 bool
isSetSBOTerm() const1203 SBase::isSetSBOTerm () const
1204 {
1205 return (mSBOTerm != -1);
1206 }
1207
1208
1209 bool
isSetModelHistory()1210 SBase::isSetModelHistory()
1211 {
1212 return (mHistory != NULL);
1213 }
1214
1215
1216 /*
1217 * Sets the metaid field of the given SBML object to a copy of metaid.
1218 */
1219 int
setMetaId(const std::string & metaid)1220 SBase::setMetaId (const std::string& metaid)
1221 {
1222 if (getLevel() == 1)
1223 {
1224 return LIBSBML_UNEXPECTED_ATTRIBUTE;
1225 }
1226 else if (metaid.empty())
1227 {
1228 mMetaId.erase();
1229 // force any annotation to synchronize
1230 if (isSetAnnotation())
1231 {
1232 mCVTermsChanged = true;
1233 }
1234 return LIBSBML_OPERATION_SUCCESS;
1235 }
1236 else if (!(SyntaxChecker::isValidXMLID(metaid)))
1237 {
1238 return LIBSBML_INVALID_ATTRIBUTE_VALUE;
1239 }
1240 else
1241 {
1242 mMetaId = metaid;
1243 // force any annotation to synchronize
1244 if (isSetAnnotation())
1245 {
1246 mCVTermsChanged = true;
1247 }
1248 return LIBSBML_OPERATION_SUCCESS;
1249 }
1250 }
1251
1252
1253 int
setId(const std::string & sid)1254 SBase::setId (const std::string& sid)
1255 {
1256 if (getLevel() == 3 && getVersion() > 1)
1257 {
1258 // HACK to make a rule/initailassignment/eventassignment
1259 // in l3v2 not able to use this function
1260 int tc = getTypeCode();
1261 if (tc == SBML_ALGEBRAIC_RULE || tc == SBML_ASSIGNMENT_RULE ||
1262 tc == SBML_RATE_RULE || tc == SBML_INITIAL_ASSIGNMENT ||
1263 tc == SBML_EVENT_ASSIGNMENT)
1264 {
1265 return LIBSBML_USE_ID_ATTRIBUTE_FUNCTION;
1266 }
1267
1268
1269 if (!(SyntaxChecker::isValidInternalSId(sid)))
1270 {
1271 return LIBSBML_INVALID_ATTRIBUTE_VALUE;
1272 }
1273 else
1274 {
1275 mId = sid;
1276 return LIBSBML_OPERATION_SUCCESS;
1277 }
1278 }
1279 else
1280 {
1281 return LIBSBML_UNEXPECTED_ATTRIBUTE;
1282 }
1283 }
1284
1285
1286 int
setName(const std::string & name)1287 SBase::setName (const std::string& name)
1288 {
1289 if (getLevel() == 3 && getVersion() > 1)
1290 {
1291 mName = name;
1292 return LIBSBML_OPERATION_SUCCESS;
1293 }
1294 else
1295 {
1296 return LIBSBML_UNEXPECTED_ATTRIBUTE;
1297 }
1298 }
1299
1300
1301 int
setIdAttribute(const std::string & sid)1302 SBase::setIdAttribute (const std::string& sid)
1303 {
1304 if (!(SyntaxChecker::isValidInternalSId(sid)))
1305 {
1306 return LIBSBML_INVALID_ATTRIBUTE_VALUE;
1307 }
1308 else
1309 {
1310 mId = sid;
1311 return LIBSBML_OPERATION_SUCCESS;
1312 }
1313 }
1314
1315 /*
1316 * Sets the annotation of this SBML object to a copy of annotation.
1317 */
1318 int
setAnnotation(const XMLNode * annotation)1319 SBase::setAnnotation (const XMLNode* annotation)
1320 {
1321 //
1322 // (*NOTICE*)
1323 //
1324 // syncAnnotation() must not be invoked in this function.
1325 //
1326 //
1327
1328 if (annotation == NULL)
1329 {
1330 delete mAnnotation;
1331 mAnnotation = NULL;
1332 }
1333
1334
1335 //else if (!(math->isWellFormedASTNode()))
1336 //{
1337 // return LIBSBML_INVALID_OBJECT;
1338 //}
1339 if (mAnnotation != annotation)
1340 {
1341 delete mAnnotation;
1342
1343 // the annotation is an rdf annotation but the object has no metaid
1344 if (RDFAnnotationParser::hasRDFAnnotation(annotation) == true
1345 && (RDFAnnotationParser::hasCVTermRDFAnnotation(annotation) == true
1346 || RDFAnnotationParser::hasHistoryRDFAnnotation(annotation) == true)
1347 && isSetMetaId() == false)
1348 {
1349 mAnnotation = NULL;
1350 return LIBSBML_MISSING_METAID;
1351 }
1352 else
1353 {
1354 // check for annotation tags and add if necessary
1355 const string& name = annotation->getName();
1356 if (name != "annotation")
1357 {
1358 XMLToken ann_t = XMLToken(XMLTriple("annotation", "", ""),
1359 XMLAttributes());
1360 mAnnotation = new XMLNode(ann_t);
1361
1362 // The root node of the given XMLNode tree can be an empty XMLNode
1363 // (i.e. neither start, end, nor text XMLNode) if the given annotation was
1364 // converted from an XML string whose top level elements are neither
1365 // "html" nor "body" and not enclosed with <annotation>..</annotation> tags
1366 // (e.g. <foo xmlns:foo="...">..</foo><bar xmlns:bar="...">..</bar> )
1367 if (!annotation->isStart() && !annotation->isEnd() &&
1368 !annotation->isText())
1369 {
1370 for (unsigned int i=0; i < annotation->getNumChildren(); i++)
1371 {
1372 mAnnotation->addChild(annotation->getChild(i));
1373 }
1374 }
1375 else
1376 {
1377 mAnnotation->addChild(*annotation);
1378 }
1379 }
1380 else
1381 {
1382 mAnnotation = annotation->clone();
1383 }
1384 }
1385 }
1386
1387 //
1388 // delete existing mCVTerms
1389 //
1390 // existing CVTerms (if any) needs to be deleted at any rate, otherwise
1391 // unsetAnnotation() ( setAnnotation(NULL) ) doesn't work as expected.
1392 // (These functions must clear all elements in an annotation.)
1393 //
1394
1395 /* in L3 might be a model history */
1396 if (mHistory != NULL)
1397 {
1398 delete mHistory;
1399 mHistory = NULL;
1400 }
1401
1402 if (mCVTerms != NULL)
1403 {
1404 // delete existing mCVTerms (if any)
1405 unsigned int size = mCVTerms->getSize();
1406 while (size--) delete static_cast<CVTerm*>( mCVTerms->remove(0) );
1407 delete mCVTerms;
1408 mCVTerms = NULL;
1409 }
1410
1411
1412 if(mAnnotation != NULL
1413 && RDFAnnotationParser::hasCVTermRDFAnnotation(mAnnotation))
1414 {
1415 // parse mAnnotation (if any) and set mCVTerms
1416 mCVTerms = new List();
1417 RDFAnnotationParser::parseRDFAnnotation(mAnnotation, mCVTerms);
1418 mCVTermsChanged = true;
1419 }
1420
1421 if(getLevel() > 2 && mAnnotation != NULL
1422 && RDFAnnotationParser::hasHistoryRDFAnnotation(mAnnotation))
1423 {
1424 // parse mAnnotation (if any) and set mHistory
1425 mHistory = RDFAnnotationParser::parseRDFAnnotation(mAnnotation);
1426 mHistoryChanged = true;
1427 }
1428
1429 for (size_t i=0; i < mPlugins.size(); i++)
1430 {
1431 mPlugins[i]->parseAnnotation(this, mAnnotation);
1432 }
1433
1434
1435 //mAnnotationChanged = true;
1436
1437
1438 return LIBSBML_OPERATION_SUCCESS;
1439 }
1440
1441 /*
1442 * Sets the annotation (by string) of this SBML object to a copy of annotation.
1443 */
1444 int
setAnnotation(const std::string & annotation)1445 SBase::setAnnotation (const std::string& annotation)
1446 {
1447
1448 int success = LIBSBML_OPERATION_FAILED;
1449
1450 //
1451 // (*NOTICE*)
1452 //
1453 // syncAnnotation() must not be invoked in this function.
1454 //
1455 //
1456
1457 if(annotation.empty())
1458 {
1459 unsetAnnotation();
1460 return LIBSBML_OPERATION_SUCCESS;
1461 }
1462
1463 XMLNode* annt_xmln;
1464
1465 // you might not have a document !!
1466 if (getSBMLDocument() != NULL)
1467 {
1468 XMLNamespaces* xmlns = getSBMLDocument()->getNamespaces();
1469 annt_xmln = XMLNode::convertStringToXMLNode(annotation,xmlns);
1470 }
1471 else
1472 {
1473 annt_xmln = XMLNode::convertStringToXMLNode(annotation);
1474 }
1475
1476 if(annt_xmln != NULL)
1477 {
1478 success = setAnnotation(annt_xmln);
1479 delete annt_xmln;
1480 }
1481 return success;
1482
1483 }
1484
1485
1486 /*
1487 * Appends annotation to the existing annotations.
1488 * This allows other annotations to be preserved whilst
1489 * adding additional information.
1490 */
1491 int
appendAnnotation(const XMLNode * annotation)1492 SBase::appendAnnotation (const XMLNode* annotation)
1493 {
1494 int success = LIBSBML_OPERATION_FAILED;
1495 unsigned int duplicates = 0;
1496
1497 //
1498 // (*NOTICE*)
1499 //
1500 // syncAnnotation() doesn't need to be invoked in this function because
1501 // existing mCVTerm objects are properly merged in the following code.
1502 //
1503 // except when they have not been updated (ie CVTerm has been added but not synced
1504 // see bug reported via libsbml-team
1505 // https://www.pivotaltracker.com/story/show/166576120
1506
1507 if (getNumCVTerms() > 0 && mAnnotation == NULL)
1508 {
1509 syncAnnotation();
1510 }
1511
1512
1513 if(annotation == NULL)
1514 return LIBSBML_OPERATION_SUCCESS;
1515
1516 // the annotation is an rdf annotation but the object has no metaid
1517 if (RDFAnnotationParser::hasRDFAnnotation(annotation) == true
1518 && (RDFAnnotationParser::hasCVTermRDFAnnotation(annotation) == true
1519 || RDFAnnotationParser::hasHistoryRDFAnnotation(annotation) == true)
1520 && isSetMetaId() == false)
1521 {
1522 return LIBSBML_MISSING_METAID;
1523 }
1524
1525 XMLNode* new_annotation = NULL;
1526 const string& name = annotation->getName();
1527
1528 // check for annotation tags and add if necessary
1529 if (name != "annotation")
1530 {
1531 XMLToken ann_t = XMLToken(XMLTriple("annotation", "", ""), XMLAttributes());
1532 new_annotation = new XMLNode(ann_t);
1533 new_annotation->addChild(*annotation);
1534 }
1535 else
1536 {
1537 new_annotation = annotation->clone();
1538 }
1539
1540
1541 if (mAnnotation != NULL)
1542 {
1543 // if mAnnotation is just <annotation/> need to tell
1544 // it to no longer be an end
1545 if (mAnnotation->isEnd())
1546 {
1547 mAnnotation->unsetEnd();
1548 }
1549
1550
1551 // create a list of existing top level ns
1552 IdList topLevelNs;
1553 unsigned int i = 0;
1554 for(i = 0; i < mAnnotation->getNumChildren(); i++)
1555 {
1556 topLevelNs.append(mAnnotation->getChild(i).getName());
1557 }
1558
1559
1560
1561 for(i = 0; i < new_annotation->getNumChildren(); i++)
1562 {
1563 if (topLevelNs.contains(new_annotation->getChild(i).getName()) == false)
1564 {
1565 mAnnotation->addChild(new_annotation->getChild(i));
1566 }
1567 else
1568 {
1569 duplicates++;
1570 }
1571 }
1572
1573 delete new_annotation;
1574
1575 if (duplicates > 0)
1576 {
1577 success = LIBSBML_DUPLICATE_ANNOTATION_NS;
1578 }
1579 else
1580 {
1581 XMLNode *copy = mAnnotation->clone();
1582 success = setAnnotation(copy);
1583 delete copy;
1584 }
1585
1586
1587 }
1588 else
1589 {
1590 success = setAnnotation(new_annotation);
1591
1592 delete new_annotation;
1593 }
1594
1595 return success;
1596 }
1597
1598 /*
1599 * Appends annotation (by string) to the existing annotations.
1600 * This allows other annotations to be preserved whilst
1601 * adding additional information.
1602 */
1603 int
appendAnnotation(const std::string & annotation)1604 SBase::appendAnnotation (const std::string& annotation)
1605 {
1606 //
1607 // (*NOTICE*)
1608 //
1609 // syncAnnotation() doesn't need to be invoked in this function because
1610 // existing mCVTerm objects are properly merged in the following code.
1611 //
1612 // except when they have not been updated (ie CVTerm has been added but not synced
1613 // see bug reported via libsbml-team
1614 // https://www.pivotaltracker.com/story/show/166576120
1615
1616 if (getNumCVTerms() > 0 && mAnnotation == NULL)
1617 {
1618 syncAnnotation();
1619 }
1620
1621 int success = LIBSBML_OPERATION_FAILED;
1622 XMLNode* annt_xmln;
1623 if (getSBMLDocument() != NULL)
1624 {
1625 XMLNamespaces* xmlns = getSBMLDocument()->getNamespaces();
1626 annt_xmln = XMLNode::convertStringToXMLNode(annotation,xmlns);
1627 }
1628 else
1629 {
1630 annt_xmln = XMLNode::convertStringToXMLNode(annotation);
1631 }
1632
1633 if(annt_xmln != NULL)
1634 {
1635 success = appendAnnotation(annt_xmln);
1636 delete annt_xmln;
1637 }
1638
1639 return success;
1640 }
1641
1642
1643 int
removeTopLevelAnnotationElement(const std::string & elementName,const std::string elementURI,bool removeEmpty)1644 SBase::removeTopLevelAnnotationElement(const std::string& elementName,
1645 const std::string elementURI, bool removeEmpty)
1646 {
1647
1648 int success = LIBSBML_OPERATION_FAILED;
1649 if (mAnnotation == NULL)
1650 {
1651 success = LIBSBML_OPERATION_SUCCESS;
1652 return success;
1653 }
1654
1655 int index = mAnnotation->getIndex(elementName);
1656 if (index < 0)
1657 {
1658 // the annotation does not have a child of this name
1659 success = LIBSBML_ANNOTATION_NAME_NOT_FOUND;
1660 return success;
1661 }
1662 else
1663 {
1664 // check uri matches
1665 if (elementURI.empty() == false)
1666 {
1667 XMLNode child = mAnnotation->getChild((unsigned int)index);
1668 std::string prefix = child.getPrefix();
1669
1670 if (prefix.empty() == false
1671 && elementURI != child.getNamespaceURI(prefix))
1672 {
1673 success = LIBSBML_ANNOTATION_NS_NOT_FOUND;
1674 return success;
1675 }
1676 else
1677 {
1678 bool match = false;
1679 int n = 0;
1680
1681 while (match == false && n < child.getNamespacesLength())
1682 {
1683 if (elementURI == child.getNamespaceURI(n))
1684 {
1685 match = true;
1686 }
1687 n++;
1688 }
1689
1690 if (match == false)
1691 {
1692 success = LIBSBML_ANNOTATION_NS_NOT_FOUND;
1693 return success;
1694 }
1695 }
1696 }
1697
1698 // remove the annotation at the index corresponding to the name
1699 delete mAnnotation->removeChild((unsigned int)index);
1700 if (removeEmpty && mAnnotation->getNumChildren() == 0)
1701 {
1702 delete mAnnotation;
1703 mAnnotation = NULL;
1704 }
1705
1706 // check success
1707 if (mAnnotation == NULL || mAnnotation->getIndex(elementName) < 0)
1708 {
1709 success = LIBSBML_OPERATION_SUCCESS;
1710 }
1711 }
1712
1713 return success;
1714 }
1715
1716
1717 int
replaceTopLevelAnnotationElement(const XMLNode * annotation)1718 SBase::replaceTopLevelAnnotationElement(const XMLNode* annotation)
1719 {
1720 int success = LIBSBML_OPERATION_FAILED;
1721 XMLNode * replacement = NULL;
1722 if (annotation->getName() == "annotation")
1723 {
1724 if (annotation->getNumChildren() != 1)
1725 {
1726 success = LIBSBML_INVALID_OBJECT;
1727 return success;
1728 }
1729 else
1730 {
1731 replacement = annotation->getChild(0).clone();
1732 }
1733 }
1734 else
1735 {
1736 replacement = annotation->clone();
1737 }
1738
1739 success = removeTopLevelAnnotationElement(replacement->getName());
1740 if (success == LIBSBML_OPERATION_SUCCESS)
1741 {
1742 success = appendAnnotation(annotation);
1743 }
1744
1745 delete (replacement);
1746
1747 return success;
1748 }
1749
1750
1751 int
replaceTopLevelAnnotationElement(const std::string & annotation)1752 SBase::replaceTopLevelAnnotationElement(const std::string& annotation)
1753 {
1754 int success = LIBSBML_OPERATION_FAILED;
1755 XMLNode* annt_xmln;
1756 if (getSBMLDocument() != NULL)
1757 {
1758 XMLNamespaces* xmlns = getSBMLDocument()->getNamespaces();
1759 annt_xmln = XMLNode::convertStringToXMLNode(annotation,xmlns);
1760 }
1761 else
1762 {
1763 annt_xmln = XMLNode::convertStringToXMLNode(annotation);
1764 }
1765
1766 if(annt_xmln != NULL)
1767 {
1768 success = replaceTopLevelAnnotationElement(annt_xmln);
1769 }
1770
1771 delete annt_xmln;
1772
1773 return success;
1774 }
1775
1776
1777 /*
1778 * Sets the notes of this SBML object to a copy of notes.
1779 */
1780 int
setNotes(const XMLNode * notes)1781 SBase::setNotes(const XMLNode* notes)
1782 {
1783 if (mNotes == notes)
1784 {
1785 return LIBSBML_OPERATION_SUCCESS;
1786 }
1787 else if (notes == NULL)
1788 {
1789 delete mNotes;
1790 mNotes = NULL;
1791 return LIBSBML_OPERATION_SUCCESS;
1792 }
1793
1794 delete mNotes;
1795 const string& name = notes->getName();
1796
1797 /* check for notes tags and add if necessary */
1798
1799 if (name == "notes")
1800 {
1801 mNotes = static_cast<XMLNode*>( notes->clone() );
1802 }
1803 else
1804 {
1805 XMLToken notes_t = XMLToken(XMLTriple("notes", "", ""),
1806 XMLAttributes());
1807 mNotes = new XMLNode(notes_t);
1808
1809 // The root node of the given XMLNode tree can be an empty XMLNode
1810 // (i.e. neither start, end, nor text XMLNode) if the given notes was
1811 // converted from an XML string whose top level elements are neither
1812 // "html" nor "body" and not enclosed with <notes>..</notes> tag
1813 // (e.g. <p ...>..</p><br/>).
1814 if (!notes->isStart() && !notes->isEnd() && !notes->isText() )
1815 {
1816 for (unsigned int i=0; i < notes->getNumChildren(); i++)
1817 {
1818 if (mNotes->addChild(notes->getChild(i)) < 0)
1819 {
1820 return LIBSBML_OPERATION_FAILED;
1821 }
1822 }
1823 }
1824 else
1825 {
1826 if (mNotes->addChild(*notes) < 0)
1827 return LIBSBML_OPERATION_FAILED;
1828 }
1829 }
1830
1831 // in L2v2 and beyond the XHTML content of notes is restricted
1832 // but I need the notes tag to use the function
1833 // so I havent tested it until now
1834 if (getLevel() > 2
1835 || (getLevel() == 2 && getVersion() > 1))
1836 {
1837 if (!SyntaxChecker::hasExpectedXHTMLSyntax(mNotes, getSBMLNamespaces()))
1838 {
1839 delete mNotes;
1840 mNotes = NULL;
1841 return LIBSBML_INVALID_OBJECT;
1842 }
1843 }
1844
1845 return LIBSBML_OPERATION_SUCCESS;
1846
1847 }
1848
1849 /*
1850 * Sets the notes (by std::string) of this SBML object to a copy of notes.
1851 */
1852 int
setNotes(const std::string & notes,bool addXHTMLMarkup)1853 SBase::setNotes(const std::string& notes, bool addXHTMLMarkup)
1854 {
1855 int success = LIBSBML_OPERATION_FAILED;
1856
1857 if (notes.empty())
1858 {
1859 success = unsetNotes();
1860 }
1861 else
1862 {
1863 XMLNode* notes_xmln;
1864
1865 // you might not have a document !!
1866 if (getSBMLDocument() != NULL)
1867 {
1868 XMLNamespaces* xmlns = getSBMLDocument()->getNamespaces();
1869 notes_xmln = XMLNode::convertStringToXMLNode(notes,xmlns);
1870 }
1871 else
1872 {
1873 notes_xmln = XMLNode::convertStringToXMLNode(notes);
1874 }
1875
1876 if(notes_xmln != NULL)
1877 {
1878 if (addXHTMLMarkup == true)
1879 {
1880 // user has specified that they want the markup added
1881 if (getLevel() > 2
1882 || (getLevel() == 2 && getVersion() > 1))
1883 {
1884 // just say the user passed a string that did not represent xhtml
1885 // the xmlnode will not get set as it is invalid
1886 if (notes_xmln->getNumChildren() == 0
1887 && notes_xmln->isStart() == false
1888 && notes_xmln->isEnd() == false
1889 && notes_xmln->isText() == true)
1890 {
1891 //create a parent node of xhtml type p
1892 XMLAttributes blank_att = XMLAttributes();
1893 XMLTriple triple = XMLTriple("p", "http://www.w3.org/1999/xhtml", "");
1894 XMLNamespaces xmlns = XMLNamespaces();
1895 xmlns.add("http://www.w3.org/1999/xhtml", "");
1896 XMLNode *xmlnode = new XMLNode(XMLToken(triple, blank_att, xmlns));
1897
1898 // create a text node from the text given
1899 xmlnode->addChild(*notes_xmln);
1900 success = setNotes(xmlnode);
1901 delete xmlnode;
1902 }
1903 else
1904 {
1905 success = setNotes(notes_xmln);
1906 }
1907
1908 }
1909 else
1910 {
1911 success = setNotes(notes_xmln);
1912 }
1913 }
1914 else
1915 {
1916 success = setNotes(notes_xmln);
1917 }
1918 delete notes_xmln;
1919 }
1920 }
1921 return success;
1922 }
1923
1924
1925 /*
1926 * Appends notes to the existing notes.
1927 * This allows other notes to be preserved whilst
1928 * adding additional information.
1929 */
1930 int
appendNotes(const XMLNode * notes)1931 SBase::appendNotes(const XMLNode* notes)
1932 {
1933 int success = LIBSBML_OPERATION_FAILED;
1934 if(notes == NULL)
1935 {
1936 return LIBSBML_OPERATION_SUCCESS;
1937 }
1938
1939 const string& name = notes->getName();
1940
1941 // The content of notes in SBML can consist only of the following
1942 // possibilities:
1943 //
1944 // 1. A complete XHTML document (minus the XML and DOCTYPE
1945 // declarations), that is, XHTML content beginning with the
1946 // html tag.
1947 // (_NotesType is _ANotesHTML.)
1948 //
1949 // 2. The body element from an XHTML document.
1950 // (_NotesType is _ANotesBody.)
1951 //
1952 // 3. Any XHTML content that would be permitted within a body
1953 // element, each one must declare the XML namespace separately.
1954 // (_NotesType is _ANotesAny.)
1955 //
1956
1957 typedef enum { _ANotesHTML, _ANotesBody, _ANotesAny } _NotesType;
1958
1959 _NotesType addedNotesType = _ANotesAny;
1960 XMLNode addedNotes;
1961
1962 //------------------------------------------------------------
1963 //
1964 // STEP1 : identifies the type of the given notes
1965 //
1966 //------------------------------------------------------------
1967
1968 if (name == "notes")
1969 {
1970 /* check for notes tags on the added notes and strip if present and
1971 the notes tag has "html" or "body" element */
1972
1973 if (notes->getNumChildren() > 0)
1974 {
1975 // notes->getChild(0) must be "html", "body", or any XHTML
1976 // element that would be permitted within a "body" element
1977 // (e.g. <p>..</p>, <br>..</br> and so forth).
1978
1979 const string& cname = notes->getChild(0).getName();
1980
1981 if (cname == "html")
1982 {
1983 addedNotes = notes->getChild(0);
1984 addedNotesType = _ANotesHTML;
1985 }
1986 else if (cname == "body")
1987 {
1988 addedNotes = notes->getChild(0);
1989 addedNotesType = _ANotesBody;
1990 }
1991 else
1992 {
1993 // the notes tag must NOT be stripped if notes->getChild(0) node
1994 // is neither "html" nor "body" element because the children of
1995 // the addedNotes will be added to the curNotes later if the node
1996 // is neither "html" nor "body".
1997 addedNotes = *notes;
1998 addedNotesType = _ANotesAny;
1999 }
2000 }
2001 else
2002 {
2003 // the given notes is empty
2004 return LIBSBML_OPERATION_SUCCESS;
2005 }
2006 }
2007 else
2008 {
2009 // if the XMLNode argument notes has been created from a string and
2010 // it is a set of subelements there may be a single empty node
2011 // as parent - leaving this in doesnt affect the writing out of notes
2012 // but messes up the check for correct syntax
2013 if (!notes->isStart() && !notes->isEnd() && !notes->isText() )
2014 {
2015 if (notes->getNumChildren() > 0)
2016 {
2017 addedNotes = *notes;
2018 addedNotesType = _ANotesAny;
2019 }
2020 else
2021 {
2022 // the given notes is empty
2023 return LIBSBML_OPERATION_SUCCESS;
2024 }
2025 }
2026 else
2027 {
2028 if (name == "html")
2029 {
2030 addedNotes = *notes;
2031 addedNotesType = _ANotesHTML;
2032 }
2033 else if (name == "body")
2034 {
2035 addedNotes = *notes;
2036 addedNotesType = _ANotesBody;
2037 }
2038 else
2039 {
2040 // The given notes node needs to be added to a parent node
2041 // if the node is neither "html" nor "body" element because the
2042 // children of addedNotes will be added to the curNotes later if the
2043 // node is neither "html" nor "body" (i.e. any XHTML element that
2044 // would be permitted within a "body" element)
2045 addedNotes.addChild(*notes);
2046 addedNotesType = _ANotesAny;
2047 }
2048 }
2049 }
2050
2051 //
2052 // checks the addedNotes of "html" if the html tag contains "head" and
2053 // "body" tags which must be located in this order.
2054 //
2055 if (addedNotesType == _ANotesHTML)
2056 {
2057 if ((addedNotes.getNumChildren() != 2) ||
2058 ( (addedNotes.getChild(0).getName() != "head") ||
2059 (addedNotes.getChild(1).getName() != "body")
2060 )
2061 )
2062 {
2063 return LIBSBML_INVALID_OBJECT;
2064 }
2065 }
2066
2067 // check whether notes is valid xhtml
2068 if (getLevel() > 2
2069 || (getLevel() == 2 && getVersion() > 1))
2070 {
2071 XMLNode tmpNotes(XMLTriple("notes","",""), XMLAttributes());
2072
2073 if (addedNotesType == _ANotesAny)
2074 {
2075 for (unsigned int i=0; i < addedNotes.getNumChildren(); i++)
2076 {
2077 tmpNotes.addChild(addedNotes.getChild(i));
2078 }
2079 }
2080 else
2081 {
2082 tmpNotes.addChild(addedNotes);
2083 }
2084
2085 if (!SyntaxChecker::hasExpectedXHTMLSyntax(&tmpNotes, getSBMLNamespaces()))
2086 {
2087 return LIBSBML_INVALID_OBJECT;
2088 }
2089 }
2090
2091
2092 if ( mNotes != NULL )
2093 {
2094 //------------------------------------------------------------
2095 //
2096 // STEP2: identifies the type of the existing notes
2097 //
2098 //------------------------------------------------------------
2099
2100 _NotesType curNotesType = _ANotesAny;
2101 XMLNode& curNotes = *mNotes;
2102
2103 // curNotes.getChild(0) must be "html", "body", or any XHTML
2104 // element that would be permitted within a "body" element .
2105
2106 const string& cname = curNotes.getChild(0).getName();
2107
2108 if (cname == "html")
2109 {
2110 XMLNode& curHTML = curNotes.getChild(0);
2111 //
2112 // checks the curHTML if the html tag contains "head" and "body" tags
2113 // which must be located in this order, otherwise nothing will be done.
2114 //
2115 if ((curHTML.getNumChildren() != 2) ||
2116 ( (curHTML.getChild(0).getName() != "head") ||
2117 (curHTML.getChild(1).getName() != "body")
2118 )
2119 )
2120 {
2121 return LIBSBML_INVALID_OBJECT;
2122 }
2123 curNotesType = _ANotesHTML;
2124 }
2125 else if (cname == "body")
2126 {
2127 curNotesType = _ANotesBody;
2128 }
2129 else
2130 {
2131 curNotesType = _ANotesAny;
2132 }
2133
2134 /*
2135 * BUT we also have the issue of the rules relating to notes
2136 * contents and where to add them ie we cannot add a second body element
2137 * etc...
2138 */
2139
2140 //------------------------------------------------------------
2141 //
2142 // STEP3: appends the given notes to the current notes
2143 //
2144 //------------------------------------------------------------
2145
2146 unsigned int i;
2147
2148 if (curNotesType == _ANotesHTML)
2149 {
2150 XMLNode& curHTML = curNotes.getChild(0);
2151 XMLNode& curBody = curHTML.getChild(1);
2152
2153 if (addedNotesType == _ANotesHTML)
2154 {
2155 // adds the given html tag to the current html tag
2156
2157 XMLNode& addedBody = addedNotes.getChild(1);
2158
2159 for (i=0; i < addedBody.getNumChildren(); i++)
2160 {
2161 if (curBody.addChild(addedBody.getChild(i)) < 0 )
2162 return LIBSBML_OPERATION_FAILED;
2163 }
2164 }
2165 else if ((addedNotesType == _ANotesBody)
2166 || (addedNotesType == _ANotesAny))
2167 {
2168 // adds the given body or other tag (permitted in the body) to the current
2169 // html tag
2170
2171 for (i=0; i < addedNotes.getNumChildren(); i++)
2172 {
2173 if (curBody.addChild(addedNotes.getChild(i)) < 0 )
2174 return LIBSBML_OPERATION_FAILED;
2175 }
2176 }
2177 success = LIBSBML_OPERATION_SUCCESS;
2178 }
2179 else if (curNotesType == _ANotesBody)
2180 {
2181 if (addedNotesType == _ANotesHTML)
2182 {
2183 // adds the given html tag to the current body tag
2184
2185 XMLNode addedHTML(addedNotes);
2186 XMLNode& addedBody = addedHTML.getChild(1);
2187 XMLNode& curBody = curNotes.getChild(0);
2188
2189 for (i=0; i < curBody.getNumChildren(); i++)
2190 {
2191 addedBody.insertChild(i,curBody.getChild(i));
2192 }
2193
2194 curNotes.removeChildren();
2195 if (curNotes.addChild(addedHTML) < 0)
2196 return LIBSBML_OPERATION_FAILED;
2197 }
2198 else if ((addedNotesType == _ANotesBody) || (addedNotesType == _ANotesAny))
2199 {
2200 // adds the given body or other tag (permitted in the body) to the current
2201 // body tag
2202
2203 XMLNode& curBody = curNotes.getChild(0);
2204
2205 for (i=0; i < addedNotes.getNumChildren(); i++)
2206 {
2207 if (curBody.addChild(addedNotes.getChild(i)) < 0)
2208 return LIBSBML_OPERATION_FAILED;
2209 }
2210 }
2211 success = LIBSBML_OPERATION_SUCCESS;
2212 }
2213 else if (curNotesType == _ANotesAny)
2214 {
2215 if (addedNotesType == _ANotesHTML)
2216 {
2217 // adds the given html tag to the current any tag permitted in the body.
2218
2219 XMLNode addedHTML(addedNotes);
2220 XMLNode& addedBody = addedHTML.getChild(1);
2221
2222 for (i=0; i < curNotes.getNumChildren(); i++)
2223 {
2224 addedBody.insertChild(i,curNotes.getChild(i));
2225 }
2226
2227 curNotes.removeChildren();
2228 if (curNotes.addChild(addedHTML) < 0)
2229 return LIBSBML_OPERATION_FAILED;
2230 }
2231 else if (addedNotesType == _ANotesBody)
2232 {
2233 // adds the given body tag to the current any tag permitted in the body.
2234
2235 XMLNode addedBody(addedNotes);
2236
2237 for (i=0; i < curNotes.getNumChildren(); i++)
2238 {
2239 addedBody.insertChild(i,curNotes.getChild(i));
2240 }
2241
2242 curNotes.removeChildren();
2243 if (curNotes.addChild(addedBody) < 0)
2244 return LIBSBML_OPERATION_FAILED;
2245 }
2246 else if (addedNotesType == _ANotesAny)
2247 {
2248 // adds the given any tag permitted in the boy to that of the current
2249 // any tag.
2250
2251 for (i=0; i < addedNotes.getNumChildren(); i++)
2252 {
2253 if (curNotes.addChild(addedNotes.getChild(i)) < 0)
2254 return LIBSBML_OPERATION_FAILED;
2255 }
2256 }
2257 success = LIBSBML_OPERATION_SUCCESS;
2258 }
2259 }
2260 else // if (mNotes == NULL)
2261 {
2262 // setNotes accepts XMLNode with/without top level notes tags.
2263 success = setNotes(notes);
2264 }
2265
2266 return success;
2267 }
2268
2269 /*
2270 * Appends notes (by string) to the existing notes.
2271 * This allows other notes to be preserved whilst
2272 * adding additional information.
2273 */
2274 int
appendNotes(const std::string & notes)2275 SBase::appendNotes(const std::string& notes)
2276 {
2277 int success = LIBSBML_OPERATION_FAILED;
2278 if (notes.empty())
2279 {
2280 return LIBSBML_OPERATION_SUCCESS;
2281 }
2282
2283 XMLNode* notes_xmln;
2284 // you might not have a document !!
2285 if (getSBMLDocument() != NULL)
2286 {
2287 XMLNamespaces* xmlns = getSBMLDocument()->getNamespaces();
2288 notes_xmln = XMLNode::convertStringToXMLNode(notes,xmlns);
2289 }
2290 else
2291 {
2292 notes_xmln = XMLNode::convertStringToXMLNode(notes);
2293 }
2294
2295 if(notes_xmln != NULL)
2296 {
2297 success = appendNotes(notes_xmln);
2298 delete notes_xmln;
2299 }
2300 return success;
2301 }
2302
2303
2304 int
setModelHistory(ModelHistory * history)2305 SBase::setModelHistory(ModelHistory * history)
2306 {
2307 /* ModelHistory is only allowed on Model in L2
2308 * but on any element in L3
2309 */
2310 if (getLevel() < 3)
2311 {
2312 if (getTypeCode() != SBML_MODEL)
2313 {
2314 return LIBSBML_UNEXPECTED_ATTRIBUTE;
2315 }
2316 }
2317 // shouldnt add a history to an object with no metaid
2318 if (!isSetMetaId())
2319 {
2320 return LIBSBML_MISSING_METAID;
2321 }
2322
2323 if (mHistory == history)
2324 {
2325 return LIBSBML_OPERATION_SUCCESS;
2326 }
2327 else if (history == NULL)
2328 {
2329 delete mHistory;
2330 mHistory = NULL;
2331 mHistoryChanged = true;
2332 return LIBSBML_OPERATION_SUCCESS;
2333 }
2334 else if (!(history->hasRequiredAttributes()))
2335 {
2336 delete mHistory;
2337 mHistory = NULL;
2338 return LIBSBML_INVALID_OBJECT;
2339 }
2340 else
2341 {
2342 delete mHistory;
2343 mHistory = static_cast<ModelHistory*>( history->clone() );
2344 mHistoryChanged = true;
2345 return LIBSBML_OPERATION_SUCCESS;
2346 }
2347 }
2348
2349
2350 /** @cond doxygenLibsbmlInternal */
2351 /*
2352 * Sets the parent SBMLDocument of this SBML object.
2353 */
2354 void
setSBMLDocument(SBMLDocument * d)2355 SBase::setSBMLDocument (SBMLDocument* d)
2356 {
2357 mSBML = d;
2358
2359 //
2360 // (EXTENSION)
2361 //
2362 for (size_t i=0; i < mPlugins.size(); i++)
2363 {
2364 mPlugins[i]->setSBMLDocument(d);
2365 }
2366 }
2367
2368
2369 /*
2370 * Sets the parent SBML object of this SBML object.
2371 *
2372 * @param sb the SBML object to use.
2373 */
2374 void
connectToParent(SBase * parent)2375 SBase::connectToParent (SBase* parent)
2376 {
2377 mParentSBMLObject = parent;
2378 if (mParentSBMLObject)
2379 {
2380 #if 0
2381 cout << "[DEBUG] connectToParent " << this << " (parent) " << SBMLTypeCode_toString(parent->getTypeCode(),"core")
2382 << " " << parent->getSBMLDocument() << endl;
2383 #endif
2384 setSBMLDocument(mParentSBMLObject->getSBMLDocument());
2385 }
2386 else
2387 {
2388 setSBMLDocument(0);
2389 }
2390 for (unsigned int p=0; p<mPlugins.size(); p++) {
2391 mPlugins[p]->connectToParent(this);
2392 }
2393 }
2394
2395
2396 /*
2397 * Sets this SBML object to child SBML objects (if any).
2398 * (Creates a child-parent relationship by the parent)
2399 *
2400 * Subclasses must override this function if they define
2401 * one ore more child elements.
2402 * Basically, this function needs to be called in
2403 * constructors, copy constructors and assignment operators.
2404 */
2405 void
connectToChild()2406 SBase::connectToChild()
2407 {
2408 for (size_t p=0; p<mPlugins.size(); p++) {
2409 mPlugins[p]->connectToParent(this);
2410 }
2411 }
2412 /** @endcond */
2413
2414 SBase*
getAncestorOfType(int type,const std::string & pkgName)2415 SBase::getAncestorOfType(int type, const std::string& pkgName)
2416 {
2417 if (pkgName == "core" && type == SBML_DOCUMENT)
2418 return getSBMLDocument();
2419
2420 SBase *child;
2421 SBase *parent = getParentSBMLObject();
2422
2423 while ( parent != NULL &&
2424 !( parent->getPackageName() == "core" &&
2425 parent->getTypeCode() == SBML_DOCUMENT )
2426 )
2427 {
2428 if (parent->getTypeCode() == type && parent->getPackageName() == pkgName)
2429 return parent;
2430 else
2431 {
2432 child = parent;
2433 parent = child->getParentSBMLObject();
2434 }
2435 }
2436
2437 // if we get here we havent found an ancestor of this type
2438 return NULL;
2439
2440 }
2441
2442
2443 const SBase*
getAncestorOfType(int type,const std::string pkgName) const2444 SBase::getAncestorOfType(int type, const std::string pkgName) const
2445 {
2446 if (pkgName == "core" && type == SBML_DOCUMENT)
2447 return getSBMLDocument();
2448
2449 const SBase *child;
2450 const SBase *parent = getParentSBMLObject();
2451
2452 while ( parent != NULL &&
2453 !( parent->getPackageName() == "core" &&
2454 parent->getTypeCode() == SBML_DOCUMENT )
2455 )
2456 {
2457 if (parent->getTypeCode() == type && parent->getPackageName() == pkgName)
2458 return parent;
2459 else
2460 {
2461 child = parent;
2462 parent = child->getParentSBMLObject();
2463 }
2464 }
2465
2466 // if we get here we havent found an ancestor of this type
2467 return NULL;
2468
2469 }
2470
2471
2472 /*
2473 * Sets the sboTerm field to value.
2474 */
2475 int
setSBOTerm(int value)2476 SBase::setSBOTerm (int value)
2477 {
2478 if (getLevel() < 2 || (getLevel() == 2 && getVersion() < 2))
2479 {
2480 mSBOTerm = -1;
2481 return LIBSBML_UNEXPECTED_ATTRIBUTE;
2482 }
2483 else
2484 {
2485 if ( !SBO::checkTerm(value) )
2486 {
2487 mSBOTerm = -1;
2488 return LIBSBML_INVALID_ATTRIBUTE_VALUE;
2489 }
2490 mSBOTerm = value;
2491 return LIBSBML_OPERATION_SUCCESS;
2492 }
2493 }
2494
2495 /*
2496 * Sets the sboTerm field to value converted from the given string.
2497 */
2498 int
setSBOTerm(const std::string & sboid)2499 SBase::setSBOTerm (const std::string &sboid)
2500 {
2501 return setSBOTerm(SBO::stringToInt(sboid));
2502 }
2503
2504
2505 /*
2506 * Sets the namespaces relevant of this SBML object.
2507 *
2508 * @param xmlns the namespaces to set.
2509 */
2510 int
setNamespaces(XMLNamespaces * xmlns)2511 SBase::setNamespaces(XMLNamespaces* xmlns)
2512 {
2513 if (xmlns == NULL)
2514 {
2515 mSBMLNamespaces->setNamespaces(NULL);
2516 return LIBSBML_OPERATION_SUCCESS;
2517 }
2518 else
2519 {
2520 mSBMLNamespaces->setNamespaces(xmlns);
2521 return LIBSBML_OPERATION_SUCCESS;
2522 }
2523 }
2524
2525
2526
2527 /*
2528 * Unsets the metaid of this SBML object.
2529 */
2530 int
unsetMetaId()2531 SBase::unsetMetaId ()
2532 {
2533 /* only in L2 onwards */
2534 if (getLevel() < 2)
2535 {
2536 return LIBSBML_UNEXPECTED_ATTRIBUTE;
2537 }
2538
2539 mMetaId.erase();
2540
2541 if (mMetaId.empty())
2542 {
2543 return LIBSBML_OPERATION_SUCCESS;
2544 }
2545 else
2546 {
2547 return LIBSBML_OPERATION_FAILED;
2548 }
2549 }
2550
2551
2552 /*
2553 * Unsets the id of this SBML object.
2554 */
2555 int
unsetId()2556 SBase::unsetId ()
2557 {
2558 if (getLevel() == 3 && getVersion() > 1)
2559 {
2560 mId.erase();
2561 // HACK to make a rule in l3v2 not able to use this function
2562 int tc = getTypeCode();
2563 if (tc == SBML_ALGEBRAIC_RULE || tc == SBML_ASSIGNMENT_RULE ||
2564 tc == SBML_RATE_RULE || tc == SBML_INITIAL_ASSIGNMENT ||
2565 tc == SBML_EVENT_ASSIGNMENT)
2566 {
2567 return LIBSBML_USE_ID_ATTRIBUTE_FUNCTION;
2568 }
2569
2570
2571 if (mId.empty())
2572 {
2573 return LIBSBML_OPERATION_SUCCESS;
2574 }
2575 else
2576 {
2577 return LIBSBML_OPERATION_FAILED;
2578 }
2579 }
2580 else
2581 {
2582 return LIBSBML_OPERATION_FAILED;
2583 }
2584 }
2585
2586
2587 int
unsetIdAttribute()2588 SBase::unsetIdAttribute ()
2589 {
2590 mId.erase();
2591
2592 if (mId.empty())
2593 {
2594 return LIBSBML_OPERATION_SUCCESS;
2595 }
2596 else
2597 {
2598 return LIBSBML_OPERATION_FAILED;
2599 }
2600 }
2601
2602
2603 /*
2604 * Unsets the name of this SBML object.
2605 */
2606 int
unsetName()2607 SBase::unsetName ()
2608 {
2609 if (getLevel() == 3 && getVersion() > 1)
2610 {
2611 mName.erase();
2612
2613 if (mName.empty())
2614 {
2615 return LIBSBML_OPERATION_SUCCESS;
2616 }
2617 else
2618 {
2619 return LIBSBML_OPERATION_FAILED;
2620 }
2621 }
2622 else
2623 {
2624 return LIBSBML_OPERATION_FAILED;
2625 }
2626 }
2627
2628
2629 /*
2630 * Unsets the notes of this SBML object.
2631 */
2632 int
unsetNotes()2633 SBase::unsetNotes ()
2634 {
2635 delete mNotes;
2636 mNotes = NULL;
2637 return LIBSBML_OPERATION_SUCCESS;
2638 }
2639
2640
2641 /*
2642 * Unsets the annotation of this SBML object.
2643 */
2644 int
unsetAnnotation()2645 SBase::unsetAnnotation ()
2646 {
2647 XMLNode* empty = NULL;
2648 return setAnnotation(empty);
2649 }
2650
2651
2652 /*
2653 * Unsets the sboTerm of this SBML object.
2654 */
2655 int
unsetSBOTerm()2656 SBase::unsetSBOTerm ()
2657 {
2658 if (getLevel() < 2 || (getLevel() == 2 && getVersion() < 2))
2659 {
2660 mSBOTerm = -1;
2661 return LIBSBML_UNEXPECTED_ATTRIBUTE;
2662 }
2663 else
2664 {
2665 mSBOTerm = -1;
2666 return LIBSBML_OPERATION_SUCCESS;
2667 }
2668 }
2669
2670
2671 /** @cond doxygenLibsbmlInternal */
removeDuplicatedResources(CVTerm * term,QualifierType_t type)2672 void SBase::removeDuplicatedResources(CVTerm *term, QualifierType_t type)
2673 {
2674 int length = term->getResources()->getLength();
2675 if (type == BIOLOGICAL_QUALIFIER)
2676 {
2677 BiolQualifierType_t biolQual = BQB_UNKNOWN;
2678 for (int p = length-1; p > -1; p--)
2679 {
2680 biolQual = getResourceBiologicalQualifier(term->getResources()->getValue(p));
2681 if (biolQual != BQB_UNKNOWN)
2682 {
2683 /* resource is already present
2684 * - dont want to add again;
2685 * so delete it from set to be added
2686 */
2687 term->removeResource(term->getResources()->getValue(p));
2688 }
2689 }
2690 }
2691 else if (type == MODEL_QUALIFIER)
2692 {
2693 ModelQualifierType_t modelQual = BQM_UNKNOWN;
2694 for (int p = length-1; p > -1; p--)
2695 {
2696 modelQual = getResourceModelQualifier(term->getResources()->getValue(p));
2697 if (modelQual != BQM_UNKNOWN)
2698 {
2699 /* resource is already present
2700 * - dont want to add again;
2701 * so delete it from set to be added
2702 */
2703 term->removeResource(term->getResources()->getValue(p));
2704 }
2705 }
2706 }
2707 }
2708 /** @endcond */
2709
2710 /** @cond doxygenLibsbmlInternal */
addTermToExistingBag(CVTerm * term,QualifierType_t type)2711 int SBase::addTermToExistingBag(CVTerm *term, QualifierType_t type )
2712 {
2713 unsigned int added = 0;
2714 unsigned int length = mCVTerms->getSize();
2715
2716 CVTerm* nthTerm = NULL;
2717
2718 if (length == 0) return (int)added;
2719
2720 if (type == BIOLOGICAL_QUALIFIER)
2721 {
2722 BiolQualifierType_t biol = term->getBiologicalQualifierType();
2723
2724 for (int n = (int)length -1; n >= 0 && added == 0; n--)
2725 {
2726 nthTerm = static_cast <CVTerm *>(mCVTerms->get((unsigned int)n));
2727
2728 if (nthTerm != NULL && biol == nthTerm->getBiologicalQualifierType())
2729 {
2730 for (int r = 0; r < term->getResources()->getLength(); r++)
2731 {
2732 nthTerm->addResource(
2733 term->getResources()->getValue(r));
2734 }
2735 added = 1;
2736 }
2737 }
2738 }
2739 else if (type == MODEL_QUALIFIER)
2740 {
2741 ModelQualifierType_t model = term->getModelQualifierType();
2742
2743 for (unsigned int n = 0; n < length && added == 0; n++)
2744 {
2745 nthTerm = static_cast <CVTerm *>(mCVTerms->get(n));
2746
2747 if (nthTerm != NULL && model == nthTerm->getModelQualifierType())
2748 {
2749 for (int r = 0; r < term->getResources()->getLength(); r++)
2750 {
2751 nthTerm->addResource(
2752 term->getResources()->getValue(r));
2753 }
2754 added = 1;
2755 }
2756 }
2757 }
2758 return (int)added;
2759 }
2760 /** @endcond */
2761
2762 /*
2763 * Adds a copy of the given CVTerm to this SBML object.
2764 */
2765 int
addCVTerm(CVTerm * term,bool newBag)2766 SBase::addCVTerm(CVTerm * term, bool newBag)
2767 {
2768 unsigned int added = 0;
2769 // shouldnt add a CVTerm to an object with no metaid
2770 if (!isSetMetaId())
2771 {
2772 return LIBSBML_MISSING_METAID;
2773 }
2774
2775 if (term == NULL)
2776 {
2777 return LIBSBML_OPERATION_FAILED;
2778 }
2779 else if (!term->hasRequiredAttributes())
2780 {
2781 return LIBSBML_INVALID_OBJECT;
2782 }
2783
2784 /* clone the term to be added so that I can adjust
2785 * which resources are actually added
2786 */
2787 CVTerm * copyTerm = term->clone();
2788
2789 if (mCVTerms == NULL)
2790 {
2791 mCVTerms = new List();
2792 mCVTerms->add((void *) term->clone());
2793 }
2794 else if (mCVTerms->getSize() == 0)
2795 {
2796 mCVTerms->add((void *) term->clone());
2797 }
2798 else
2799 {
2800 /* check whether the resources are already listed */
2801 QualifierType_t type = copyTerm->getQualifierType();
2802 removeDuplicatedResources(copyTerm, type);
2803
2804 /* if the qualifier of the term being added is already present
2805 * add to the list of resources for that qualifier
2806 */
2807 if (newBag == false)
2808 {
2809 added = (unsigned int)addTermToExistingBag(copyTerm, type);
2810 }
2811
2812 if (added == 0 && copyTerm->getResources()->getLength() > 0)
2813 {
2814 /* no matching copyTerms already in list */
2815 mCVTerms->add((void *) copyTerm->clone());
2816 }
2817
2818 }
2819
2820 delete copyTerm;
2821 mCVTermsChanged = true;
2822 return LIBSBML_OPERATION_SUCCESS;
2823 }
2824
2825
2826 /*
2827 * @return the list of CVTerms for this SBML object.
2828 */
2829 List*
getCVTerms()2830 SBase::getCVTerms()
2831 {
2832 return mCVTerms;
2833 }
2834
2835
2836 /*
2837 * @return the list of CVTerms for this SBML object.
2838 */
2839 List*
getCVTerms() const2840 SBase::getCVTerms() const
2841 {
2842 return mCVTerms;
2843 }
2844
2845 /*
2846 * Returns the number of CVTerm objects in the annotations of this SBML
2847 * object.
2848 *
2849 * @return the number of CVTerms for this SBML object.
2850 */
2851 unsigned int
getNumCVTerms()2852 SBase::getNumCVTerms()
2853 {
2854 if (mCVTerms != NULL)
2855 {
2856 return mCVTerms->getSize();
2857 }
2858 else
2859 {
2860 return 0;
2861 }
2862 }
2863
2864
2865 /*
2866 * Returns the nth CVTerm in the list of CVTerms of this SBML
2867 * object.
2868 *
2869 * @param n unsigned int the index of the CVTerm to retrieve.
2870 *
2871 * @return the nth CVTerm in the list of CVTerms for this SBML object.
2872 */
2873 CVTerm*
getCVTerm(unsigned int n)2874 SBase::getCVTerm(unsigned int n)
2875 {
2876 return (mCVTerms) ? static_cast <CVTerm*> (mCVTerms->get(n)) : NULL;
2877 }
2878
2879
2880 /*
2881 * Clears the list of CVTerms of this SBML
2882 * object.
2883 */
2884 int
unsetCVTerms()2885 SBase::unsetCVTerms()
2886 {
2887 if (mCVTerms != NULL)
2888 {
2889 unsigned int size = mCVTerms->getSize();
2890 while (size--) delete static_cast<CVTerm*>( mCVTerms->remove(0) );
2891 delete mCVTerms;
2892 mCVTermsChanged = true;
2893 }
2894 mCVTerms = NULL;
2895
2896 if (mCVTerms != NULL)
2897 return LIBSBML_OPERATION_FAILED;
2898 else
2899 return LIBSBML_OPERATION_SUCCESS;
2900 }
2901
2902
2903 int
unsetModelHistory()2904 SBase::unsetModelHistory()
2905 {
2906 if (mHistory != NULL)
2907 mHistoryChanged = true;
2908
2909 delete mHistory;
2910 mHistory = NULL;
2911
2912 /* ModelHistory is only allowed on Model in L2
2913 * but on any element in L3
2914 */
2915 if (getLevel() < 3 && getTypeCode() != SBML_MODEL)
2916 {
2917 return LIBSBML_UNEXPECTED_ATTRIBUTE;
2918 }
2919
2920 if (mHistory != NULL)
2921 {
2922 return LIBSBML_OPERATION_FAILED;
2923 }
2924 else
2925 {
2926 return LIBSBML_OPERATION_SUCCESS;
2927 }
2928 }
2929
2930
2931 /*
2932 * Returns the BiologicalQualifier associated with this resource,
2933 * an empty string if the resource does not exist.
2934 *
2935 * @param resource string representing the resource; e.g.,
2936 * "http://www.geneontology.org/#GO:0005892".
2937 *
2938 * @return the BiolQualifierType_t associated with the resource
2939 */
2940 BiolQualifierType_t
getResourceBiologicalQualifier(std::string resource)2941 SBase::getResourceBiologicalQualifier(std::string resource)
2942 {
2943 if (mCVTerms != NULL)
2944 {
2945 for (unsigned int n = 0; n < mCVTerms->getSize(); n++)
2946 {
2947 // does this term have a biological qualifier
2948 if (static_cast <CVTerm *>(mCVTerms->get(n))->getQualifierType()
2949 == BIOLOGICAL_QUALIFIER)
2950 {
2951 // check whether given resource is present
2952 for (int r = 0;
2953 r < static_cast <CVTerm *>(mCVTerms->get(n))->getResources()->getLength(); r++)
2954 {
2955 if (resource ==
2956 static_cast <CVTerm *>(mCVTerms->get(n))->getResources()->getValue(r))
2957 {
2958 return static_cast <CVTerm *>(mCVTerms->get(n))->getBiologicalQualifierType();
2959 }
2960 }
2961 }
2962 }
2963 }
2964
2965 return BQB_UNKNOWN;
2966 }
2967
2968 /*
2969 * Returns the ModelQualifier associated with this resource,
2970 * an empty string if the resource does not exist.
2971 *
2972 * @param resource string representing the resource; e.g.,
2973 * "http://www.geneontology.org/#GO:0005892".
2974 *
2975 * @return the ModelQualifierType_t associated with the resource
2976 */
2977 ModelQualifierType_t
getResourceModelQualifier(std::string resource)2978 SBase::getResourceModelQualifier(std::string resource)
2979 {
2980 if (mCVTerms != NULL)
2981 {
2982 for (unsigned int n = 0; n < mCVTerms->getSize(); n++)
2983 {
2984 // does this term have a biological qualifier
2985 if (static_cast <CVTerm *>(mCVTerms->get(n))->getQualifierType()
2986 == MODEL_QUALIFIER)
2987 {
2988 // check whether given resource is present
2989 for (int r = 0;
2990 r < static_cast <CVTerm *>(mCVTerms->get(n))->getResources()->getLength(); r++)
2991 {
2992 if (resource ==
2993 static_cast <CVTerm *>(mCVTerms->get(n))->getResources()->getValue(r))
2994 {
2995 return static_cast <CVTerm *>(mCVTerms->get(n))->getModelQualifierType();
2996 }
2997 }
2998 }
2999 }
3000 }
3001
3002 return BQM_UNKNOWN;
3003 }
3004
3005
3006 /*
3007 * @return the parent Model of this SBML object.
3008 */
3009 const Model*
getModel() const3010 SBase::getModel () const
3011 {
3012 return (mSBML != NULL) ? mSBML->getModel() : NULL;
3013 }
3014
3015
3016 /*
3017 * @return the SBML level of this SBML object.
3018 */
3019 unsigned int
getLevel() const3020 SBase::getLevel () const
3021 {
3022 if (mSBML != NULL)
3023 return mSBML->mLevel;
3024 else if (mSBMLNamespaces != NULL)
3025 return mSBMLNamespaces->getLevel();
3026 else
3027 return SBMLDocument::getDefaultLevel();
3028 }
3029
3030
3031 /*
3032 * @return the SBML version of this SBML object.
3033 */
3034 unsigned int
getVersion() const3035 SBase::getVersion () const
3036 {
3037 if (mSBML != NULL)
3038 return mSBML->mVersion;
3039 else if (mSBMLNamespaces != NULL)
3040 return mSBMLNamespaces->getVersion();
3041 else
3042 return SBMLDocument::getDefaultVersion();
3043 }
3044
3045 /*
3046 * @return the SBML version of this SBML object.
3047 */
3048 unsigned int
getPackageCoreVersion() const3049 SBase::getPackageCoreVersion() const
3050 {
3051 const SBMLExtension* sbmlext = SBMLExtensionRegistry::getInstance().getExtensionInternal(mURI);
3052
3053 if (sbmlext)
3054 {
3055 return sbmlext->getVersion(mURI);
3056 }
3057 return 1;
3058 }
3059
3060 // ------------------------------------------------------------------
3061 //
3062 // functions to faciliate matlab binding
3063
3064 /** @cond doxygenLibsbmlInternal */
3065 int
getAttribute(const std::string & attributeName,double & value) const3066 SBase::getAttribute(const std::string& attributeName, double& value) const
3067 {
3068 return LIBSBML_OPERATION_FAILED;
3069 }
3070 /** @endcond */
3071
3072
3073 /** @cond doxygenLibsbmlInternal */
3074 int
getAttribute(const std::string & attributeName,bool & value) const3075 SBase::getAttribute(const std::string& attributeName, bool& value) const
3076 {
3077 return LIBSBML_OPERATION_FAILED;
3078 }
3079 /** @endcond */
3080
3081
3082 /** @cond doxygenLibsbmlInternal */
3083 int
getAttribute(const std::string & attributeName,int & value) const3084 SBase::getAttribute(const std::string& attributeName, int& value) const
3085 {
3086 if (attributeName == "sboTerm")
3087 {
3088 value = getSBOTerm();
3089 return LIBSBML_OPERATION_SUCCESS;
3090 }
3091 return LIBSBML_OPERATION_FAILED;
3092 }
3093 /** @endcond */
3094
3095
3096 /** @cond doxygenLibsbmlInternal */
3097 int
getAttribute(const std::string & attributeName,unsigned int & value) const3098 SBase::getAttribute(const std::string& attributeName, unsigned int& value) const
3099 {
3100 return LIBSBML_OPERATION_FAILED;
3101 }
3102 /** @endcond */
3103
3104
3105 /** @cond doxygenLibsbmlInternal */
3106 int
getAttribute(const std::string & attributeName,std::string & value) const3107 SBase::getAttribute(const std::string& attributeName, std::string& value) const
3108 {
3109 if (attributeName == "metaid")
3110 {
3111 value = getMetaId();
3112 return LIBSBML_OPERATION_SUCCESS;
3113 }
3114 else if (attributeName == "id")
3115 {
3116 value = getIdAttribute();
3117 return LIBSBML_OPERATION_SUCCESS;
3118 }
3119 else if (attributeName == "name")
3120 {
3121 value = getName();
3122 return LIBSBML_OPERATION_SUCCESS;
3123 }
3124 else if (attributeName == "sboTerm")
3125 {
3126 value = getSBOTermID();
3127 return LIBSBML_OPERATION_SUCCESS;
3128 }
3129
3130
3131 return LIBSBML_OPERATION_FAILED;
3132 }
3133 /** @endcond */
3134
3135
3136 /** @cond doxygenLibsbmlInternal */
3137 //int
3138 //SBase::getAttribute(const std::string& attributeName, const char * value) const
3139 //{
3140 // if (attributeName == "metaid")
3141 // {
3142 // value = getMetaId().c_str();
3143 // return LIBSBML_OPERATION_SUCCESS;
3144 // }
3145 // else if (attributeName == "id")
3146 // {
3147 // value = getIdAttribute().c_str();
3148 // return LIBSBML_OPERATION_SUCCESS;
3149 // }
3150 // else if (attributeName == "name")
3151 // {
3152 // value = getName().c_str();
3153 // return LIBSBML_OPERATION_SUCCESS;
3154 // }
3155 // else if (attributeName == "sboTerm")
3156 // {
3157 // value = getSBOTermID().c_str();
3158 // return LIBSBML_OPERATION_SUCCESS;
3159 // }
3160 //
3161 //
3162 // return LIBSBML_OPERATION_FAILED;
3163 //}
3164 /** @endcond */
3165
3166
3167 /** @cond doxygenLibsbmlInternal */
3168 bool
isSetAttribute(const std::string & attributeName) const3169 SBase::isSetAttribute(const std::string& attributeName) const
3170 {
3171 bool value = false;
3172 if (attributeName == "metaid")
3173 {
3174 value = isSetMetaId();
3175 }
3176 else if (attributeName == "id")
3177 {
3178 value = isSetIdAttribute();
3179 }
3180 else if (attributeName == "name")
3181 {
3182 value = isSetName();
3183 }
3184 else if (attributeName == "sboTerm")
3185 {
3186 value = isSetSBOTerm();
3187 }
3188
3189
3190 return value;
3191 }
3192 /** @endcond */
3193
3194
3195 /** @cond doxygenLibsbmlInternal */
3196 int
setAttribute(const std::string & attributeName,double value)3197 SBase::setAttribute(const std::string& attributeName, double value)
3198 {
3199 return LIBSBML_OPERATION_FAILED;
3200 }
3201 /** @endcond */
3202
3203
3204 /** @cond doxygenLibsbmlInternal */
3205 int
setAttribute(const std::string & attributeName,bool value)3206 SBase::setAttribute(const std::string& attributeName, bool value)
3207 {
3208 return LIBSBML_OPERATION_FAILED;
3209 }
3210 /** @endcond */
3211
3212
3213 /** @cond doxygenLibsbmlInternal */
3214 int
setAttribute(const std::string & attributeName,int value)3215 SBase::setAttribute(const std::string& attributeName, int value)
3216 {
3217 int return_value = LIBSBML_OPERATION_FAILED;
3218
3219 if (attributeName == "sboTerm")
3220 {
3221 return_value = setSBOTerm(value);
3222 }
3223
3224 return return_value;
3225 }
3226 /** @endcond */
3227
3228
3229 /** @cond doxygenLibsbmlInternal */
3230 int
setAttribute(const std::string & attributeName,unsigned int value)3231 SBase::setAttribute(const std::string& attributeName, unsigned int value)
3232 {
3233 return LIBSBML_OPERATION_FAILED;
3234 }
3235 /** @endcond */
3236
3237
3238 /** @cond doxygenLibsbmlInternal */
3239 int
setAttribute(const std::string & attributeName,const std::string & value)3240 SBase::setAttribute(const std::string& attributeName, const std::string& value)
3241 {
3242 int return_value = LIBSBML_OPERATION_FAILED;
3243 if (attributeName == "metaid")
3244 {
3245 return_value = setMetaId(value);
3246 }
3247 else if (attributeName == "id")
3248 {
3249 return_value = setIdAttribute(value);
3250 }
3251 else if (attributeName == "name")
3252 {
3253 return_value = setName(value);
3254 }
3255 else if (attributeName == "sboTerm")
3256 {
3257 return_value = setSBOTerm(value);
3258 }
3259
3260
3261 return return_value;
3262 }
3263 /** @endcond */
3264
3265
3266 /** @cond doxygenLibsbmlInternal */
3267 //int
3268 //SBase::setAttribute(const std::string& attributeName, const char * value)
3269 //{
3270 // int return_value = LIBSBML_OPERATION_FAILED;
3271 // if (attributeName == "metaid")
3272 // {
3273 // return_value = setMetaId(value);
3274 // }
3275 // else if (attributeName == "id")
3276 // {
3277 // return_value = setIdAttribute(value);
3278 // }
3279 // else if (attributeName == "name")
3280 // {
3281 // return_value = setName(value);
3282 // }
3283 // else if (attributeName == "sboTerm")
3284 // {
3285 // return_value = setSBOTerm(value);
3286 // }
3287 //
3288 // return return_value;
3289 //}
3290 /** @endcond */
3291
3292
3293 /** @cond doxygenLibsbmlInternal */
3294 int
unsetAttribute(const std::string & attributeName)3295 SBase::unsetAttribute(const std::string& attributeName)
3296 {
3297 int value = LIBSBML_OPERATION_FAILED;
3298 if (attributeName == "metaid")
3299 {
3300 value = unsetMetaId();
3301 }
3302 else if (attributeName == "id")
3303 {
3304 value = unsetIdAttribute();
3305 }
3306 else if (attributeName == "name")
3307 {
3308 value = unsetName();
3309 }
3310 else if (attributeName == "sboTerm")
3311 {
3312 value = unsetSBOTerm();
3313 }
3314
3315
3316 return value;
3317 }
3318 /** @endcond */
3319
3320 /** @cond doxygenLibsbmlInternal */
3321 SBase*
createChildObject(const std::string & elementName)3322 SBase::createChildObject(const std::string& elementName)
3323 {
3324 return NULL;
3325 }
3326 /** @endcond */
3327
3328 /** @cond doxygenLibsbmlInternal */
3329 int
addChildObject(const std::string & elementName,const SBase * element)3330 SBase::addChildObject(const std::string& elementName, const SBase* element)
3331 {
3332 return LIBSBML_OPERATION_FAILED;
3333 }
3334 /** @endcond */
3335
3336 /** @cond doxygenLibsbmlInternal */
3337 SBase*
removeChildObject(const std::string & elementName,const std::string & id)3338 SBase::removeChildObject(const std::string& elementName, const std::string& id)
3339 {
3340 return NULL;
3341 }
3342 /** @endcond */
3343
3344 /** @cond doxygenLibsbmlInternal */
3345
3346 unsigned int
getNumObjects(const std::string & objectName)3347 SBase::getNumObjects(const std::string& objectName)
3348 {
3349 return 0;
3350 }
3351
3352 /** @endcond */
3353
3354 /** @cond doxygenLibsbmlInternal */
3355
3356 SBase*
getObject(const std::string & objectName,unsigned int index)3357 SBase::getObject(const std::string& objectName, unsigned int index)
3358 {
3359 return NULL;
3360 }
3361
3362 /** @endcond */
3363 /** @cond doxygenLibsbmlInternal */
3364
3365 int
setMath(const ASTNode * math)3366 SBase::setMath(const ASTNode* math)
3367 {
3368 return LIBSBML_UNEXPECTED_ATTRIBUTE;
3369 }
3370
3371 int
setMessage(const std::string & message,bool addXHTMLMarkup)3372 SBase::setMessage (const std::string& message, bool addXHTMLMarkup)
3373 {
3374 return LIBSBML_UNEXPECTED_ATTRIBUTE;
3375 }
3376
3377 std::string
getMessageString() const3378 SBase::getMessageString () const
3379 {
3380 return mEmptyString;
3381 }
3382
3383
3384 const ASTNode*
getMath() const3385 SBase::getMath() const
3386 {
3387 return NULL;
3388 }
3389
3390
3391 bool
isSetMath() const3392 SBase::isSetMath() const
3393 {
3394 return getMath() != NULL;
3395 }
3396
3397
3398 /** @endcond */
3399
3400 /*
3401 * @return the version of package to which this SBML object
3402 * belongs to.
3403 * 0 will be returned if this element belongs to Core package.
3404 *
3405 * @see getLevel()
3406 * @see getVersion()
3407 */
3408 unsigned int
getPackageVersion() const3409 SBase::getPackageVersion () const
3410 {
3411 const SBMLExtension* sbmlext = SBMLExtensionRegistry::getInstance().getExtensionInternal(mURI);
3412
3413 if (sbmlext)
3414 {
3415 return sbmlext->getPackageVersion(mURI);
3416 }
3417
3418 return 0;
3419 }
3420
3421
3422 /*
3423 * Returns the name of package in which this element is defined.
3424 *
3425 */
3426 const std::string&
getPackageName() const3427 SBase::getPackageName () const
3428 {
3429 if (SBMLNamespaces::isSBMLNamespace(mURI))
3430 {
3431 static const std::string pkgName = "core";
3432 return pkgName;
3433 }
3434
3435 const SBMLExtension* sbmlext = SBMLExtensionRegistry::getInstance().getExtensionInternal(mURI);
3436
3437 if (sbmlext)
3438 {
3439 return sbmlext->getName();
3440 }
3441
3442 static const std::string pkgName = "unknown";
3443 return pkgName;
3444 }
3445
3446
3447 /*
3448 * @return the typecode (int) of this SBML object.
3449 */
3450 int
getTypeCode() const3451 SBase::getTypeCode () const
3452 {
3453 return SBML_UNKNOWN;
3454 }
3455
3456
3457 const std::string&
getElementName() const3458 SBase::getElementName () const
3459 {
3460 static const std::string name = "unknown";
3461 return name;
3462 }
3463
3464 //
3465 //
3466 // (EXTENSION)
3467 //
3468 //
3469
3470
3471 /*
3472 * Returns a plugin object (extenstion interface) of package extension
3473 * with the given package name or URI.
3474 *
3475 * @param package the name or URI of the package.
3476 *
3477 * @return the plugin object of package extension with the given package
3478 * name or URI.
3479 */
3480 SBasePlugin*
getPlugin(const std::string & package)3481 SBase::getPlugin(const std::string& package)
3482 {
3483 SBasePlugin* sbPlugin = 0;
3484
3485 for (size_t i=0; i < mPlugins.size(); i++)
3486 {
3487 std::string uri = mPlugins[i]->getURI();
3488 const SBMLExtension* sbext = SBMLExtensionRegistry::getInstance().getExtensionInternal(uri);
3489 if (uri == package)
3490 {
3491 sbPlugin = mPlugins[i];
3492 break;
3493 }
3494 else if (sbext && (sbext->getName() == package) )
3495 {
3496 sbPlugin = mPlugins[i];
3497 break;
3498 }
3499 }
3500
3501 return sbPlugin;
3502 }
3503
3504
3505 /*
3506 * Returns a plugin object (extenstion interface) of package extension
3507 * with the given package name or URI.
3508 *
3509 * @param package the name or URI of the package.
3510 *
3511 * @return the plugin object of package extension with the given package
3512 * name or URI.
3513 */
3514 const SBasePlugin*
getPlugin(const std::string & package) const3515 SBase::getPlugin(const std::string& package) const
3516 {
3517 return const_cast<SBase*>(this)->getPlugin(package);
3518 }
3519
3520
3521 SBasePlugin*
getPlugin(unsigned int n)3522 SBase::getPlugin(unsigned int n)
3523 {
3524 if (n>=getNumPlugins()) return NULL;
3525 return mPlugins[n];
3526 }
3527
3528
3529 SBasePlugin*
getDisabledPlugin(unsigned int n)3530 SBase::getDisabledPlugin(unsigned int n)
3531 {
3532 if (n>=getNumDisabledPlugins()) return NULL;
3533 return mDisabledPlugins[n];
3534 }
3535
3536
3537 /*
3538 * Returns a plugin object (extenstion interface) of package extension
3539 * with the given package name or URI.
3540 *
3541 * @param package the name or URI of the package.
3542 *
3543 * @return the plugin object of package extension with the given package
3544 * name or URI.
3545 */
3546 const SBasePlugin*
getPlugin(unsigned int n) const3547 SBase::getPlugin(unsigned int n) const
3548 {
3549 return const_cast<SBase*>(this)->getPlugin(n);
3550 }
3551
3552
3553 const SBasePlugin*
getDisabledPlugin(unsigned int n) const3554 SBase::getDisabledPlugin(unsigned int n) const
3555 {
3556 return const_cast<SBase*>(this)->getDisabledPlugin(n);
3557 }
3558
3559
3560 /*
3561 * Returns the number of plugin objects of package extensions.
3562 *
3563 * @return the number of plugin objects of package extensions.
3564 */
3565 unsigned int
getNumPlugins() const3566 SBase::getNumPlugins() const
3567 {
3568 return (unsigned int)mPlugins.size();
3569 }
3570
3571 unsigned int
getNumDisabledPlugins() const3572 SBase::getNumDisabledPlugins() const
3573 {
3574 return (unsigned int)mDisabledPlugins.size();
3575 }
3576
3577 void
deleteDisabledPlugins(bool recursive)3578 SBase::deleteDisabledPlugins(bool recursive /*= true*/)
3579 {
3580 for_each(mDisabledPlugins.begin(), mDisabledPlugins.end(), DeletePluginEntity());
3581 mDisabledPlugins.clear();
3582
3583 if (recursive)
3584 {
3585 List* list = getAllElements();
3586 for (ListIterator iter = list->begin(); iter != list->end(); ++iter)
3587 {
3588 (static_cast<SBase*>(*iter))->deleteDisabledPlugins();
3589 }
3590 delete list;
3591 }
3592
3593 }
3594
3595 int
disablePackage(const std::string & pkgURI,const std::string & prefix)3596 SBase::disablePackage(const std::string& pkgURI, const std::string& prefix)
3597 {
3598 return enablePackage(pkgURI, prefix, false);
3599 }
3600
3601 /*
3602 * Enables/Disables the given package with this object.
3603 */
3604 int
enablePackage(const std::string & pkgURI,const std::string & prefix,bool flag)3605 SBase::enablePackage(const std::string& pkgURI, const std::string& prefix, bool flag)
3606 {
3607 //
3608 // Checks if the package with the given URI is already enabled/disabled with
3609 // this element.
3610 //
3611 int success = LIBSBML_OPERATION_SUCCESS;
3612
3613 if (flag)
3614 {
3615 if (isPackageURIEnabled(pkgURI))
3616 {
3617 return success;
3618 }
3619 else if (mSBML != NULL && mSBML->isIgnoredPackage(pkgURI) == true)
3620 {
3621 return success;
3622 }
3623 }
3624 else
3625 {
3626 if (!isPackageURIEnabled(pkgURI))
3627 {
3628 if (mSBML == NULL)
3629 {
3630 return success;
3631
3632 }
3633 else if (mSBML->isIgnoredPackage(pkgURI) == false)
3634 {
3635 return success;
3636 }
3637 }
3638 }
3639
3640 // if we are dealing with an unknown package it will not be in the register
3641 if (mSBML == NULL
3642 || (mSBML != NULL && mSBML->isIgnoredPackage(pkgURI) == false
3643 && mSBML->isDisabledIgnoredPackage(pkgURI) == false))
3644 {
3645 //
3646 // Checks if the given pkgURI is registered in SBMLExtensionRegistry
3647 //
3648 if (!SBMLExtensionRegistry::getInstance().isRegistered(pkgURI))
3649 {
3650 return LIBSBML_PKG_UNKNOWN;
3651 }
3652
3653 const SBMLExtension *sbmlext =
3654 SBMLExtensionRegistry::getInstance().getExtensionInternal(pkgURI);
3655
3656 //
3657 // Checks version conflicts of the given package
3658 //
3659 if (flag && isPackageEnabled(sbmlext->getName()))
3660 {
3661 return LIBSBML_PKG_CONFLICTED_VERSION;
3662 }
3663
3664 //
3665 // Checks if the SBML Level and Version of the given pkgURI is
3666 // consistent with those of this object.
3667 //
3668 /* if we happen to be using layout in L2 we cannot do the version
3669 * check since the uri has no way of telling which sbml version is being used.
3670 */
3671 if (sbmlext->getName() == "layout" || sbmlext->getName() == "render" )
3672 {
3673 if (sbmlext->getLevel(pkgURI) != getLevel() )
3674 {
3675 return LIBSBML_PKG_VERSION_MISMATCH;
3676 }
3677 }
3678 // we decided l3v1 packages would work with l3v2 so dont force the version
3679 // to be the same
3680 //else if ( (sbmlext->getLevel(pkgURI) != getLevel() ) ||
3681 // (sbmlext->getVersion(pkgURI) != getVersion())
3682 // )
3683 else if (sbmlext->getLevel(pkgURI) != getLevel() )
3684 {
3685 return LIBSBML_PKG_VERSION_MISMATCH;
3686 }
3687
3688 }
3689
3690 SBase* rootElement = getRootElement();
3691 rootElement->enablePackageInternal(pkgURI,prefix,flag);
3692
3693 return LIBSBML_OPERATION_SUCCESS;
3694 }
3695
3696 /** @cond doxygenLibsbmlInternal */
3697 /*
3698 * Enables/Disables the given package with this element and child
3699 * elements (if any).
3700 * (This is an internal implementation for enablePackage function)
3701 */
3702 void
enablePackageInternal(const std::string & pkgURI,const std::string & pkgPrefix,bool flag)3703 SBase::enablePackageInternal(const std::string& pkgURI, const std::string& pkgPrefix, bool flag)
3704 {
3705 if (flag)
3706 {
3707 if (mSBMLNamespaces)
3708 {
3709 #if 0
3710 cout << "[DEBUG] SBase::enablePackageInternal() (uri) " << pkgURI
3711 << " (prefix) " << pkgPrefix << " (element) " << getElementName() << endl;
3712 #endif
3713 mSBMLNamespaces->addNamespace(pkgURI, pkgPrefix);
3714 }
3715
3716 //
3717 // go through disabled plugins, and if we have one re-enable that one, rather
3718 // than creating a new one
3719 //
3720
3721 bool wasDisabled = false;
3722 int numDisabledPlugins = (int)mDisabledPlugins.size();
3723 for (int i = numDisabledPlugins - 1; i >= 0; --i)
3724 {
3725 SBasePlugin *current = mDisabledPlugins[(size_t)i];
3726 std::string uri = current->getURI();
3727 if (pkgURI == uri)
3728 {
3729 mDisabledPlugins.erase(mDisabledPlugins.begin() + i);
3730 current->connectToParent(this);
3731 mPlugins.push_back(current);
3732 wasDisabled = true;
3733 }
3734 }
3735
3736
3737 if (!wasDisabled)
3738 {
3739 //
3740 // enable the given package
3741 //
3742 const SBMLExtension* sbmlext = SBMLExtensionRegistry::getInstance().getExtensionInternal(pkgURI);
3743
3744 if (sbmlext)
3745 {
3746 SBaseExtensionPoint extPoint(getPackageName(), getTypeCode(), getElementName());
3747 const SBasePluginCreatorBase* sbPluginCreator = sbmlext->getSBasePluginCreator(extPoint);
3748 // trully awful hack for the case where we are adding a plugin to a modelDefinition
3749 // since these do not have plugins the plugin creator is NULL
3750 // we have to force it to realise it is also a core model
3751 if (sbPluginCreator == NULL && getPackageName() == "comp" && getElementName() == "modelDefinition")
3752 {
3753 SBaseExtensionPoint coreextPoint("core", SBML_MODEL, "model");
3754 sbPluginCreator = sbmlext->getSBasePluginCreator(coreextPoint);
3755
3756 }
3757 if (sbPluginCreator)
3758 {
3759 SBasePlugin* entity = sbPluginCreator->createPlugin(pkgURI, pkgPrefix, getNamespaces());
3760 entity->connectToParent(this);
3761 mPlugins.push_back(entity);
3762 }
3763 }
3764
3765 }
3766 /* check whether we are trying to reenable an unknown package
3767 * that we previously disabled
3768 */
3769 for (int i = 0; i < mAttributesOfUnknownDisabledPkg.getLength();)
3770 {
3771 if (pkgURI == mAttributesOfUnknownDisabledPkg.getURI(i)
3772 && pkgPrefix == mAttributesOfUnknownDisabledPkg.getPrefix(i))
3773 {
3774 mAttributesOfUnknownPkg.add(
3775 mAttributesOfUnknownDisabledPkg.getName(i),
3776 mAttributesOfUnknownDisabledPkg.getValue(i), pkgURI, pkgPrefix);
3777 mAttributesOfUnknownDisabledPkg.remove(i);
3778 }
3779 else {
3780 i++;
3781 }
3782 }
3783 for (unsigned int i = 0; i < mElementsOfUnknownDisabledPkg.getNumChildren();)
3784 {
3785 if (pkgURI == mElementsOfUnknownDisabledPkg.getChild(i).getURI()
3786 && pkgPrefix == mElementsOfUnknownDisabledPkg.getChild(i).getPrefix())
3787 {
3788 mElementsOfUnknownPkg.addChild(mElementsOfUnknownDisabledPkg.getChild(i));
3789 XMLNode* removed = mElementsOfUnknownDisabledPkg.removeChild(i);
3790 delete removed;
3791 }
3792 else {
3793 i++;
3794 }
3795 }
3796 }
3797 else
3798 {
3799 //
3800 // disable the given package
3801 //
3802 int numPlugins = (int)mPlugins.size();
3803 for (int i=numPlugins-1; i >= 0; --i)
3804 {
3805 SBasePlugin *current = mPlugins[(size_t)i];
3806 std::string uri = current->getURI();
3807 if (pkgURI == uri)
3808 {
3809 mPlugins.erase( mPlugins.begin() + i );
3810 mDisabledPlugins.push_back(current);
3811 }
3812 }
3813
3814 if (mSBMLNamespaces)
3815 {
3816 mSBMLNamespaces->removeNamespace(pkgURI);
3817 }
3818
3819 /* before we remove the unknown package keep a copy
3820 * in case we try to re-enable it later
3821 */
3822 for (int i = 0; i < mAttributesOfUnknownPkg.getLength();)
3823 {
3824 if (pkgURI == mAttributesOfUnknownPkg.getURI(i)
3825 && pkgPrefix == mAttributesOfUnknownPkg.getPrefix(i))
3826 {
3827 mAttributesOfUnknownDisabledPkg.add(
3828 mAttributesOfUnknownPkg.getName(i),
3829 mAttributesOfUnknownPkg.getValue(i), pkgURI, pkgPrefix);
3830 mAttributesOfUnknownPkg.remove(i);
3831 }
3832 else {
3833 i++;
3834 }
3835 }
3836 for (unsigned int i = 0; i < mElementsOfUnknownPkg.getNumChildren();)
3837 {
3838 if (pkgURI == mElementsOfUnknownPkg.getChild(i).getURI()
3839 && pkgPrefix == mElementsOfUnknownPkg.getChild(i).getPrefix())
3840 {
3841 mElementsOfUnknownDisabledPkg.addChild(mElementsOfUnknownPkg.getChild(i));
3842 XMLNode* removed = mElementsOfUnknownPkg.removeChild(i);
3843 delete removed;
3844 }
3845 else {
3846 i++;
3847 }
3848 }
3849 }
3850
3851 /* ---------------------------------------------------------
3852 *
3853 * (EXTENSION)
3854 *
3855 * ----------------------------------------------------------
3856 */
3857
3858 for (size_t i=0; i < mPlugins.size(); i++)
3859 {
3860 mPlugins[i]->enablePackageInternal(pkgURI,pkgPrefix,flag);
3861 }
3862 }
3863 /** @endcond */
3864
3865
3866 /*
3867 * Predicate returning @c true if
3868 * the a package with the given URI is enabled with this object.
3869 *
3870 * @param pkgURI the URI of the package.
3871 *
3872 * @return @c true if the given package is enabled with this object,
3873 * @c false otherwise.
3874 */
3875 bool
isPackageURIEnabled(const std::string & pkgURI) const3876 SBase::isPackageURIEnabled(const std::string& pkgURI) const
3877 {
3878 for (size_t i=0; i < mPlugins.size(); i++)
3879 {
3880 if (mPlugins[i]->getURI() == pkgURI)
3881 return true;
3882 }
3883 return false;
3884 }
3885
3886
3887 /*
3888 * Predicate returning @c true if
3889 * the a package with the given URI is enabled with this object.
3890 *
3891 * @param pkgURI the URI of the package.
3892 *
3893 * @return @c true if the given package is enabled with this object,
3894 * @c false otherwise.
3895 */
3896 bool
isPkgURIEnabled(const std::string & pkgURI) const3897 SBase::isPkgURIEnabled(const std::string& pkgURI) const
3898 {
3899 return isPackageURIEnabled(pkgURI);
3900 }
3901
3902 /*
3903 * Predicate returning @c true if
3904 * the given package (don't care the package version) is enabled with
3905 * this object.
3906 *
3907 * @param pkgName the URI of the package.
3908 *
3909 * @return @c true if the given package is enabled with this object,
3910 * @c false otherwise.
3911 */
3912 bool
isPackageEnabled(const std::string & pkgName) const3913 SBase::isPackageEnabled(const std::string& pkgName) const
3914 {
3915 for (size_t i=0; i < mPlugins.size(); i++)
3916 {
3917 if (mPlugins[i]->getPackageName() == pkgName)
3918 return true;
3919 }
3920 return false;
3921 }
3922
3923 /*
3924 * Predicate returning @c true if
3925 * the given package (don't care the package version) is enabled with
3926 * this object.
3927 *
3928 * @param pkgName the URI of the package.
3929 *
3930 * @return @c true if the given package is enabled with this object,
3931 * @c false otherwise.
3932 */
3933 bool
isPkgEnabled(const std::string & pkgName) const3934 SBase::isPkgEnabled(const std::string& pkgName) const
3935 {
3936 return isPackageEnabled(pkgName);
3937 }
3938
3939 bool
hasValidLevelVersionNamespaceCombination()3940 SBase::hasValidLevelVersionNamespaceCombination()
3941 {
3942 int typecode = getTypeCode();
3943 XMLNamespaces *xmlns = getNamespaces();
3944
3945 return hasValidLevelVersionNamespaceCombination(typecode, xmlns);
3946 }
3947
3948 /** @cond doxygenLibsbmlInternal */
3949 bool
matchesSBMLNamespaces(const SBase * sb)3950 SBase::matchesSBMLNamespaces(const SBase * sb)
3951 {
3952 bool match = matchesCoreSBMLNamespace(sb);
3953
3954 if (match == true)
3955 {
3956 SBMLNamespaces *sbmlns = getSBMLNamespaces();
3957 SBMLNamespaces *sbmlns_rhs = sb->getSBMLNamespaces();
3958
3959 if (sbmlns->getNamespaces()->containIdenticalSetNS(
3960 sbmlns_rhs->getNamespaces()) == false)
3961 {
3962 match = false;
3963 }
3964 }
3965
3966 return match;
3967 }
3968
3969 bool
matchesSBMLNamespaces(const SBase * sb) const3970 SBase::matchesSBMLNamespaces(const SBase * sb) const
3971 {
3972 bool match = matchesCoreSBMLNamespace(sb);
3973
3974 if (match == true)
3975 {
3976 SBMLNamespaces *sbmlns = getSBMLNamespaces();
3977 SBMLNamespaces *sbmlns_rhs = sb->getSBMLNamespaces();
3978
3979 if (sbmlns->getNamespaces()->containIdenticalSetNS(
3980 sbmlns_rhs->getNamespaces()) == false)
3981 {
3982 match = false;
3983 }
3984 }
3985
3986 return match;
3987 }
3988
3989
3990 bool
matchesRequiredSBMLNamespacesForAddition(const SBase * sb)3991 SBase::matchesRequiredSBMLNamespacesForAddition(const SBase * sb)
3992 {
3993 // if core does not match forget it
3994 bool match = matchesCoreSBMLNamespace(sb);
3995
3996 if (match == true)
3997 {
3998 XMLNamespaces *xmlns = getSBMLNamespaces()->getNamespaces();
3999 XMLNamespaces *xmlns_rhs = sb->getSBMLNamespaces()->getNamespaces();
4000
4001 // if child has a package it must match the parent
4002 for (int i = 0; i < xmlns_rhs->getNumNamespaces(); i++)
4003 {
4004 // look to see if the beginning f the uri looks like a package uri
4005 // and if there is a second 'version'
4006 std::string uri = xmlns_rhs->getURI(i);
4007 size_t version = uri.find("http://www.sbml.org/sbml/level3/version");
4008 if (version != string::npos)
4009 {
4010 version = uri.find("version", version+33);
4011 }
4012 if (version != string::npos)
4013 {
4014 if (xmlns->containsUri(uri) == false)
4015 {
4016 match = false;
4017 }
4018 }
4019 }
4020 }
4021
4022 return match;
4023 }
4024
4025
4026 bool
matchesRequiredSBMLNamespacesForAddition(const SBase * sb) const4027 SBase::matchesRequiredSBMLNamespacesForAddition(const SBase * sb) const
4028 {
4029 // if core does not match forget it
4030 bool match = matchesCoreSBMLNamespace(sb);
4031
4032 if (match == true)
4033 {
4034 XMLNamespaces *xmlns = getSBMLNamespaces()->getNamespaces();
4035 XMLNamespaces *xmlns_rhs = sb->getSBMLNamespaces()->getNamespaces();
4036
4037 // if child has a package it must match the parent
4038 for (int i = 0; i < xmlns_rhs->getNumNamespaces(); i++)
4039 {
4040 // look to see if the beginning f the uri looks like a package uri
4041 // and if there is a second 'version'
4042 std::string uri = xmlns_rhs->getURI(i);
4043 size_t version = uri.find("http://www.sbml.org/sbml/level3/version");
4044 if (version != string::npos)
4045 {
4046 version = uri.find("version", version+33);
4047 }
4048 if (version != string::npos)
4049 {
4050 if (xmlns->containsUri(uri) == false)
4051 {
4052 match = false;
4053 }
4054 }
4055 }
4056 }
4057
4058 return match;
4059 }
4060
4061
4062 bool
matchesCoreSBMLNamespace(const SBase * sb)4063 SBase::matchesCoreSBMLNamespace(const SBase * sb)
4064 {
4065 bool match = false;
4066
4067 SBMLNamespaces *sbmlns = getSBMLNamespaces();
4068 SBMLNamespaces *sbmlns_rhs = sb->getSBMLNamespaces();
4069
4070 if (sbmlns->getLevel() != sbmlns_rhs->getLevel())
4071 return match;
4072
4073 if (sbmlns->getVersion() != sbmlns_rhs->getVersion())
4074 return match;
4075
4076 std::string coreNs = SBMLNamespaces::getSBMLNamespaceURI(
4077 sbmlns->getLevel(), sbmlns->getVersion());
4078
4079 if (sbmlns->getNamespaces()->containsUri(coreNs)
4080 && sbmlns_rhs->getNamespaces()->containsUri(coreNs))
4081 {
4082 match = true;
4083 }
4084
4085 //if (sbmlns->getNamespaces()->containIdenticalSetNS(sbmlns_rhs->getNamespaces())
4086 // == true)
4087 //{
4088 // match = true;
4089 //}
4090
4091 return match;
4092 }
4093
4094
4095 bool
matchesCoreSBMLNamespace(const SBase * sb) const4096 SBase::matchesCoreSBMLNamespace(const SBase * sb) const
4097 {
4098 bool match = false;
4099
4100 SBMLNamespaces *sbmlns = getSBMLNamespaces();
4101 SBMLNamespaces *sbmlns_rhs = sb->getSBMLNamespaces();
4102
4103 if (sbmlns->getLevel() != sbmlns_rhs->getLevel())
4104 return match;
4105
4106 if (sbmlns->getVersion() != sbmlns_rhs->getVersion())
4107 return match;
4108
4109 std::string coreNs = SBMLNamespaces::getSBMLNamespaceURI(
4110 sbmlns->getLevel(), sbmlns->getVersion());
4111
4112 if (sbmlns->getNamespaces()->containsUri(coreNs)
4113 && sbmlns_rhs->getNamespaces()->containsUri(coreNs))
4114 {
4115 match = true;
4116 }
4117
4118 //if (sbmlns->getNamespaces()->containIdenticalSetNS(sbmlns_rhs->getNamespaces())
4119 // == true)
4120 //{
4121 // match = true;
4122 //}
4123
4124 return match;
4125 }
4126
4127
4128 bool
hasValidLevelVersionNamespaceCombination(int typecode,XMLNamespaces * xmlns)4129 SBase::hasValidLevelVersionNamespaceCombination(int typecode, XMLNamespaces *xmlns)
4130 {
4131
4132
4133 //
4134 // (TODO) Currently, the following check code works only for
4135 // elements in SBML core.
4136 // This function may need to be extented for other elements
4137 // defined in each package extension.
4138 //
4139
4140 bool valid = true;
4141 bool sbmlDeclared = false;
4142 std::string declaredURI("");
4143 unsigned int version = getVersion();
4144
4145 if (xmlns != NULL)
4146 {
4147 //
4148 // checks defined SBML XMLNamespace
4149 // returns false if different SBML XMLNamespaces
4150 // (e.g. SBML_XMLNS_L2V1 and SBML_XMLNS_L2V3) are defined.
4151 //
4152 int numNS = 0;
4153
4154 if (xmlns->hasURI(SBML_XMLNS_L3V2))
4155 {
4156 ++numNS;
4157 declaredURI.assign(SBML_XMLNS_L3V2);
4158 }
4159
4160 if (xmlns->hasURI(SBML_XMLNS_L3V1))
4161 {
4162 ++numNS;
4163 declaredURI.assign(SBML_XMLNS_L3V1);
4164 }
4165
4166 if (xmlns->hasURI(SBML_XMLNS_L2V5))
4167 {
4168 if (numNS > 0) return false;
4169 ++numNS;
4170 declaredURI.assign(SBML_XMLNS_L2V5);
4171 }
4172
4173 if (xmlns->hasURI(SBML_XMLNS_L2V4))
4174 {
4175 if (numNS > 0) return false;
4176 ++numNS;
4177 declaredURI.assign(SBML_XMLNS_L2V4);
4178 }
4179
4180 if (xmlns->hasURI(SBML_XMLNS_L2V3))
4181 {
4182 // checks different SBML XMLNamespaces
4183 if (numNS > 0) return false;
4184 ++numNS;
4185 declaredURI.assign(SBML_XMLNS_L2V3);
4186 }
4187
4188 if (xmlns->hasURI(SBML_XMLNS_L2V2))
4189 {
4190 // checks different SBML XMLNamespaces
4191 if (numNS > 0) return false;
4192 ++numNS;
4193 declaredURI.assign(SBML_XMLNS_L2V2);
4194 }
4195
4196 if (xmlns->hasURI(SBML_XMLNS_L2V1))
4197 {
4198 // checks different SBML XMLNamespaces
4199 if (numNS > 0) return false;
4200 ++numNS;
4201 declaredURI.assign(SBML_XMLNS_L2V1);
4202 }
4203
4204 if (xmlns->hasURI(SBML_XMLNS_L1))
4205 {
4206 // checks different SBML XMLNamespaces
4207 if (numNS > 0) return false;
4208 ++numNS;
4209 declaredURI.assign(SBML_XMLNS_L1);
4210 }
4211
4212 // checks if the SBML Namespace is explicitly defined.
4213 for (int i=0; i < xmlns->getLength(); i++)
4214 {
4215 if (!declaredURI.empty() &&
4216 xmlns->getURI(i) == declaredURI)
4217 {
4218 sbmlDeclared = true;
4219 break;
4220 }
4221 }
4222 }
4223
4224 const std::string& pkgName = getPackageName();
4225
4226 if (pkgName == "core")
4227 {
4228 // we need to consider whether it should be necessary to declare the sbml namespace.
4229 //if (!sbmlDeclared)
4230 // return false;
4231
4232 if (typecode == SBML_UNKNOWN)
4233 {
4234 valid = false;
4235 return valid;
4236 }
4237 switch (getLevel())
4238 {
4239 case 1:
4240 // some components didnt exist in level 1
4241 if ( typecode == SBML_COMPARTMENT_TYPE
4242 || typecode == SBML_CONSTRAINT
4243 || typecode == SBML_EVENT
4244 || typecode == SBML_EVENT_ASSIGNMENT
4245 || typecode == SBML_FUNCTION_DEFINITION
4246 || typecode == SBML_INITIAL_ASSIGNMENT
4247 || typecode == SBML_SPECIES_TYPE
4248 || typecode == SBML_MODIFIER_SPECIES_REFERENCE
4249 || typecode == SBML_TRIGGER
4250 || typecode == SBML_DELAY
4251 || typecode == SBML_STOICHIOMETRY_MATH
4252 || typecode == SBML_PRIORITY
4253 || typecode == SBML_LOCAL_PARAMETER)
4254 valid = false;
4255 switch (version)
4256 {
4257 case 1:
4258 case 2:
4259 // the namespaces contains the sbml namespaces
4260 // check it is the correct ns for the level/version
4261 if (sbmlDeclared)
4262 {
4263 if (declaredURI != string(SBML_XMLNS_L1))
4264 {
4265 valid = false;
4266 }
4267 }
4268 break;
4269 default:
4270 valid = false;
4271 break;
4272 }
4273 break;
4274 case 2:
4275 if ( typecode == SBML_PRIORITY
4276 || typecode == SBML_LOCAL_PARAMETER)
4277 valid = false;
4278 switch (version)
4279 {
4280 case 1:
4281 // some components didnt exist in l2v1
4282 if ( typecode == SBML_COMPARTMENT_TYPE
4283 || typecode == SBML_CONSTRAINT
4284 || typecode == SBML_INITIAL_ASSIGNMENT
4285 || typecode == SBML_SPECIES_TYPE)
4286 valid = false;
4287 // the namespaces contains the sbml namespaces
4288 // check it is the correct ns for the level/version
4289 if (sbmlDeclared)
4290 {
4291 if (declaredURI != string(SBML_XMLNS_L2V1))
4292 {
4293 valid = false;
4294 }
4295 }
4296 break;
4297 case 2:
4298 // the namespaces contains the sbml namespaces
4299 // check it is the correct ns for the level/version
4300 if (sbmlDeclared)
4301 {
4302 if (declaredURI != string(SBML_XMLNS_L2V2))
4303 {
4304 valid = false;
4305 }
4306 }
4307 break;
4308 case 3:
4309 // the namespaces contains the sbml namespaces
4310 // check it is the correct ns for the level/version
4311 if (sbmlDeclared)
4312 {
4313 if (declaredURI != string(SBML_XMLNS_L2V3))
4314 {
4315 valid = false;
4316 }
4317 }
4318 break;
4319 case 4:
4320 // the namespaces contains the sbml namespaces
4321 // check it is the correct ns for the level/version
4322 if (sbmlDeclared)
4323 {
4324 if (declaredURI != string(SBML_XMLNS_L2V4))
4325 {
4326 valid = false;
4327 }
4328 }
4329 break;
4330 case 5:
4331 // the namespaces contains the sbml namespaces
4332 // check it is the correct ns for the level/version
4333 if (sbmlDeclared)
4334 {
4335 if (declaredURI != string(SBML_XMLNS_L2V5))
4336 {
4337 valid = false;
4338 }
4339 }
4340 break;
4341 default:
4342 valid = false;
4343 break;
4344 }
4345 break;
4346 case 3:
4347 // some components no longer exist in level 3
4348 if ( typecode == SBML_COMPARTMENT_TYPE
4349 || typecode == SBML_SPECIES_TYPE
4350 || typecode == SBML_STOICHIOMETRY_MATH)
4351 valid = false;
4352 switch (version)
4353 {
4354 case 1:
4355 // the namespaces contains the sbml namespaces
4356 // check it is the correct ns for the level/version
4357 if (sbmlDeclared)
4358 {
4359 if (declaredURI != string(SBML_XMLNS_L3V1))
4360 {
4361 valid = false;
4362 }
4363 }
4364 break;
4365 case 2:
4366 // the namespaces contains the sbml namespaces
4367 // check it is the correct ns for the level/version
4368 if (sbmlDeclared)
4369 {
4370 if (declaredURI != string(SBML_XMLNS_L3V2))
4371 {
4372 valid = false;
4373 }
4374 }
4375 break;
4376 default:
4377 valid = false;
4378 break;
4379 }
4380 break;
4381 default:
4382 valid = false;
4383 break;
4384 }
4385 }
4386
4387 // if this is an extension namespace, this method will return the wrong answer,
4388 // so instead return true
4389 ISBMLExtensionNamespaces* test = dynamic_cast<ISBMLExtensionNamespaces*> (mSBMLNamespaces);
4390 if (!valid && test != NULL)
4391 return true;
4392
4393 return valid;
4394 }
4395
4396 /* sets the SBMLnamespaces - internal use only*/
4397 int
setSBMLNamespaces(SBMLNamespaces * sbmlns)4398 SBase::setSBMLNamespaces(SBMLNamespaces * sbmlns)
4399 {
4400 if (sbmlns == NULL)
4401 return LIBSBML_INVALID_OBJECT;
4402
4403 SBMLNamespaces* sbmlnsClone = (sbmlns) ? sbmlns->clone() : 0;
4404 setSBMLNamespacesAndOwn(sbmlnsClone);
4405
4406 return LIBSBML_OPERATION_SUCCESS;
4407 }
4408
4409 /*
4410 * sets the SBMLnamespaces - only for internal use in the
4411 * constructors of SBase subclasses in extension packages.
4412 */
4413 void
setSBMLNamespacesAndOwn(SBMLNamespaces * sbmlns)4414 SBase::setSBMLNamespacesAndOwn(SBMLNamespaces * sbmlns)
4415 {
4416 delete mSBMLNamespaces;
4417 mSBMLNamespaces = sbmlns;
4418
4419 if(sbmlns != NULL)
4420 setElementNamespace(sbmlns->getURI());
4421 }
4422
4423
4424 /* gets the SBMLnamespaces - internal use only*/
4425 SBMLNamespaces *
getSBMLNamespaces() const4426 SBase::getSBMLNamespaces() const
4427 {
4428 if (mSBML != NULL)
4429 return mSBML->mSBMLNamespaces;
4430
4431 // initialize SBML namespace if need be
4432 if (mSBMLNamespaces == NULL)
4433 const_cast<SBase*>(this)->mSBMLNamespaces = new SBMLNamespaces();
4434 return mSBMLNamespaces;
4435 }
4436 /** @endcond */
4437
4438
4439
4440 /*
4441 * @return the partial SBML that describes this SBML object.
4442 */
4443 char*
toSBML()4444 SBase::toSBML ()
4445 {
4446 ostringstream os;
4447 XMLOutputStream stream(os, "UTF-8", false);
4448
4449 write(stream);
4450
4451 return safe_strdup( os.str().c_str() );
4452 }
4453
4454
4455 /** @cond doxygenLibsbmlInternal */
4456 /*
4457 * Reads (initializes) this SBML object by reading from XMLInputStream.
4458 */
4459 void
read(XMLInputStream & stream)4460 SBase::read (XMLInputStream& stream)
4461 {
4462 if ( !stream.peek().isStart() ) return;
4463
4464 const XMLToken element = stream.next();
4465 int position = 0;
4466
4467 setSBaseFields( element );
4468
4469 ExpectedAttributes expectedAttributes;
4470 addExpectedAttributes(expectedAttributes);
4471 readAttributes( element.getAttributes(), expectedAttributes );
4472
4473 /* if we are reading a document pass the
4474 * SBML Namespace information to the input stream object
4475 * thus the MathML reader can find out what level/version
4476 * of SBML it is parsing
4477 */
4478 if (element.getName() == "sbml")
4479 {
4480 stream.setSBMLNamespaces(this->getSBMLNamespaces());
4481 // need to check that any prefix on the sbmlns also occurs on element
4482 // remembering the horrible situation where the sbmlns might be declared
4483 // with more than one prefix
4484 XMLNamespaces * xmlns = this->getSBMLNamespaces()->getNamespaces();
4485 if (xmlns != NULL)
4486 {
4487 int i = xmlns->getIndexByPrefix(element.getPrefix());
4488 if (i < xmlns->getNumNamespaces())
4489 {
4490 bool errorLoggedAlready = false;
4491 bool error = false;
4492 if (i > -1)
4493 {
4494 if (xmlns->getURI(i) != this->getSBMLNamespaces()->getURI())
4495 {
4496 error = true;
4497 }
4498 }
4499 else if ( i == -1)
4500 {
4501 error = true;
4502 }
4503
4504 /* if there is a mismatch in level/version this will already
4505 * be logged; do not need another error
4506 */
4507 for (unsigned int n = 0; n < this->getErrorLog()->getNumErrors(); n++)
4508 {
4509 unsigned int errorId =
4510 this->getErrorLog()->getError(n)->getErrorId();
4511 if (errorId == MissingOrInconsistentLevel
4512 || errorId == MissingOrInconsistentVersion
4513 || errorId == InvalidSBMLLevelVersion
4514 || errorId == InvalidNamespaceOnSBML)
4515 {
4516 errorLoggedAlready = true;
4517 }
4518 }
4519
4520 if (error == true && errorLoggedAlready == false)
4521 {
4522 static ostringstream errMsg;
4523 errMsg.str("");
4524 errMsg << "The prefix for the <sbml> element does not match "
4525 << "the prefix for the SBML namespace. This means that "
4526 << "the <sbml> element in not in the SBMLNamespace."<< endl;
4527
4528 logError(InvalidNamespaceOnSBML,
4529 getLevel(), getVersion(), errMsg.str());
4530 }
4531 }
4532 }
4533
4534 }
4535 else
4536 {
4537 //
4538 // checks if the given default namespace (if any) is a valid
4539 // SBML namespace
4540 //
4541 checkDefaultNamespace(mSBMLNamespaces->getNamespaces(), element.getName());
4542 if (!element.getPrefix().empty())
4543 {
4544 XMLNamespaces * prefixedNS = new XMLNamespaces();
4545 prefixedNS->add(element.getURI(), element.getPrefix());
4546 checkDefaultNamespace(prefixedNS, element.getName(), element.getPrefix());
4547 delete prefixedNS;
4548 }
4549 }
4550
4551 if ( element.isEnd() ) return;
4552
4553 while ( stream.isGood() )
4554 {
4555 if (CallbackRegistry::invokeCallbacks(getSBMLDocument()) != LIBSBML_OPERATION_SUCCESS)
4556 {
4557 if (getErrorLog() != NULL && !getErrorLog()->contains(OperationInterrupted))
4558 logError(OperationInterrupted, getLevel(), getVersion());
4559 break;
4560 }
4561
4562 // this used to skip the text
4563 // stream.skipText();
4564 // instead, read text and store in variable
4565 std::string text;
4566 while(stream.isGood() && stream.peek().isText())
4567 {
4568 text += stream.next().getCharacters();
4569 }
4570 setElementText(text);
4571
4572 const XMLToken& next = stream.peek();
4573
4574 // Re-check stream.isGood() because stream.peek() could hit something.
4575 if ( !stream.isGood() ) break;
4576
4577 if ( next.isEndFor(element) )
4578 {
4579 stream.next();
4580 break;
4581 }
4582 else if ( next.isStart() )
4583 {
4584 const std::string nextName = next.getName();
4585 #if 0
4586 cout << "[DEBUG] SBase::read " << nextName << " uri "
4587 << stream.peek().getURI() << endl;
4588 #endif
4589
4590 SBase * object = NULL;
4591 try
4592 {
4593 object = createObject(stream);
4594 }
4595 catch (const SBMLExtensionException&)
4596 {
4597 object = NULL;
4598 }
4599
4600 if (!object)
4601 {
4602 object = createExtensionObject(stream);
4603 }
4604
4605 if (object != NULL)
4606 {
4607 checkOrderAndLogError(object, position);
4608 position = object->getElementPosition();
4609
4610 object->connectToParent(static_cast <SBase*>(this));
4611
4612 object->read(stream);
4613
4614 if ( !stream.isGood() ) break;
4615
4616 if (object->getPackageName() == "core"
4617 && object->getTypeCode() == SBML_SPECIES_REFERENCE
4618 && object->getLevel() > 1)
4619 {
4620 static_cast <SpeciesReference *> (object)->sortMath();
4621 }
4622 checkListOfPopulated(object);
4623 }
4624 else if ( !( storeUnknownExtElement(stream)
4625 || readOtherXML(stream)
4626 || readAnnotation(stream)
4627 || readNotes(stream) ))
4628 {
4629 logUnknownElement(nextName, getLevel(), getVersion());
4630 stream.skipPastEnd( stream.next() );
4631 }
4632 }
4633 else
4634 {
4635 stream.skipPastEnd( stream.next() );
4636 }
4637 }
4638 }
4639 /** @endcond */
4640
4641
4642 void
setElementText(const std::string &)4643 SBase::setElementText(const std::string &)
4644 {
4645 }
4646
4647 /** @cond doxygenLibsbmlInternal */
4648 /*
4649 * Writes (serializes) this SBML object by writing it to XMLOutputStream.
4650 */
4651 void
write(XMLOutputStream & stream) const4652 SBase::write (XMLOutputStream& stream) const
4653 {
4654
4655 #if 0
4656 XMLNamespaces *xmlns = getNamespaces();
4657 {
4658 cout << "[DEBUG] SBase::write (element name) " << getElementName()
4659 << " (element ns) " << getElementNamespace();
4660
4661 if (xmlns)
4662 {
4663 cout << " (xmlns) ";
4664 XMLOutputStream xos(std::cout);
4665 xos << *xmlns;
4666 cout << endl;
4667 }
4668
4669 }
4670 #endif
4671
4672 stream.startElement( getElementName(), getPrefix() );
4673
4674 writeXMLNS ( stream );
4675 writeAttributes( stream );
4676 writeElements ( stream );
4677
4678 stream.endElement( getElementName(), getPrefix() );
4679
4680 }
4681 /** @endcond */
4682
4683
4684 /** @cond doxygenLibsbmlInternal */
4685 /*
4686 * Subclasses should override this method to write out their contained
4687 * SBML objects as XML elements. Be sure to call your parent's
4688 * implementation of this method as well.
4689 */
4690 void
writeElements(XMLOutputStream & stream) const4691 SBase::writeElements (XMLOutputStream& stream) const
4692 {
4693 if (mNotes != NULL)
4694 {
4695 mNotes->writeToStream(stream);
4696 }
4697
4698 /*
4699 * NOTE: CVTerms on a model have already been dealt with
4700 */
4701
4702 const_cast <SBase *> (this)->syncAnnotation();
4703 if (mAnnotation != NULL) stream << *mAnnotation;
4704 }
4705
4706 void
writeExtensionElements(XMLOutputStream & stream) const4707 SBase::writeExtensionElements (XMLOutputStream& stream) const
4708 {
4709 /* ---------------------------------------------------------
4710 *
4711 * (EXTENSION)
4712 *
4713 * ----------------------------------------------------------
4714 */
4715
4716 for (size_t i=0; i < mPlugins.size(); i++)
4717 {
4718 mPlugins[i]->writeElements(stream);
4719 }
4720
4721 //
4722 // writes elements of unkown packages
4723 //
4724 if (getLevel() > 2)
4725 {
4726 stream << mElementsOfUnknownPkg;
4727 }
4728
4729 /////////////////////////////////////////////////////////////////////////
4730
4731 }
4732 /** @endcond */
4733
4734
4735 /** @cond doxygenLibsbmlInternal */
4736 /*
4737 * Subclasses should override this method to create, store, and then
4738 * return an SBML object corresponding to the next XMLToken in the
4739 * XMLInputStream.
4740 *
4741 * @return the SBML object corresponding to next XMLToken in the
4742 * XMLInputStream or @c NULL if the token was not recognized.
4743 */
4744 SBase*
createObject(XMLInputStream &)4745 SBase::createObject (XMLInputStream&)
4746 {
4747 return NULL;
4748 }
4749
4750
4751 SBase*
createExtensionObject(XMLInputStream & stream)4752 SBase::createExtensionObject (XMLInputStream& stream)
4753 {
4754 SBase* object = NULL;
4755
4756 /* ---------------------------------------------------------
4757 *
4758 * (EXTENSION)
4759 *
4760 * ----------------------------------------------------------
4761 */
4762
4763 const string& uri = stream.peek().getURI();
4764 SBasePlugin* sbext = NULL;
4765
4766 for (size_t i=0; i < mPlugins.size(); i++)
4767 {
4768 if (mPlugins[i]->getURI() == uri)
4769 {
4770 sbext = mPlugins[i];
4771 break;
4772 }
4773 }
4774
4775 if (sbext)
4776 {
4777 #if 0
4778 std::cout << "[DEBUG] SBase::createExtensionObject " << getElementName()
4779 << " " << uri << std::endl;
4780 #endif
4781 try
4782 {
4783 object = sbext->createObject(stream);
4784 }
4785 catch (const SBMLExtensionException&)
4786 {
4787 object = NULL;
4788 }
4789 }
4790 #if 0
4791 else
4792 {
4793 std::cout << "[DEBUG] SBase::createExtensionObject " << getElementName()
4794 << " " << uri << " is NULL" << std::endl;
4795 }
4796 #endif
4797
4798 /////////////////////////////////////////////////////////////////////////
4799
4800 return object;
4801 }
4802 /** @endcond */
4803
4804
4805 /** @cond doxygenLibsbmlInternal */
4806 /*
4807 * Subclasses should override this method to read (and store) XHTML,
4808 * MathML, etc. directly from the XMLInputStream.
4809 *
4810 * @return @c true if the subclass read from the stream, false otherwise.
4811 */
4812 bool
readOtherXML(XMLInputStream & stream)4813 SBase::readOtherXML (XMLInputStream& stream)
4814 {
4815 /* ---------------------------------------------------------
4816 *
4817 * (EXTENSION)
4818 *
4819 * ----------------------------------------------------------
4820 */
4821
4822 bool read = false;
4823
4824 for (size_t i=0; i < mPlugins.size(); i++)
4825 {
4826 if (mPlugins[i]->readOtherXML(this, stream))
4827 read = true;
4828 }
4829
4830 return read;
4831 }
4832 /** @endcond */
4833
4834
4835 /** @cond doxygenLibsbmlInternal */
4836 /*
4837 * @return @c true if read an <annotation> element from the stream
4838 */
4839 bool
readAnnotation(XMLInputStream & stream)4840 SBase::readAnnotation (XMLInputStream& stream)
4841 {
4842 const string& name = stream.peek().getName();
4843
4844 unsigned int level = getLevel();
4845
4846 if (name == "annotation"
4847 || (level == 1 && getVersion() == 1 && name == "annotations"))
4848 {
4849 // XMLNode* new_annotation = NULL;
4850 // If this is a level 1 document then annotations are not allowed on
4851 // the sbml container
4852 if (level == 1 && getTypeCode() == SBML_DOCUMENT)
4853 {
4854 logError(AnnotationNotesNotAllowedLevel1);
4855 }
4856
4857
4858 // If an annotation already exists, log it as an error and replace
4859 // the content of the existing annotation with the new one.
4860
4861 if (mAnnotation != NULL)
4862 {
4863 string msg = "An SBML <" + getElementName() + "> element ";
4864 switch(getTypeCode()) {
4865 case SBML_INITIAL_ASSIGNMENT:
4866 case SBML_EVENT_ASSIGNMENT:
4867 case SBML_ASSIGNMENT_RULE:
4868 case SBML_RATE_RULE:
4869 //LS DEBUG: could use other attribute values, or 'isSetActualId'.
4870 break;
4871 default:
4872 if (isSetId()) {
4873 msg += "with id '" + getId() + "' ";
4874 }
4875 break;
4876 }
4877 msg += "has multiple <annotation> children.";
4878 if (getLevel() < 3)
4879 {
4880 logError(NotSchemaConformant, getLevel(), getVersion(),
4881 "Only one <annotation> element is permitted inside a "
4882 "particular containing element. " + msg);
4883 }
4884 else
4885 {
4886 logError(MultipleAnnotations, getLevel(), getVersion(), msg);
4887 }
4888 }
4889
4890 delete mAnnotation;
4891 mAnnotation = new XMLNode(stream);
4892 checkAnnotation();
4893 if(mCVTerms != NULL)
4894 {
4895 unsigned int size = mCVTerms->getSize();
4896 while (size--) delete static_cast<CVTerm*>( mCVTerms->remove(0) );
4897 delete mCVTerms;
4898 }
4899 mCVTerms = new List();
4900 /* might have model history on sbase objects */
4901 if (getLevel() > 2 && getTypeCode()!= SBML_MODEL)
4902 {
4903 delete mHistory;
4904 if (RDFAnnotationParser::hasHistoryRDFAnnotation(mAnnotation))
4905 {
4906 mHistory = RDFAnnotationParser::parseRDFAnnotation(mAnnotation,
4907 getMetaId().c_str(), &(stream));
4908 if (mHistory != NULL && mHistory->hasRequiredAttributes() == false)
4909 {
4910 logError(RDFNotCompleteModelHistory, getLevel(), getVersion(),
4911 "An invalid ModelHistory element has been stored.");
4912 }
4913 setModelHistory(mHistory);
4914 }
4915 else
4916 {
4917 mHistory = NULL;
4918 }
4919 }
4920 if (RDFAnnotationParser::hasCVTermRDFAnnotation(mAnnotation))
4921 {
4922 RDFAnnotationParser::parseRDFAnnotation(mAnnotation, mCVTerms,
4923 getMetaId().c_str(), &(stream));
4924
4925 bool hasNestedTerms = false;
4926 // look at cvterms to see if we have a nested term
4927 for (unsigned int cv = 0; cv < mCVTerms->getSize(); cv++)
4928 {
4929 CVTerm * term = (CVTerm *)(mCVTerms->get(cv));
4930 if (term->getNumNestedCVTerms() > 0)
4931 {
4932 hasNestedTerms = true;
4933 /* this essentially tells the code that rewrites the annotation to
4934 * reconstruct the node and should leave out the nested bit
4935 * if it not allowed
4936 */
4937 term->setHasBeenModifiedFlag();
4938 }
4939 }
4940
4941 if (hasNestedTerms == true)
4942 {
4943 unsigned int version = getVersion();
4944 if (level < 2 ||
4945 (level == 2 && version < 5) ||
4946 (level == 3) )
4947 {
4948 logError(NestedAnnotationNotAllowed, level, version,
4949 "The nested annotation has been stored but will not be written out.");
4950 }
4951 }
4952
4953 }
4954
4955 for (size_t i=0; i < mPlugins.size(); i++)
4956 {
4957 mPlugins[i]->parseAnnotation(this, mAnnotation);
4958 }
4959 return true;
4960 }
4961
4962 return false;
4963 }
4964 /** @endcond */
4965
4966
4967 /** @cond doxygenLibsbmlInternal */
4968 /*
4969 * @return @c true if read a <notes> element from the stream
4970 */
4971 bool
readNotes(XMLInputStream & stream)4972 SBase::readNotes (XMLInputStream& stream)
4973 {
4974 const string& name = stream.peek().getName();
4975
4976 if (name == "notes")
4977 {
4978 // If this is a level 1 document then notes are not allowed on
4979 // the sbml container
4980 if (getLevel() == 1 && getTypeCode() == SBML_DOCUMENT)
4981 {
4982 logError(AnnotationNotesNotAllowedLevel1);
4983 }
4984
4985 // If a notes element already exists, then it is an error.
4986 // If an annotation element already exists, then the ordering is wrong.
4987 // In either case, replace existing content with the new notes read.
4988
4989 if (mNotes != NULL)
4990 {
4991 if (getLevel() < 3)
4992 {
4993 logError(NotSchemaConformant, getLevel(), getVersion(),
4994 "Only one <notes> element is permitted inside a "
4995 "particular containing element.");
4996 }
4997 else
4998 {
4999 logError(OnlyOneNotesElementAllowed, getLevel(), getVersion());
5000 }
5001 }
5002 else if (mAnnotation != NULL)
5003 {
5004 logError(NotSchemaConformant, getLevel(), getVersion(),
5005 "Incorrect ordering of <annotation> and <notes> elements -- "
5006 "<notes> must come before <annotation> due to the way that "
5007 "the XML Schema for SBML is defined.");
5008 }
5009
5010 delete mNotes;
5011 mNotes = new XMLNode(stream);
5012
5013 //
5014 // checks if the given default namespace (if any) is a valid
5015 // SBML namespace
5016 //
5017 const XMLNamespaces &xmlns = mNotes->getNamespaces();
5018 checkDefaultNamespace(&xmlns,"notes");
5019
5020 if (getSBMLDocument() != NULL)
5021 {
5022 if (getSBMLDocument()->getNumErrors() == 0)
5023 {
5024 checkXHTML(mNotes);
5025 }
5026 }
5027 return true;
5028 }
5029
5030 return false;
5031 }
5032
5033 bool
getHasBeenDeleted() const5034 SBase::getHasBeenDeleted() const
5035 {
5036 return mHasBeenDeleted;
5037 }
5038 /** @endcond */
5039
5040
5041 /** @cond doxygenLibsbmlInternal */
5042 /*
5043 * @return the ordinal position of the element with respect to its siblings
5044 * or -1 (default) to indicate the position is not significant.
5045 */
5046 int
getElementPosition() const5047 SBase::getElementPosition () const
5048 {
5049 return -1;
5050 }
5051 /** @endcond */
5052
5053
5054 /** @cond doxygenLibsbmlInternal */
5055 SBMLErrorLog*
getErrorLog()5056 SBase::getErrorLog ()
5057 {
5058 return (mSBML != NULL) ? mSBML->getErrorLog() : NULL;
5059 }
5060 /** @endcond */
5061
5062
5063 /** @cond doxygenLibsbmlInternal */
5064 /*
5065 * Helper to log a common type of error.
5066 */
5067 void
logUnknownAttribute(const string & attribute,const unsigned int level,const unsigned int version,const string & element,const string prefix)5068 SBase::logUnknownAttribute( const string& attribute,
5069 const unsigned int level,
5070 const unsigned int version,
5071 const string& element,
5072 const string prefix)
5073 {
5074 ostringstream msg;
5075
5076 if (getPackageName() != "core")
5077 {
5078 if (prefix.empty() == false)
5079 {
5080 msg << "Attribute '" << attribute << "' is not part of the "
5081 << "definition of an SBML Level " << level
5082 << " Version " << version << " Package "
5083 << getPackageName() << " Version " << getPackageVersion() << " <"
5084 << element << "> element.";
5085 if (mSBML != NULL)
5086 {
5087 getErrorLog()->logError(UnknownPackageAttribute,
5088 level, version, msg.str(), getLine(), getColumn());
5089 }
5090 }
5091 else
5092 {
5093 msg << "Attribute '" << attribute << "' is not part of the "
5094 << "definition of an SBML Level " << level
5095 << " Version " << version << " Package "
5096 << getPackageName() << " Version " << getPackageVersion() << " <"
5097 << element << "> element.";
5098 if (mSBML != NULL)
5099 {
5100 getErrorLog()->logError(UnknownCoreAttribute,
5101 level, version, msg.str(), getLine(), getColumn());
5102 }
5103 }
5104 return;
5105 }
5106 else
5107 {
5108 msg << "Attribute '" << attribute << "' is not part of the "
5109 << "definition of an SBML Level " << level
5110 << " Version " << version << " <" << element << "> element.";
5111 }
5112 /* Akiya made this note - so it needs checking BUT if it can crash due to no
5113 * SBMLDocument object then it can crash whatever level - so I put the catch outside
5114 */
5115 if (mSBML)
5116 {
5117 //
5118 // (TODO) Needs to be fixed so that error can be added when
5119 // no SBMLDocument attached.
5120 //
5121 if (level < 3)
5122 {
5123
5124 getErrorLog()->logError(NotSchemaConformant,
5125 level, version, msg.str(), getLine(), getColumn());
5126 }
5127 else
5128 {
5129 if (element == "<listOfFunctionDefinitions>"
5130 || element == "listOfFunctionDefinitions")
5131 {
5132 getErrorLog()->logError(AllowedAttributesOnListOfFuncs, level,
5133 version, msg.str(), getLine(), getColumn());
5134 }
5135 else if (element == "<sbml>" || element == "sbml")
5136 {
5137 getErrorLog()->logError(AllowedAttributesOnSBML, level,
5138 version, msg.str(), getLine(), getColumn());
5139 }
5140 else if (element == "<listOfUnitDefinitions>"
5141 || element == "listOfUnitDefinitions")
5142 {
5143 getErrorLog()->logError(AllowedAttributesOnListOfUnitDefs, level,
5144 version, msg.str(), getLine(), getColumn());
5145 }
5146 else if (element == "<listOfCompartments>"
5147 || element == "listOfCompartments")
5148 {
5149 getErrorLog()->logError(AllowedAttributesOnListOfComps, level,
5150 version, msg.str(), getLine(), getColumn());
5151 }
5152 else if (element == "<listOfSpecies>" || element == "listOfSpecies")
5153 {
5154 getErrorLog()->logError(AllowedAttributesOnListOfSpecies, level,
5155 version, msg.str(), getLine(), getColumn());
5156 }
5157 else if (element == "<listOfParameters>"
5158 || element == "listOfParameters")
5159 {
5160 getErrorLog()->logError(AllowedAttributesOnListOfParams, level,
5161 version, msg.str(), getLine(), getColumn());
5162 }
5163 else if (element == "<listOfInitialAssignments>"
5164 || element == "listOfInitialAssignments")
5165 {
5166 getErrorLog()->logError(AllowedAttributesOnListOfInitAssign, level,
5167 version, msg.str(), getLine(), getColumn());
5168 }
5169 else if (element == "<listOfRules>" || element == "listOfRules")
5170 {
5171 getErrorLog()->logError(AllowedAttributesOnListOfRules, level,
5172 version, msg.str(), getLine(), getColumn());
5173 }
5174 else if (element == "<listOfConstraints>"
5175 || element == "listOfConstraints")
5176 {
5177 getErrorLog()->logError(AllowedAttributesOnListOfConstraints, level,
5178 version, msg.str(), getLine(), getColumn());
5179 }
5180 else if (element == "<listOfReactions>" || element == "listOfReactions")
5181 {
5182 getErrorLog()->logError(AllowedAttributesOnListOfReactions, level,
5183 version, msg.str(), getLine(), getColumn());
5184 }
5185 else if (element == "<listOfEvents>" || element == "listOfEvents")
5186 {
5187 getErrorLog()->logError(AllowedAttributesOnListOfEvents, level,
5188 version, msg.str(), getLine(), getColumn());
5189 }
5190 else if (element == "<model>" || element == "model")
5191 {
5192 getErrorLog()->logError(AllowedAttributesOnModel, level,
5193 version, msg.str(), getLine(), getColumn());
5194 }
5195 else if (element == "<listOfUnits>" || element == "listOfUnits")
5196 {
5197 getErrorLog()->logError(AllowedAttributesOnListOfUnits, level,
5198 version, msg.str(), getLine(), getColumn());
5199 }
5200 else if (element == "<unitDefinition>" || element == "unitDefinition")
5201 {
5202 getErrorLog()->logError(AllowedAttributesOnUnitDefinition, level,
5203 version, msg.str(), getLine(), getColumn());
5204 }
5205 else if (element == "<unit>" || element == "unit")
5206 {
5207 getErrorLog()->logError(AllowedAttributesOnUnit, level,
5208 version, msg.str(), getLine(), getColumn());
5209 }
5210 else if (element == "<functionDefinition>"
5211 || element == "functionDefinition")
5212 {
5213 getErrorLog()->logError(AllowedAttributesOnFunc, level,
5214 version, msg.str(), getLine(), getColumn());
5215 }
5216 else if (element == "<compartment>" || element == "compartment")
5217 {
5218 getErrorLog()->logError(AllowedAttributesOnCompartment, level,
5219 version, msg.str(), getLine(), getColumn());
5220 }
5221 else if (element == "<species>" || element == "species")
5222 {
5223 getErrorLog()->logError(AllowedAttributesOnSpecies, level,
5224 version, msg.str(), getLine(), getColumn());
5225 }
5226 else if (element == "<parameter>" || element == "parameter")
5227 {
5228 getErrorLog()->logError(AllowedAttributesOnParameter, level,
5229 version, msg.str(), getLine(), getColumn());
5230 }
5231 else if (element == "<initialAssignment>"
5232 || element == "initialAssignment")
5233 {
5234 getErrorLog()->logError(AllowedAttributesOnInitialAssign, level,
5235 version, msg.str(), getLine(), getColumn());
5236 }
5237 else if (element == "<assignmentRule>"
5238 || element == "assignmentRule")
5239 {
5240 getErrorLog()->logError(AllowedAttributesOnAssignRule, level,
5241 version, msg.str(), getLine(), getColumn());
5242 }
5243 else if (element == "<rateRule>" || element == "rateRule")
5244 {
5245 getErrorLog()->logError(AllowedAttributesOnRateRule, level,
5246 version, msg.str(), getLine(), getColumn());
5247 }
5248 else if (element == "<algebraicRule>" || element == "algebraicRule")
5249 {
5250 getErrorLog()->logError(AllowedAttributesOnAlgRule, level,
5251 version, msg.str(), getLine(), getColumn());
5252 }
5253 else if (element == "<constraint>" || element == "constraint")
5254 {
5255 getErrorLog()->logError(AllowedAttributesOnConstraint, level,
5256 version, msg.str(), getLine(), getColumn());
5257 }
5258 else if (element == "<reaction>" || element == "reaction")
5259 {
5260 getErrorLog()->logError(AllowedAttributesOnReaction, level,
5261 version, msg.str(), getLine(), getColumn());
5262 }
5263 else if (element == "<listOfReactants>"
5264 || element == "listOfReactants")
5265 {
5266 getErrorLog()->logError(AllowedAttributesOnListOfSpeciesRef, level,
5267 version, msg.str(), getLine(), getColumn());
5268 }
5269 else if (element == "<listOfProducts>"
5270 || element == "listOfProducts")
5271 {
5272 getErrorLog()->logError(AllowedAttributesOnListOfSpeciesRef, level,
5273 version, msg.str(), getLine(), getColumn());
5274 }
5275 else if (element == "<listOfModifiers>"
5276 || element == "listOfModifiers")
5277 {
5278 getErrorLog()->logError(AllowedAttributesOnListOfMods, level,
5279 version, msg.str(), getLine(), getColumn());
5280 }
5281 else if (element == "<speciesReference>"
5282 || element == "speciesReference")
5283 {
5284 getErrorLog()->logError(AllowedAttributesOnSpeciesReference, level,
5285 version, msg.str(), getLine(), getColumn());
5286 }
5287 else if (element == "<modifierSpeciesReference>"
5288 || element == "modifierSpeciesReference")
5289 {
5290 getErrorLog()->logError(AllowedAttributesOnModifier, level,
5291 version, msg.str(), getLine(), getColumn());
5292 }
5293 else if (element == "<listOfLocalParameters>"
5294 || element == "listOfLocalParameters")
5295 {
5296 getErrorLog()->logError(AllowedAttributesOnListOfLocalParam, level,
5297 version, msg.str(), getLine(), getColumn());
5298 }
5299 else if (element == "<kineticLaw>" || element == "kineticLaw")
5300 {
5301 getErrorLog()->logError(AllowedAttributesOnKineticLaw, level,
5302 version, msg.str(), getLine(), getColumn());
5303 }
5304 else if (element == "<localParameter>" || element == "localParameter")
5305 {
5306 getErrorLog()->logError(AllowedAttributesOnLocalParameter, level,
5307 version, msg.str(), getLine(), getColumn());
5308 }
5309 else if (element == "<event>" || element == "event")
5310 {
5311 getErrorLog()->logError(AllowedAttributesOnEvent, level,
5312 version, msg.str(), getLine(), getColumn());
5313 }
5314 else if (element == "<listOfEventAssignments>"
5315 || element == "listOfEventAssignments")
5316 {
5317 getErrorLog()->logError(AllowedAttributesOnListOfEventAssign, level,
5318 version, msg.str(), getLine(), getColumn());
5319 }
5320 else if (element == "<trigger>" || element == "trigger")
5321 {
5322 getErrorLog()->logError(AllowedAttributesOnTrigger, level,
5323 version, msg.str(), getLine(), getColumn());
5324 }
5325 else if (element == "<delay>" || element == "delay")
5326 {
5327 getErrorLog()->logError(AllowedAttributesOnDelay, level,
5328 version, msg.str(), getLine(), getColumn());
5329 }
5330 else if (element == "<eventAssignment>" || element == "eventAssignment")
5331 {
5332 getErrorLog()->logError(AllowedAttributesOnEventAssignment, level,
5333 version, msg.str(), getLine(), getColumn());
5334 }
5335 else if (element == "<priority>" || element == "priority")
5336 {
5337 getErrorLog()->logError(AllowedAttributesOnPriority, level,
5338 version, msg.str(), getLine(), getColumn());
5339 }
5340 }
5341 }
5342 }
5343 /** @endcond */
5344
5345
5346 /** @cond doxygenLibsbmlInternal */
5347 /*
5348 * Helper to log a common type of error.
5349 */
5350 void
logUnknownElement(const string & element,const unsigned int level,const unsigned int version)5351 SBase::logUnknownElement( const string& element,
5352 const unsigned int level,
5353 const unsigned int version )
5354 {
5355 bool logged = false;
5356 ostringstream msg;
5357
5358 if (level > 2 && getTypeCode() == SBML_LIST_OF)
5359 {
5360 int tc = static_cast<ListOf*>(this)->getItemTypeCode();
5361 msg << "Element '" << element << "' is not part of the definition of <"
5362 << this->getElementName() << ">.";
5363 switch (tc)
5364 {
5365 case SBML_UNIT:
5366 getErrorLog()->logError(OnlyUnitsInListOfUnits,
5367 level, version, msg.str(),
5368 getLine(), getColumn());
5369 logged = true;
5370 break;
5371 case SBML_FUNCTION_DEFINITION:
5372
5373 getErrorLog()->logError(OnlyFuncDefsInListOfFuncDefs,
5374 level, version, msg.str(),
5375 getLine(), getColumn());
5376 logged = true;
5377 break;
5378 case SBML_UNIT_DEFINITION:
5379
5380 getErrorLog()->logError(OnlyUnitDefsInListOfUnitDefs,
5381 level, version, msg.str(),
5382 getLine(), getColumn());
5383 logged = true;
5384 break;
5385 case SBML_COMPARTMENT:
5386
5387 getErrorLog()->logError(OnlyCompartmentsInListOfCompartments,
5388 level, version, msg.str(),
5389 getLine(), getColumn());
5390 logged = true;
5391 break;
5392 case SBML_SPECIES:
5393
5394 getErrorLog()->logError(OnlySpeciesInListOfSpecies,
5395 level, version, msg.str(),
5396 getLine(), getColumn());
5397 logged = true;
5398 break;
5399 case SBML_PARAMETER:
5400
5401 getErrorLog()->logError(OnlyParametersInListOfParameters,
5402 level, version, msg.str(),
5403 getLine(), getColumn());
5404 logged = true;
5405 break;
5406 case SBML_INITIAL_ASSIGNMENT:
5407
5408 getErrorLog()->logError(OnlyInitAssignsInListOfInitAssigns,
5409 level, version, msg.str(),
5410 getLine(), getColumn());
5411 logged = true;
5412 break;
5413 case SBML_CONSTRAINT:
5414
5415 getErrorLog()->logError(OnlyConstraintsInListOfConstraints,
5416 level, version, msg.str(),
5417 getLine(), getColumn());
5418 logged = true;
5419 break;
5420 case SBML_RULE:
5421
5422 getErrorLog()->logError(OnlyRulesInListOfRules,
5423 level, version, msg.str(),
5424 getLine(), getColumn());
5425 logged = true;
5426 break;
5427 case SBML_REACTION:
5428
5429 getErrorLog()->logError(OnlyReactionsInListOfReactions,
5430 level, version, msg.str(),
5431 getLine(), getColumn());
5432 logged = true;
5433 break;
5434 case SBML_EVENT:
5435
5436 getErrorLog()->logError(OnlyEventsInListOfEvents,
5437 level, version, msg.str(),
5438 getLine(), getColumn());
5439 logged = true;
5440 break;
5441 case SBML_LOCAL_PARAMETER:
5442
5443 getErrorLog()->logError(OnlyLocalParamsInListOfLocalParams,
5444 level, version, msg.str(),
5445 getLine(), getColumn());
5446 logged = true;
5447 break;
5448 case SBML_EVENT_ASSIGNMENT:
5449
5450 getErrorLog()->logError(OnlyEventAssignInListOfEventAssign,
5451 level, version, msg.str(),
5452 getLine(), getColumn());
5453 logged = true;
5454 break;
5455 }
5456 }
5457
5458 if (logged == false && getPackageName() != "core")
5459 {
5460 // put in a package message
5461 // for now - want to log error from package but needs further work
5462 ostringstream msg1;
5463 msg1 << "Element '" << element << "' is not part of the definition of '"
5464 << this->getElementName() << "' in "
5465 << "SBML Level " << level << " Version " << version
5466 << " Package " << getPackageName()
5467 << " Version " << getPackageVersion() << ".";
5468
5469 if (mSBML != NULL)
5470 {
5471 getErrorLog()->logError(UnrecognizedElement,
5472 level, version, msg1.str(), getLine(), getColumn());
5473 logged = true;
5474 }
5475 }
5476
5477 if (logged == false)
5478 {
5479 ostringstream msg1;
5480 msg1 << "Element '" << element << "' is not part of the definition of "
5481 << "SBML Level " << level << " Version " << version << ".";
5482
5483 if (mSBML != NULL)
5484 {
5485 getErrorLog()->logError(UnrecognizedElement,
5486 level, version, msg1.str(), getLine(), getColumn());
5487 }
5488 }
5489
5490 }
5491 /** @endcond */
5492
5493
5494 /** @cond doxygenLibsbmlInternal */
5495 /*
5496 * Helper to log a common type of error.
5497 */
5498 void
logEmptyString(const string & attribute,const unsigned int level,const unsigned int version,const string & element)5499 SBase::logEmptyString( const string& attribute,
5500 const unsigned int level,
5501 const unsigned int version,
5502 const string& element )
5503
5504 {
5505 ostringstream msg;
5506
5507 msg << "Attribute '" << attribute << "' on an "
5508 << element << " must not be an empty string.";
5509
5510 //
5511 // (TODO) Needs to be fixed so that error can be added when
5512 // no SBMLDocument attached.
5513 //
5514 if (mSBML != NULL)
5515 getErrorLog()->logError(NotSchemaConformant,
5516 level, version, msg.str(), getLine(), getColumn());
5517 }
5518 /** @endcond */
5519
5520
5521 /** @cond doxygenLibsbmlInternal */
5522 /*
5523 * Convenience method for easily logging problems from within method
5524 * implementations.
5525 *
5526 * This is essentially a short form of getErrorLog()->logError(...)
5527 */
5528 void
logError(unsigned int id,const unsigned int,const unsigned int,const std::string details)5529 SBase::logError ( unsigned int id
5530 , const unsigned int
5531 , const unsigned int
5532 , const std::string details )
5533 {
5534 //
5535 // (TODO) Needs to be fixed so that error can be added when
5536 // no SBMLDocument attached.
5537 //
5538 if ( SBase::getErrorLog() != NULL && mSBML != NULL)
5539 getErrorLog()->logError(id, getLevel(), getVersion(), details, getLine(), getColumn());
5540 }
5541 /** @endcond */
5542
5543
5544 /** @cond doxygenLibsbmlInternal */
5545 /**
5546 * Subclasses should override this method to get the list of
5547 * expected attributes.
5548 * This function is invoked from corresponding readAttributes()
5549 * function.
5550 */
5551 void
addExpectedAttributes(ExpectedAttributes & attributes)5552 SBase::addExpectedAttributes(ExpectedAttributes& attributes)
5553 {
5554 //
5555 // metaid: ID { use="optional" } (L2v1 ->)
5556 //
5557 if (getLevel() > 1 )
5558 attributes.add("metaid");
5559
5560 //
5561 // sboTerm: SBOTerm { use="optional" } (L2v3 ->)
5562 //
5563 if (getLevel() > 2 || (getLevel() == 2 && getVersion() > 2) )
5564 attributes.add("sboTerm");
5565
5566 // l3v2 added id/name to sbase
5567 if (getLevel() == 3 && getVersion() > 1)
5568 {
5569 attributes.add("id");
5570 attributes.add("name");
5571 }
5572 }
5573
5574
5575 /*
5576 * Subclasses should override this method to read values from the given
5577 * XMLAttributes set into their specific fields. Be sure to call your
5578 * parent's implementation of this method as well.
5579 */
5580 void
readAttributes(const XMLAttributes & attributes,const ExpectedAttributes & expectedAttributes)5581 SBase::readAttributes (const XMLAttributes& attributes,
5582 const ExpectedAttributes& expectedAttributes)
5583 {
5584 const_cast<XMLAttributes&>(attributes).setErrorLog(getErrorLog());
5585
5586 const unsigned int level = getLevel ();
5587 const unsigned int version = getVersion();
5588
5589 //
5590 // check that all attributes are expected
5591 //
5592 for (int i = 0; i < attributes.getLength(); i++)
5593 {
5594 std::string name = attributes.getName(i);
5595 std::string uri = attributes.getURI(i);
5596 std::string prefix = attributes.getPrefix(i);
5597
5598 //
5599 // To allow prefixed attribute whose namespace doesn't belong to
5600 // core or extension package.
5601 //
5602 // (e.g. xsi:type attribute in Curve element in layout extension)
5603 //
5604 if (!prefix.empty())
5605 {
5606 if ( expectedAttributes.hasAttribute(prefix + ":" + name) ) continue;
5607 }
5608
5609
5610 //
5611 // Checks if there are attributes of unknown package extensions
5612 //
5613 // if we happen to be on the sbml element (document) then
5614 // getPrefix() and mURI have not been set and just return defaults
5615 // thus a prefix does not appear to come from the right place !!!
5616 if (!prefix.empty() && getElementName() == "sbml")
5617 {
5618 if (!expectedAttributes.hasAttribute(name))
5619 {
5620 if (name == "required")
5621 {
5622 //we have an l2 doc with a package declared
5623 for (unsigned int i = 0; i < this->getNumPlugins(); ++i)
5624 {
5625 if (getPlugin(i)->getURI() == uri)
5626 {
5627 enablePackageInternal(uri, prefix, false);
5628 }
5629 }
5630 logError(NotSchemaConformant, getLevel(), getVersion(), "The L3 package '" + prefix +
5631 "' cannot be used in this document.");
5632 }
5633 else
5634 {
5635 logUnknownAttribute(name, level, version, getElementName());
5636 }
5637 }
5638 }
5639 else if (!prefix.empty() && (prefix != getPrefix()) && (uri != mURI) )
5640 {
5641 storeUnknownExtAttribute(getElementName(), attributes, (unsigned int)i);
5642 }
5643 else if (!prefix.empty() && level == 3 && getPackageCoreVersion() > 1 && (name == "id" || name == "name"))
5644 {
5645 logUnknownAttribute(name, level, version, getElementName(), prefix);
5646 }
5647 else if (!expectedAttributes.hasAttribute(name))
5648 {
5649 logUnknownAttribute(name, level, version, getElementName(), prefix);
5650 }
5651 }
5652
5653 if (level > 1)
5654 {
5655 bool assigned = attributes.readInto("metaid", mMetaId, getErrorLog(), false, getLine(), getColumn());
5656
5657 if (assigned && mMetaId.empty())
5658 {
5659 logEmptyString("metaid", level, version,
5660 SBMLTypeCode_toString(getTypeCode(), getPackageName().c_str()));
5661 }
5662
5663 if (isSetMetaId())
5664 {
5665 if (!SyntaxChecker::isValidXMLID(mMetaId))
5666 {
5667 logError(InvalidMetaidSyntax, getLevel(), getVersion(), "The metaid '" + mMetaId + "' does not conform to the syntax.");
5668 }
5669 }
5670 }
5671
5672 //
5673 // sboTerm: SBOTerm { use="optional" } (L2v3 ->)
5674 //
5675 // (NOTE)
5676 //
5677 // SBO::readTerm() must be invoked for L2V2 object in each
5678 // readAttributes function in SBase derived class if the sboTerm
5679 // attribute is required in L2V2.
5680 //
5681 if (level > 2 || ( (level == 2) && (version > 2) ) )
5682 {
5683 mSBOTerm = SBO::readTerm(attributes, this->getErrorLog(), level, version,
5684 getLine(), getColumn());
5685 }
5686
5687 // for l3v2 a document should only have sbo terms from modelling framework
5688 // this is impossible to catch in the validation framework which does not work
5689 // on a document level - so we will need to catch it here
5690 if (isSetSBOTerm() && getTypeCode() == SBML_DOCUMENT)
5691 {
5692 if (!SBO::isModellingFramework(mSBOTerm))
5693 {
5694 std::string message = SBO::intToString(mSBOTerm);
5695 message += " does not derive from the modelling framework branch.";
5696 this->getErrorLog()->logError(InvalidSBMLElementSBOTerm, level, version,
5697 message, getLine(), getColumn());
5698 }
5699 }
5700
5701 // for l3v2 and above
5702 // read id and name
5703 if (level == 3 && version > 1)
5704 {
5705 XMLTriple tripleId("id", "", "");
5706
5707 bool assigned = attributes.readInto(tripleId, mId, getErrorLog(), false,
5708 getLine(), getColumn());
5709
5710 if (assigned && mId.empty())
5711 {
5712 logEmptyString("id", level, version,
5713 SBMLTypeCode_toString(getTypeCode(), getPackageName().c_str()));
5714 }
5715
5716 if (isSetId())
5717 {
5718 if (!SyntaxChecker::isValidInternalSId(mId)) logError(InvalidIdSyntax);
5719 }
5720
5721 XMLTriple tripleName("name", "", "");
5722 attributes.readInto(tripleName, mName, getErrorLog(), false,
5723 getLine(), getColumn());
5724
5725 }
5726 //
5727 // (EXTENSION)
5728 //
5729 readExtensionAttributes(attributes, &expectedAttributes);
5730 }
5731
5732
5733 void
readExtensionAttributes(const XMLAttributes & attributes,const ExpectedAttributes * expectedAttributes)5734 SBase::readExtensionAttributes (const XMLAttributes& attributes, const ExpectedAttributes* expectedAttributes)
5735 {
5736 const_cast<XMLAttributes&>(attributes).setErrorLog(getErrorLog());
5737
5738 /* ---------------------------------------------------------
5739 *
5740 * (EXTENSION)
5741 *
5742 * ----------------------------------------------------------
5743 */
5744 const ExpectedAttributes* base = expectedAttributes != NULL ?
5745 expectedAttributes : new ExpectedAttributes();
5746
5747
5748 for (size_t i=0; i < mPlugins.size(); i++)
5749 {
5750 #if 0
5751 std::cout << "[DEBUG] SBase::readExtensionAttributes "
5752 << mPlugins[i]->getURI() << " "
5753 << getElementName() << std::endl;
5754 #endif
5755
5756 ExpectedAttributes ea(*base);
5757
5758 mPlugins[i]->addExpectedAttributes(ea);
5759 mPlugins[i]->readAttributes(attributes,ea);
5760 }
5761
5762 if (expectedAttributes == NULL )
5763 delete base;
5764
5765 /////////////////////////////////////////////////////////////////////////
5766
5767 }
5768
5769
5770 /**
5771 * Stores the given attribute to the list of ignored attributes if
5772 * the given attribute belongs to some unknown package.
5773 * Unknown attribute error will be logged if the "required" attribute
5774 * of the package in SBMLDocument element is "true".
5775 */
5776 void
storeUnknownExtAttribute(const std::string & element,const XMLAttributes & xattr,unsigned int index)5777 SBase::storeUnknownExtAttribute(const std::string& element,
5778 const XMLAttributes& xattr, unsigned int index)
5779 {
5780 if (!mSBML) return;
5781
5782 if (element == "sbml" && xattr.getName((int)index) == "required")
5783 return;
5784
5785 std::string uri = xattr.getURI((int)index);
5786
5787 //
5788 // Checks if the extension package is enabled.
5789 //
5790 if (!mSBML->isPackageURIEnabled(uri))
5791 {
5792 //
5793 // Checks if the extension package with the uri is unsupporeted
5794 // (ignored)
5795 //
5796 if (mSBML->isIgnoredPackage(uri))
5797 {
5798 std::string name = xattr.getName((int)index);
5799 std::string prefix = xattr.getPrefix((int)index);
5800 std::string value = xattr.getValue((int)index);
5801
5802 mAttributesOfUnknownPkg.add(name,value,uri,prefix);
5803
5804 /* this is now caught earlier and so can be ignored here
5805 if (mSBML->getPackageRequired(uri))
5806 {
5807 logUnknownAttribute(prefix + ":" + name, getLevel(), getVersion(), element);
5808 }
5809 */
5810 }
5811 else
5812 {
5813 std::string name = xattr.getName((int)index);
5814 std::string prefix = xattr.getPrefix((int)index);
5815 logUnknownAttribute(prefix + ":" + name, getLevel(), getVersion(), element);
5816 }
5817 }
5818 }
5819
5820
5821 bool
storeUnknownExtElement(XMLInputStream & stream)5822 SBase::storeUnknownExtElement(XMLInputStream &stream)
5823 {
5824 string uri = stream.peek().getURI();
5825
5826 if (SBMLNamespaces::isSBMLNamespace(uri))
5827 {
5828 return false;
5829 }
5830 else if (mSBML != NULL && mSBML->isIgnoredPackage(uri))
5831 {
5832 //
5833 // Checks if the extension package with the uri is unknown
5834 // (ignored)
5835 //
5836 /* do not need to do this now i have logged this as
5837 * a required package that cannot be interpreted
5838
5839 if (mSBML->getPackageRequired(uri))
5840 {
5841 const string& name = stream.peek().getName();
5842 string prefix = stream.peek().getPrefix();
5843 if (!prefix.empty()) prefix += ":";
5844 logUnknownElement(prefix + name, getLevel(), getVersion());
5845 }
5846 */
5847
5848 XMLNode xmlnode(stream);
5849 mElementsOfUnknownPkg.addChild(xmlnode);
5850
5851 return true;
5852 }
5853
5854 return false;
5855 }
5856 /** @endcond */
5857
5858
5859 /** @cond doxygenLibsbmlInternal */
5860 /*
5861 * Returns the prefix of this element.
5862 */
5863 std::string
getPrefix() const5864 SBase::getPrefix() const
5865 {
5866 std::string prefix = "";
5867
5868 XMLNamespaces *xmlns = getNamespaces();
5869 string uri = getURI();
5870 if(xmlns && mSBML && !mSBML->isEnabledDefaultNS(uri))
5871 {
5872 prefix = xmlns->getPrefix(uri);
5873 #if 0
5874 std::cout << "[DEBUG] SBase::getPrefix() " << prefix << " URI " << mURI
5875 << " element " << getElementName() << std::endl;
5876 #endif
5877 }
5878 #if 0
5879 else
5880 {
5881 if (!xmlns)
5882 {
5883 std::cout << "[DEBUG] SBase::getPrefix() [NO XMLNS] " << prefix << " URI " << mURI
5884 << " element " << getElementName() << std::endl;
5885 }
5886 if (!mSBML)
5887 {
5888 std::cout << "[DEBUG] SBase::getPrefix() [NO mSBML] " << prefix << " URI " << mURI
5889 << " element " << getElementName() << std::endl;
5890 }
5891
5892 }
5893 #endif
5894
5895 return prefix;
5896 }
5897
5898
5899 /*
5900 * Returns the prefix of this element.
5901 */
5902 std::string
getSBMLPrefix() const5903 SBase::getSBMLPrefix() const
5904 {
5905 std::string prefix = "";
5906
5907 XMLNamespaces *xmlns = getNamespaces();
5908 if (xmlns == NULL)
5909 return getPrefix();
5910
5911 for (int i = 0; i < xmlns->getNumNamespaces(); i++)
5912 {
5913 string uri = xmlns->getURI(i);
5914 if (SBMLNamespaces::isSBMLNamespace(uri))
5915 return xmlns->getPrefix(i);
5916 }
5917
5918 return getPrefix();
5919 }
5920
5921 /*
5922 * Returns the root element of this element.
5923 *
5924 * @note The root element may not be an SBMLDocument element. For example,
5925 * this element is the root element if this element doesn't have a parent
5926 * SBML object (i.e. mParentSBMLObject is NULL)
5927 */
5928 SBase*
getRootElement()5929 SBase::getRootElement()
5930 {
5931 if (mSBML)
5932 {
5933 return mSBML;
5934 }
5935 else if (mParentSBMLObject)
5936 {
5937 return mParentSBMLObject->getRootElement();
5938 }
5939 else
5940 {
5941 return this;
5942 }
5943 }
5944
5945
5946 /*
5947 * Subclasses should override this method to write their XML attributes
5948 * to the XMLOutputStream. Be sure to call your parent's implementation
5949 * of this method as well.
5950 */
5951 void
writeAttributes(XMLOutputStream & stream) const5952 SBase::writeAttributes (XMLOutputStream& stream) const
5953 {
5954 // if (getTypeCode() == SBML_DOCUMENT)
5955 // {
5956 // if (this->getNamespaces()) stream << *(this->getNamespaces());
5957 // }
5958 unsigned int level = getLevel();
5959 unsigned int version = getVersion();
5960 unsigned int pkgCoreVersion = getPackageCoreVersion();
5961 string sbmlPrefix = getSBMLPrefix();
5962 if ( level > 1 && !mMetaId.empty() )
5963 {
5964 stream.writeAttribute("metaid", sbmlPrefix, mMetaId);
5965 }
5966
5967 //
5968 // sboTerm: SBOTerm { use="optional" } (L2v3 ->)
5969 //
5970 // (NOTE)
5971 //
5972 // SBO::writeTerm() must be invoked for L2V2 object in each
5973 // readAttributes function in SBase derived class if the sboTerm
5974 // attribute is required in L2V2.
5975 //
5976 if (level > 2 || ( (level == 2) && (version > 2) ) )
5977 {
5978 SBO::writeTerm(stream, mSBOTerm, sbmlPrefix);
5979 }
5980
5981 // only write for l3v2 and above
5982 // but do not write for an l3v1 package
5983 if (level == 3 && version > 1)
5984 {
5985 if (getPackageName().empty() || getPackageName() == "core")
5986 {
5987 stream.writeAttribute("id", mId);
5988 stream.writeAttribute("name", mName);
5989 }
5990 else if (getPackageCoreVersion() > 1)
5991 {
5992 stream.writeAttribute("id", mId);
5993 stream.writeAttribute("name", mName);
5994 }
5995 }
5996 }
5997
5998
5999 /*
6000 *
6001 * Subclasses should override this method to write their xmlns attriubutes
6002 * (if any) to the XMLOutputStream. Be sure to call your parent's implementation
6003 * of this method as well.
6004 *
6005 */
6006 void
writeXMLNS(XMLOutputStream &) const6007 SBase::writeXMLNS (XMLOutputStream&) const
6008 {
6009 // do nothing.
6010 }
6011
6012
6013
6014 void
writeExtensionAttributes(XMLOutputStream & stream) const6015 SBase::writeExtensionAttributes (XMLOutputStream& stream) const
6016 {
6017 /* ---------------------------------------------------------
6018 *
6019 * (EXTENSION)
6020 *
6021 * ----------------------------------------------------------
6022 */
6023
6024 // debug
6025 #if 0
6026 cout << "[DEBUG] SBase::writeExtensionAttributes() " << getTypeCode() << endl;
6027 #endif
6028
6029 for (size_t i=0; i < mPlugins.size(); i++)
6030 {
6031 #if 0
6032 cout << "[DEBUG] SBase::writeExtensionAttributes() " << i << endl;
6033 #endif
6034 mPlugins[i]->writeAttributes(stream);
6035 }
6036
6037 //
6038 // writes attributes of unknown packages
6039 //
6040 for (int i=0; i < mAttributesOfUnknownPkg.getLength(); i++)
6041 {
6042 std::string name = mAttributesOfUnknownPkg.getName(i);
6043 std::string prefix = mAttributesOfUnknownPkg.getPrefix(i);
6044 std::string value = mAttributesOfUnknownPkg.getValue(i);
6045 stream.writeAttribute(name, prefix, value);
6046 }
6047
6048 /////////////////////////////////////////////////////////////////////////
6049 }
6050 /** @endcond */
6051
6052
6053 /** @cond doxygenLibsbmlInternal */
6054
6055
6056 bool
hasOptionalAttributes() const6057 SBase::hasOptionalAttributes() const
6058 {
6059 bool hasAttributes = false;
6060
6061 if (isSetMetaId() == true) hasAttributes = true;
6062 if (isSetSBOTerm() == true) hasAttributes = true;
6063
6064 if (getLevel() == 3 && getVersion() > 1)
6065 {
6066 if (isSetId() == true) hasAttributes = true;
6067 if (isSetName() == true) hasAttributes = true;
6068 }
6069
6070 return hasAttributes;
6071 }
6072
6073
6074 /** @endcond */
6075
6076
6077 /** @cond doxygenLibsbmlInternal */
6078
6079
6080 bool
hasOptionalElements() const6081 SBase::hasOptionalElements() const
6082 {
6083 bool hasElements = false;
6084
6085 if (isSetNotes() == true) hasElements = true;
6086 if (isSetAnnotation() == true) hasElements = true;
6087
6088 return hasElements;
6089 }
6090
6091
6092 /** @endcond */
6093
6094 /** @cond doxygenLibsbmlInternal */
6095 /*
6096 * Synchronizes the annotation of this SBML object.
6097 */
6098 void
syncAnnotation()6099 SBase::syncAnnotation ()
6100 {
6101 // look to see whether an existing history has been altered
6102 if (mHistoryChanged == false)
6103 {
6104 if (getModelHistory() != NULL)
6105 {
6106 if (getModelHistory()->hasBeenModified() == true)
6107 {
6108 mHistoryChanged = true;
6109 }
6110 }
6111 }
6112 // or an existing CVTerm
6113 if (mCVTermsChanged == false)
6114 {
6115 for (unsigned int i = 0; i < getNumCVTerms(); i++)
6116 {
6117 if (getCVTerm(i)->hasBeenModified() == true)
6118 {
6119 mCVTermsChanged = true;
6120 break;
6121 }
6122 }
6123 }
6124
6125 if (mHistoryChanged == true || mCVTermsChanged == true)
6126 {
6127 reconstructRDFAnnotation();
6128 mHistoryChanged = false;
6129 mCVTermsChanged = false;
6130 if (getModelHistory() != NULL)
6131 {
6132 getModelHistory()->resetModifiedFlags();
6133 }
6134 for (unsigned int i = 0; i < getNumCVTerms(); i++)
6135 {
6136 getCVTerm(i)->resetModifiedFlags();
6137 }
6138 }
6139
6140 if (mAnnotation == NULL)
6141 {
6142 XMLToken ann_token = XMLToken(XMLTriple("annotation", "", ""),
6143 XMLAttributes());
6144 mAnnotation = new XMLNode(ann_token);
6145 }
6146
6147 // sync annotations of plugins
6148 for (size_t i=0; i < mPlugins.size(); i++)
6149 {
6150 mPlugins[i]->syncAnnotation(this, mAnnotation);
6151 }
6152
6153 // if annotation still empty delete the annotation
6154 if (mAnnotation != NULL && mAnnotation->getNumChildren() == 0)
6155 {
6156 delete mAnnotation;
6157 mAnnotation = NULL;
6158 }
6159
6160 }
6161 /** @endcond */
6162
6163
6164 /** @cond doxygenLibsbmlInternal */
6165 void
reconstructRDFAnnotation()6166 SBase::reconstructRDFAnnotation()
6167 {
6168 bool hasRDF = false;
6169 bool hasAdditionalRDF = false;
6170
6171 // determine status of existing annotation before doing anything
6172 if (mAnnotation != NULL)
6173 {
6174 hasRDF = RDFAnnotationParser::hasRDFAnnotation(mAnnotation);
6175 hasAdditionalRDF =
6176 RDFAnnotationParser::hasAdditionalRDFAnnotation(mAnnotation);
6177 if (hasAdditionalRDF == false)
6178 {
6179 // look for bizaare case where a user has added a history annotation
6180 // to an object that does not legally include history in MIRIAM compliant
6181 // RDF - this needs to get written out as additional RDF
6182 if (getLevel() < 3 && getTypeCode() != SBML_MODEL
6183 && RDFAnnotationParser::hasHistoryRDFAnnotation(mAnnotation) == true)
6184 {
6185 hasAdditionalRDF = true;
6186 }
6187 }
6188
6189 if (getLevel() == 2 && getVersion() < 5)
6190 {
6191 // now look for case where the original has nested annotations
6192 // in a level/version where it is strictly speaking invalid
6193 // preserve this annotation as an additional RDF annotation
6194 bool hasNestedAnnotations = false;
6195
6196 for (unsigned int i = 0; i < getNumCVTerms(); i++)
6197 {
6198 if (getCVTerm(i)->getNumNestedCVTerms() > 0)
6199 {
6200 hasNestedAnnotations = true;
6201 break;
6202 }
6203 }
6204 if (hasRDF == true && hasNestedAnnotations == true)
6205 {
6206 hasAdditionalRDF = true;
6207 // add a copy of the annotation to the RDF as a second RDF element
6208 XMLNode RDF = mAnnotation->getChild("RDF");
6209 XMLNode * desr = RDF.getChild("Description").clone();
6210 mAnnotation->getChild("RDF").addChild(*desr);
6211 delete desr;
6212 }
6213 }
6214 }
6215
6216 // look at whether the user has changed the RDF elements
6217 if(mAnnotation != NULL && hasRDF)
6218 {
6219 XMLNode* new_annotation = NULL;
6220 if (mHistoryChanged == true)
6221 {
6222 if (mCVTermsChanged == true)
6223 {
6224 new_annotation =
6225 RDFAnnotationParser::deleteRDFAnnotation(mAnnotation);
6226 }
6227 else
6228 {
6229 new_annotation =
6230 RDFAnnotationParser::deleteRDFHistoryAnnotation(mAnnotation);
6231 }
6232 }
6233 else
6234 {
6235 if (mCVTermsChanged == true)
6236 {
6237 new_annotation =
6238 RDFAnnotationParser::deleteRDFCVTermAnnotation(mAnnotation);
6239 }
6240 }
6241
6242 if(new_annotation != NULL)
6243 {
6244 *mAnnotation = *new_annotation;
6245 delete new_annotation;
6246 }
6247 }
6248
6249 /* get the history and cvterm annotations from the element */
6250 XMLNode * history = RDFAnnotationParser::parseOnlyModelHistory(this);
6251
6252 XMLNode * cvTerms = RDFAnnotationParser::parseCVTerms(this);
6253
6254 if (history != NULL && mHistoryChanged == true && mCVTermsChanged == false)
6255 {
6256 if (cvTerms == NULL)
6257 {
6258 if (mAnnotation == NULL)
6259 {
6260 // if there was no annotation before a user added history/cvterms
6261 mAnnotation = history->clone(); //noannot.xml
6262 }
6263 else
6264 {
6265 if (mAnnotation->isEnd())
6266 {
6267 // if the original annotation had only history when it was removed
6268 // it would have left <annotation/> as the annotation
6269 // need this not to be an end element
6270 mAnnotation->unsetEnd(); // histOnly.xml
6271 }
6272
6273 if (hasAdditionalRDF)
6274 {
6275 // here the annotation after removing history has an RDF top level
6276 // element - the history needs to go into the RDF as the first
6277 // description element
6278 // <rdf><some-non-miriam-rdf> needs to become
6279 // <rdf><History/><some-non-...
6280 // test file histAddRDF
6281 mAnnotation->getChild("RDF").insertChild(0,
6282 history->getChild("RDF").getChild("Description"));
6283 }
6284 else
6285 {
6286 // here the annotation after removing history has either an
6287 // empty annotation element OR one with other top level annotations
6288 // <annotation/> OR <annotation><someAnnotations/>
6289 // just add the whole history RDF annotation
6290 // test files histOnly + histOther
6291 mAnnotation->addChild(history->getChild("RDF"));
6292 }
6293 }
6294 }
6295 else
6296 {
6297 // here the annotation after removing history has an RDF top level
6298 // element with CVTerms and (possibly)other rdf
6299 // - the history needs to go into the first RDF decsription element
6300 // that already has CVTerms
6301 // <rdf><Description-withCVTerms/><some-non-miriam-rdf> needs to become
6302 // <rdf><Description with ModelHistory and CVTerms/><some-non-...
6303 // NOTE: The History Description element has three children
6304 // creator/created and modified
6305 // test file: histCVAddRDF/histCVOnly/histCVOther
6306 unsigned int noChild
6307 = history->getChild("RDF").getChild("Description").getNumChildren();
6308 if (mAnnotation != NULL)
6309 for (unsigned int i = noChild; i > 0; i--)
6310 {
6311 ((mAnnotation->getChild("RDF")).getChild("Description")).insertChild(
6312 0, history->getChild("RDF").getChild("Description").getChild(i-1));
6313 }
6314 }
6315 }
6316
6317 if (cvTerms != NULL && mCVTermsChanged == true && mHistoryChanged == false)
6318 {
6319 if (history == NULL)
6320 {
6321 if (mAnnotation == NULL)
6322 {
6323 // if there was no annotation before a user added history/cvterms
6324 mAnnotation = cvTerms->clone(); //noannot.xml
6325 }
6326 else
6327 {
6328 if (mAnnotation->isEnd())
6329 {
6330 // if the original annotation had only CVTerms when it was removed
6331 // it would have left <annotation/> as the annotation
6332 // need this not to be an end element
6333 mAnnotation->unsetEnd(); // CVOnly.xml
6334 }
6335
6336 if (hasAdditionalRDF)
6337 {
6338 // here the annotation after removing cvterms has an RDF top level
6339 // element - the cvterms needs to go into the RDF as the first
6340 // description element
6341 // <rdf><some-non-miriam-rdf> needs to become
6342 // <rdf><cvterms/><some-non-...
6343 // test file histAddRDF
6344 mAnnotation->getChild("RDF").insertChild(0,
6345 cvTerms->getChild("RDF").getChild("Description"));
6346 }
6347 else
6348 {
6349 // here the annotation after removing CVTerms has either an
6350 // empty annotation element OR one with other top level annotations
6351 // <annotation/> OR <annotation><someAnnotations/>
6352 // just add the whole CVTerm RDF annotation
6353 // test files CVOnly + CVOther
6354 mAnnotation->addChild(cvTerms->getChild("RDF"));
6355 }
6356 }
6357 }
6358 else
6359 {
6360 // here the annotation after removing cvterms has an RDF top level
6361 // element with history and (possibly)other rdf
6362 // - the cvterms needs to go into the first RDF decsription element
6363 // that already has history but after it
6364 // <rdf><Description-withHistory/><some-non-miriam-rdf> needs to become
6365 // <rdf><Description with History and CVTerms/><some-non-...
6366 // NOTE: The History Description element has three children
6367 // creator/created and modified
6368 // test file: histCVAddRDF/histCVOnly/histCVOther
6369 unsigned int noChild
6370 = cvTerms->getChild("RDF").getChild("Description").getNumChildren();
6371 if (mAnnotation != NULL)
6372 for (unsigned int i = 0; i < noChild; i++)
6373 {
6374 ((mAnnotation->getChild("RDF")).getChild("Description")).addChild(
6375 cvTerms->getChild("RDF").getChild("Description").getChild(i));
6376 }
6377 }
6378 }
6379
6380 if (mCVTermsChanged == true && mHistoryChanged == true)
6381 {
6382 if (mAnnotation == NULL)
6383 {
6384 // if there was no annotation before a user changed history/cvterms
6385 // need to catch case where user in fact unset history/cvterms
6386 // test file noannot.xml
6387 if (history != NULL)
6388 {
6389 mAnnotation = history->clone();
6390 if (cvTerms != NULL)
6391 {
6392 unsigned int noChild
6393 = cvTerms->getChild("RDF").getChild("Description").getNumChildren();
6394 for (unsigned int i = 0; i < noChild; i++)
6395 {
6396 ((mAnnotation->getChild("RDF")).getChild("Description")).addChild(
6397 cvTerms->getChild("RDF").getChild("Description").getChild(i));
6398 }
6399 }
6400 }
6401 else
6402 {
6403 if (cvTerms != NULL)
6404 {
6405 mAnnotation = cvTerms->clone();
6406 }
6407 }
6408
6409 }
6410 else
6411 {
6412 if (mAnnotation->isEnd())
6413 {
6414 // if the original annotation had only the miriam-rdf when it was removed
6415 // it would have left <annotation/> as the annotation
6416 // need this not to be an end element
6417 mAnnotation->unsetEnd();
6418 }
6419
6420 if (hasAdditionalRDF)
6421 {
6422 // here the annotation after removing miriam-rdf has an RDF top level
6423 // element - the history and cvterms need to go into the RDF as the first
6424 // description element
6425 // <rdf><some-non-miriam-rdf> needs to become
6426 // <rdf><HistoryAndCVTerms/><some-non-...
6427 if (history != NULL)
6428 {
6429 mAnnotation->getChild("RDF").insertChild(0,
6430 history->getChild("RDF").getChild("Description"));
6431 if (cvTerms != NULL)
6432 {
6433 unsigned int noChild
6434 = cvTerms->getChild("RDF").getChild("Description").getNumChildren();
6435 for (unsigned int i = 0; i < noChild; i++)
6436 {
6437 ((mAnnotation->getChild("RDF")).getChild("Description")).addChild(
6438 cvTerms->getChild("RDF").getChild("Description").getChild(i));
6439 }
6440 }
6441 }
6442 else
6443 {
6444 if (cvTerms != NULL)
6445 {
6446 mAnnotation->getChild("RDF").insertChild(0,
6447 cvTerms->getChild("RDF").getChild("Description"));
6448 }
6449 }
6450 }
6451 else
6452 {
6453 // here the annotation after removing miriam-rdf has either an
6454 // empty annotation element OR one with other top level annotations
6455 // <annotation/> OR <annotation><someAnnotations/>
6456 // just add the whole history and cvterms
6457 if (history != NULL)
6458 {
6459 mAnnotation->addChild(history->getChild("RDF"));
6460 if (cvTerms != NULL)
6461 {
6462 unsigned int noChild
6463 = cvTerms->getChild("RDF").getChild("Description").getNumChildren();
6464 for (unsigned int i = 0; i < noChild; i++)
6465 {
6466 ((mAnnotation->getChild("RDF")).getChild("Description")).addChild(
6467 cvTerms->getChild("RDF").getChild("Description").getChild(i));
6468 }
6469 }
6470 }
6471 else
6472 {
6473 if (cvTerms != NULL)
6474 {
6475 mAnnotation->addChild(cvTerms->getChild("RDF"));
6476 }
6477 }
6478
6479 }
6480 }
6481 }
6482
6483
6484 if (history != NULL) delete history;
6485 if (cvTerms != NULL) delete cvTerms;
6486 }
6487 /** @endcond */
6488
6489
6490 /** @cond doxygenLibsbmlInternal */
6491 /*
6492 * Checks that SBML element has been read in the proper order. If object
6493 * is not in the expected position, an error is logged.
6494 */
6495 void
checkOrderAndLogError(SBase * object,int expected)6496 SBase::checkOrderAndLogError (SBase* object, int expected)
6497 {
6498 int actual = object->getElementPosition();
6499
6500 if (actual != -1 && actual < expected)
6501 {
6502 SBMLErrorCode_t error = IncorrectOrderInModel;
6503
6504 if (object->getPackageName() == "core")
6505 {
6506 if (object->getTypeCode() == SBML_LIST_OF)
6507 {
6508 int tc = static_cast<ListOf*>(object)->getItemTypeCode();
6509 //typecode (int) tc = static_cast<ListOf*>(object)->getItemTypeCode();
6510
6511 if (tc == SBML_SPECIES_REFERENCE || tc == SBML_MODIFIER_SPECIES_REFERENCE)
6512 {
6513 error = IncorrectOrderInReaction;
6514 }
6515 }
6516 else if (object->getTypeCode() == SBML_TRIGGER)
6517 {
6518 error = IncorrectOrderInEvent;
6519 }
6520
6521 logError(error, getLevel(), getVersion());
6522 }
6523 }
6524 }
6525 /** @endcond */
6526
6527
6528 /** @cond doxygenLibsbmlInternal */
6529 /*
6530 * Checks that an SBML ListOf element has been populated.
6531 * If a listOf element has been declared with no elements,
6532 * an error is logged.
6533 */
6534 void
checkListOfPopulated(SBase * object)6535 SBase::checkListOfPopulated(SBase* object)
6536 {
6537 //
6538 // (TODO) Currently, the following check code works only for
6539 // elements in SBML core.
6540 // This function may need to be extented for other elements
6541 // defined in each package extension.
6542 //
6543 if (object->getPackageName() != "core" &&
6544 object->getTypeCode() == SBML_LIST_OF)
6545 {
6546 // for now log the empty list
6547 if (static_cast <ListOf*> (object)->size() == 0)
6548 {
6549 /* hack to stop an empty listOfFunctionTerms that has
6550 * a defaultTerm object being logged as empty
6551 */
6552 if (object->getPackageName() == "qual" &&
6553 object->getElementName() == "listOfFunctionTerms")
6554 {
6555 // do nothing
6556 // will need to check for defaultTerm but will
6557 // have to pass that to the qual extension
6558 }
6559 else if (object->getPackageName() == "multi" &&
6560 object->getElementName() == "listOfSpeciesFeatures")
6561 {
6562 // do nothing
6563 // will need to check for defaultTerm but will
6564 // have to pass that to the multi extension
6565 }
6566 else if (object->getPackageName() == "render" &&
6567 (object->getElementName() == "listOfRenderInformation" ||
6568 object->getElementName() == "listOfGlobalRenderInformation"))
6569 {
6570 // do nothing
6571 // will need to check for defaultTerm but will
6572 // have to pass that to the qual extension
6573 }
6574 else
6575 {
6576 ostringstream errMsg;
6577 errMsg << object->getElementName() << " cannot be empty.";
6578
6579 logError(NotSchemaConformant, getLevel(), getVersion(), errMsg.str());
6580 }
6581 }
6582 return;
6583 }
6584
6585 if (object->getTypeCode() == SBML_LIST_OF)
6586 {
6587 // Check that the list has at least one element.
6588 if (static_cast <ListOf*> (object)->size() == 0)
6589 {
6590 //typecode (int) tc = static_cast<ListOf*>(object)->getItemTypeCode();
6591 int tc = static_cast<ListOf*>(object)->getItemTypeCode();
6592 SBMLErrorCode_t error = EmptyListElement;
6593
6594 // By default, the error will be the EmptyListElement error, unless
6595 // we have a special case for which SBML has a separate error code.
6596 switch (tc)
6597 {
6598 case SBML_UNIT:
6599 if (object->getLevel() < 3)
6600 error = EmptyListOfUnits;
6601 else
6602 error = EmptyUnitListElement;
6603 break;
6604
6605 case SBML_SPECIES_REFERENCE:
6606 case SBML_MODIFIER_SPECIES_REFERENCE:
6607 error = EmptyListInReaction;
6608 break;
6609
6610 case SBML_PARAMETER:
6611 // If listOfParameters is inside a KineticLaw, we have a separate code.
6612 if (this->getTypeCode() == SBML_KINETIC_LAW)
6613 {
6614 error = EmptyListInKineticLaw;
6615 }
6616 break;
6617 case SBML_LOCAL_PARAMETER:
6618 error = EmptyListInKineticLaw;
6619 break;
6620 case SBML_EVENT_ASSIGNMENT:
6621 if (object->getLevel() > 2)
6622 error = MissingEventAssignment;
6623 break;
6624
6625 default:;
6626 }
6627
6628 logError(error, getLevel(), getVersion());
6629 }
6630 /*
6631 * If there is a non-empty Parameter list in a kinetic law and we are in L3
6632 * report UnrecognisedElement.
6633 */
6634 else if (this->getTypeCode() == SBML_KINETIC_LAW &&
6635 getLevel() == 3)
6636 {
6637 int tc = static_cast<ListOf*>(object)->getItemTypeCode();
6638 SBMLErrorCode_t error = UnrecognizedElement;
6639 if (tc == SBML_PARAMETER) {
6640 error = UnrecognizedElement;
6641 std::string msg = "SBML Level 3 replaced the <parameter> ";
6642 msg += "within a <kineticLaw> with <localParameter>.";
6643 logError(error, getLevel(), getVersion(), msg);
6644 }
6645 }
6646 }
6647
6648 else if (object->getTypeCode() == SBML_KINETIC_LAW)
6649 {
6650 /*
6651 * if nothing has been set in the kineticLaw we assume its is empty
6652 */
6653 if (static_cast <KineticLaw *> (object)->isSetMath() == 0 &&
6654 static_cast <KineticLaw *> (object)->isSetFormula() == 0 &&
6655 static_cast <KineticLaw *> (object)->isSetTimeUnits() == 0 &&
6656 static_cast <KineticLaw *> (object)->isSetSubstanceUnits() == 0 &&
6657 static_cast <KineticLaw *> (object)->isSetSBOTerm() == 0 &&
6658 static_cast <KineticLaw *> (object)->getNumParameters() == 0)
6659 {
6660 logError(EmptyListInReaction, getLevel(), getVersion());
6661 }
6662 }
6663 }
6664 /** @endcond */
6665
6666
6667 /** @cond doxygenLibsbmlInternal */
6668 /* returns the derived units of the object
6669 * needs to be on SBase so that comp can use it for unit checking
6670 * but may also need to be implemented for other packages
6671 */
6672 UnitDefinition*
getDerivedUnitDefinition()6673 SBase::getDerivedUnitDefinition()
6674 {
6675 return NULL;
6676 }
6677 /** @endcond */
6678
6679
6680 /** @cond doxygenLibsbmlInternal */
6681 /* returns the derived units of the object
6682 * needs to be on SBase so that comp can use it for unit checking
6683 * but may also need to be implemented for other packages
6684 */
6685 bool
containsUndeclaredUnits()6686 SBase::containsUndeclaredUnits()
6687 {
6688 return false;
6689 }
6690 /** @endcond */
6691
6692
6693 //This assumes that the parent of the object is of the type ListOf. If this is not the case, it will need to be overridden.
removeFromParentAndDelete()6694 int SBase::removeFromParentAndDelete()
6695 {
6696 SBase* parent = getParentSBMLObject();
6697 if (parent==NULL) return LIBSBML_OPERATION_FAILED;
6698 ListOf* parentList = static_cast<ListOf*>(parent);
6699 if (parentList == NULL) return LIBSBML_OPERATION_FAILED;
6700 for (unsigned int i=0; i<parentList->size(); i++) {
6701 SBase* sibling = parentList->get(i);
6702 if (sibling == this) {
6703 parentList->remove(i);
6704 delete this;
6705 return LIBSBML_OPERATION_SUCCESS;
6706 }
6707 }
6708 return LIBSBML_OPERATION_FAILED;
6709 }
6710
6711 /** @cond doxygenLibsbmlInternal */
6712 const std::string
checkMathMLNamespace(const XMLToken elem)6713 SBase::checkMathMLNamespace(const XMLToken elem)
6714 {
6715 std::string prefix = "";
6716 unsigned int match = 0;
6717 int n;
6718 if (elem.getNamespaces().getLength() != 0)
6719 {
6720 for (n = 0; n < elem.getNamespaces().getLength(); n++)
6721 {
6722 if (!strcmp(elem.getNamespaces().getURI(n).c_str(),
6723 "http://www.w3.org/1998/Math/MathML"))
6724 {
6725 match = 1;
6726 break;
6727 }
6728 }
6729 }
6730 if (match == 0)
6731 {
6732 if( mSBML->getNamespaces() != NULL)
6733 /* check for implicit declaration */
6734 {
6735 for (n = 0; n < mSBML->getNamespaces()->getLength(); n++)
6736 {
6737 if (!strcmp(mSBML->getNamespaces()->getURI(n).c_str(),
6738 "http://www.w3.org/1998/Math/MathML"))
6739 {
6740 match = 1;
6741 prefix = mSBML->getNamespaces()->getPrefix(n);
6742 break;
6743 }
6744 }
6745 }
6746 }
6747 if (match == 0)
6748 {
6749 logError(InvalidMathElement, getLevel(), getVersion(), "The MathML namespace 'http://www.w3.org/1998/Math/MathML' was not found.");
6750 }
6751
6752 return prefix;
6753 }
6754 /** @endcond */
6755
6756
6757 /** @cond doxygenLibsbmlInternal */
6758 void
checkDefaultNamespace(const XMLNamespaces * xmlns,const std::string & elementName,const std::string prefix)6759 SBase::checkDefaultNamespace(const XMLNamespaces* xmlns,
6760 const std::string& elementName,
6761 const std::string prefix)
6762 {
6763 //
6764 // checks if the given default namespace (if any) is a valid
6765 // SBML namespace
6766 //
6767 if (xmlns == NULL || xmlns->getLength() == 0)
6768 return;
6769
6770 const std::string defaultURI = xmlns->getURI(prefix);
6771 if (defaultURI.empty() || mURI == defaultURI)
6772 return;
6773
6774 // if this element (SBase derived) has notes or annotation elements,
6775 // it is ok for them to be in the SBML namespace!
6776 if ( SBMLNamespaces::isSBMLNamespace(defaultURI)
6777 && !SBMLNamespaces::isSBMLNamespace(mURI)
6778 && (elementName == "notes" || elementName == "annotation"))
6779 return;
6780
6781 static ostringstream errMsg;
6782 errMsg.str("");
6783 errMsg << "xmlns=\"" << defaultURI << "\" in <" << elementName
6784 << "> element is an invalid namespace." << endl;
6785
6786 logError(NotSchemaConformant, getLevel(), getVersion(), errMsg.str());
6787
6788 }
6789
6790 void
read(XMLNode & node,XMLErrorSeverityOverride_t flag)6791 SBase::read(XMLNode& node, XMLErrorSeverityOverride_t flag /*= LIBSBML_OVERRIDE_DISABLED*/)
6792 {
6793 XMLErrorLog* log = getErrorLog();
6794
6795 // set override for error messages
6796 XMLErrorSeverityOverride_t old = LIBSBML_OVERRIDE_DISABLED;
6797 if (log != NULL )
6798 {
6799 old = log->getSeverityOverride();
6800 log->setSeverityOverride(flag);
6801 }
6802
6803 const string content = "<?xml version='1.0' encoding='UTF-8'?>"
6804 + XMLNode::convertXMLNodeToString(&node);
6805 XMLInputStream stream(content.c_str(), false);
6806
6807 // do the parsing using SBase::read
6808 read(stream);
6809
6810 // restore logging
6811 if (log != NULL )
6812 {
6813 log->setSeverityOverride(old);
6814 }
6815
6816 }
6817
6818 XMLNode*
toXMLNode()6819 SBase::toXMLNode()
6820 {
6821 char* rawsbml = toSBML();
6822 SBMLNamespaces *sbmlns = getSBMLNamespaces();
6823 XMLNamespaces xmlns(*sbmlns->getNamespaces());
6824 // in rare cases the above returns a package element with default namespace, however the
6825 // XMLNamespaces would then assign the actual default namespace, which is in most cases
6826 // the SBML namespace. In that case we adjust the default namespace here
6827 ISBMLExtensionNamespaces *extns = dynamic_cast<ISBMLExtensionNamespaces*>(sbmlns);
6828 if (extns != NULL)
6829 {
6830 xmlns.remove("");
6831 xmlns.add(xmlns.getURI(extns->getPackageName()), "");
6832 }
6833 XMLNode* ret = XMLNode::convertStringToXMLNode(rawsbml, &xmlns);
6834 safe_free(rawsbml);
6835 return ret;
6836 }
6837
6838
6839 /*
6840 * Checks the annotation does not declare an sbml namespace.
6841 * If the annotation declares an sbml namespace an error is logged.
6842 */
6843 void
checkAnnotation()6844 SBase::checkAnnotation()
6845 {
6846 unsigned int nNodes = 0;
6847 unsigned int match = 0;
6848 int n = 0;
6849 std::vector<std::string> uri_list;
6850 uri_list.clear();
6851
6852 if (mAnnotation == NULL) return;
6853
6854 //
6855 // checks if the given default namespace (if any) is a valid
6856 // SBML namespace
6857 //
6858 const XMLNamespaces &xmlns = mAnnotation->getNamespaces();
6859 checkDefaultNamespace(&xmlns,"annotation");
6860
6861 while (nNodes < mAnnotation->getNumChildren())
6862 {
6863 XMLNode topLevel = mAnnotation->getChild(nNodes);
6864
6865 // the top level must be an element (so it should be a start)
6866 if (topLevel.isStart() == false)
6867 {
6868 logError(AnnotationNotElement, getLevel(), getVersion());
6869 nNodes++;
6870 continue;
6871 }
6872 std::string uri = topLevel.getURI();
6873 std::string prefix = topLevel.getPrefix();
6874
6875 #ifdef USE_LIBXML
6876 // sometimes libxml does not catch an empty ns with a prefix
6877 if (uri.empty() && !prefix.empty())
6878 {
6879 logError(BadXMLPrefix);
6880 nNodes++;
6881 continue;
6882 }
6883 #endif
6884
6885 // cannot be other toplevel element with this uri
6886 if (!uri.empty())
6887 {
6888 if (find(uri_list.begin(), uri_list.end(), uri)
6889 != uri_list.end())
6890 {
6891 string msg = "An SBML <" + getElementName() + "> element ";
6892 switch(getTypeCode()) {
6893 case SBML_INITIAL_ASSIGNMENT:
6894 case SBML_EVENT_ASSIGNMENT:
6895 case SBML_ASSIGNMENT_RULE:
6896 case SBML_RATE_RULE:
6897 //LS DEBUG: could use other attribute values, or 'isSetActualId'.
6898 break;
6899 default:
6900 if (isSetId()) {
6901 msg += "with id '" + getId() + "' ";
6902 }
6903 break;
6904 }
6905 msg += "has an <annotation> child with multiple children with the same namespace.";
6906 logError(DuplicateAnnotationNamespaces, getLevel(), getVersion(), msg);
6907 }
6908 uri_list.push_back(uri);
6909 }
6910
6911 match = 0;
6912 n = 0;
6913
6914 bool implicitNSdecl = false;
6915 // must have a namespace
6916 if (topLevel.getNamespaces().getLength() == 0)
6917 {
6918 // not on actual element - is it explicit ??
6919 if( mSBML->getNamespaces() != NULL)
6920 /* check for implicit declaration */
6921 {
6922 for (n = 0; n < mSBML->getNamespaces()->getLength(); n++)
6923 {
6924 if (!strcmp(mSBML->getNamespaces()->getPrefix(n).c_str(),
6925 prefix.c_str()))
6926 {
6927 implicitNSdecl = true;
6928 break;
6929 }
6930 }
6931 }
6932
6933
6934 if (!implicitNSdecl)
6935 {
6936 logError(MissingAnnotationNamespace);
6937 }
6938 }
6939 // cannot declare sbml namespace
6940 while(!match && n < topLevel.getNamespaces().getLength())
6941 {
6942 match += !strcmp(topLevel.getNamespaces().getURI(n).c_str(),
6943 "http://www.sbml.org/sbml/level1");
6944 match += !strcmp(topLevel.getNamespaces().getURI(n).c_str(),
6945 "http://www.sbml.org/sbml/level2");
6946 match += !strcmp(topLevel.getNamespaces().getURI(n).c_str(),
6947 "http://www.sbml.org/sbml/level2/version2");
6948 match += !strcmp(topLevel.getNamespaces().getURI(n).c_str(),
6949 "http://www.sbml.org/sbml/level2/version3");
6950 match += !strcmp(topLevel.getNamespaces().getURI(n).c_str(),
6951 "http://www.sbml.org/sbml/level2/version4");
6952 match += !strcmp(topLevel.getNamespaces().getURI(n).c_str(),
6953 "http://www.sbml.org/sbml/level2/version5");
6954 match += !strcmp(topLevel.getNamespaces().getURI(n).c_str(),
6955 "http://www.sbml.org/sbml/level3/version1/core");
6956 match += !strcmp(topLevel.getNamespaces().getURI(n).c_str(),
6957 "http://www.sbml.org/sbml/level3/version2/core");
6958 n++;
6959 }
6960 string msg = "An SBML <" + getElementName() + "> element ";
6961 switch(getTypeCode()) {
6962 case SBML_INITIAL_ASSIGNMENT:
6963 case SBML_EVENT_ASSIGNMENT:
6964 case SBML_ASSIGNMENT_RULE:
6965 case SBML_RATE_RULE:
6966 //LS DEBUG: could use other attribute values, or 'isSetActualId'.
6967 break;
6968 default:
6969 if (isSetId()) {
6970 msg += "with id '" + getId() + "' ";
6971 }
6972 break;
6973 }
6974 if (match > 0)
6975 {
6976 msg += "uses a restricted namespace on an element in its child <annotation>.";
6977 logError(SBMLNamespaceInAnnotation, getLevel(), getVersion(), msg);
6978 break;
6979 }
6980
6981 if (implicitNSdecl && prefix.empty())
6982 {
6983 /* if this is L3 a missing namespace with empty prefix means
6984 * it is using the sbml ns - which is allowed in L3
6985 */
6986 if (getLevel() < 3)
6987 {
6988 logError(MissingAnnotationNamespace, getLevel(), getVersion(),
6989 msg + "lacks a namespace declaration on an element in its child <annotation>.");
6990 }
6991 msg += "uses a restricted namespace on an element in its child <annotation>.";
6992 logError(SBMLNamespaceInAnnotation, getLevel(), getVersion(), msg);
6993 }
6994 nNodes++;
6995 }
6996 }
6997 /** @endcond */
6998
6999
7000 /** @cond doxygenLibsbmlInternal */
7001 /*
7002 * Checks that the XHTML is valid.
7003 * If the xhtml does not conform to the specification of valid xhtml within
7004 * an sbml document, an error is logged.
7005 */
7006 void
checkXHTML(const XMLNode * xhtml)7007 SBase::checkXHTML(const XMLNode * xhtml)
7008 {
7009 if (xhtml == NULL) return;
7010
7011 const string& name = xhtml->getName();
7012 unsigned int i, errorNS, errorXML, errorDOC, errorELEM;
7013
7014 if (name == "notes")
7015 {
7016 errorNS = NotesNotInXHTMLNamespace;
7017 errorXML = NotesContainsXMLDecl;
7018 errorDOC = NotesContainsDOCTYPE;
7019 errorELEM = InvalidNotesContent;
7020 }
7021 else if (name == "message")
7022 {
7023 errorNS = ConstraintNotInXHTMLNamespace;
7024 errorXML = ConstraintContainsXMLDecl;
7025 errorDOC = ConstraintContainsDOCTYPE;
7026 errorELEM = InvalidConstraintContent;
7027 }
7028 else // We shouldn't ever get to this point.
7029 {
7030 logError(UnknownError);
7031 return;
7032 }
7033
7034 /*
7035 * errors relating to a misplaced XML or DOCTYPE declaration
7036 * will also cause a parser error.
7037 * since parsing will terminate at this error, then if it has occurred
7038 * it will be in the XML currently being checked and so a more
7039 * informative message can be added
7040 */
7041 for (i = 0; i < getErrorLog()->getNumErrors(); i++)
7042 {
7043 if (getErrorLog()->getError(i)->getErrorId() == BadXMLDeclLocation)
7044 {
7045 logError(errorXML);
7046 }
7047 if (getErrorLog()->getError(i)->getErrorId() == BadlyFormedXML)
7048 {
7049 logError(errorDOC);
7050 }
7051 }
7052
7053 XMLNamespaces* toplevelNS = (mSBML) ? mSBML->getNamespaces() : NULL;
7054
7055 /*
7056 * namespace declaration is variable
7057 * if a whole html tag has been used
7058 * or a whole body tag then namespace can be implicitly declared
7059 */
7060 unsigned int children = xhtml->getNumChildren();
7061
7062 if (children > 1)
7063 {
7064 for (i=0; i < children; i++)
7065 {
7066 if (SyntaxChecker::isAllowedElement(xhtml->getChild(i)))
7067 {
7068 if (!SyntaxChecker::hasDeclaredNS(xhtml->getChild(i),
7069 toplevelNS))
7070 {
7071 logError(errorNS);
7072 }
7073 }
7074 else
7075 {
7076 logError(errorELEM);
7077 }
7078 }
7079 }
7080 else
7081 {
7082 /* only one element which can be html or body with either implicit/explicit
7083 * namespace declaration
7084 * OR could be one of the listed elements.
7085 */
7086
7087 const string& top_name = xhtml->getChild(0).getName();
7088
7089 if (top_name != "html" && top_name != "body"
7090 && !SyntaxChecker::isAllowedElement(xhtml->getChild(0)))
7091 {
7092 logError(errorELEM);
7093 }
7094 else
7095 {
7096 if (!SyntaxChecker::hasDeclaredNS(xhtml->getChild(0), toplevelNS))
7097 {
7098 logError(errorNS);
7099 }
7100 if (top_name == "html"
7101 && !SyntaxChecker::isCorrectHTMLNode(xhtml->getChild(0)))
7102 {
7103 logError(errorELEM);
7104 }
7105 }
7106 }
7107 }
7108 /** @endcond */
7109 /** @cond doxygenLibsbmlInternal */
7110 /* default for components that have no required attributes */
7111 bool
hasRequiredAttributes() const7112 SBase::hasRequiredAttributes() const
7113 {
7114 return true;
7115 }
7116
7117 /* default for components that have no required elements */
7118 bool
hasRequiredElements() const7119 SBase::hasRequiredElements() const
7120 {
7121 return true;
7122 }
7123
7124 int
checkCompatibility(const SBase * object) const7125 SBase::checkCompatibility(const SBase * object) const
7126 {
7127 if (object == NULL)
7128 {
7129 return LIBSBML_OPERATION_FAILED;
7130 }
7131 else if (!(object->hasRequiredAttributes()) || !(object->hasRequiredElements()))
7132 {
7133 return LIBSBML_INVALID_OBJECT;
7134 }
7135 else if (getLevel() != object->getLevel())
7136 {
7137 return LIBSBML_LEVEL_MISMATCH;
7138 }
7139 else if (getVersion() != object->getVersion())
7140 {
7141 return LIBSBML_VERSION_MISMATCH;
7142 }
7143 else if (this->matchesRequiredSBMLNamespacesForAddition(object) == false)
7144 {
7145 return LIBSBML_NAMESPACES_MISMATCH;
7146 }
7147 else
7148 {
7149 return LIBSBML_OPERATION_SUCCESS;
7150 }
7151 }
7152
7153 void
removeDuplicateAnnotations()7154 SBase::removeDuplicateAnnotations()
7155 {
7156 bool resetNecessary = false;
7157 XMLNamespaces xmlns = XMLNamespaces();
7158 xmlns.add("http://www.sbml.org/libsbml/annotation", "");
7159 XMLTriple triple = XMLTriple("duplicateTopLevelElements",
7160 "http://www.sbml.org/libsbml/annotation", "");
7161 XMLAttributes att = XMLAttributes();
7162 XMLToken token = XMLToken(triple, att, xmlns);
7163 XMLNode * newNode = NULL;
7164 if (isSetAnnotation())
7165 {
7166 //make a copy to work with
7167 XMLNode * newAnnotation = mAnnotation->clone();
7168
7169 unsigned int numChildren = newAnnotation->getNumChildren();
7170 if (numChildren == 1)
7171 return;
7172
7173 bool duplicate = false;
7174 for (unsigned int i = 0; i < numChildren; i++)
7175 {
7176 duplicate = false;
7177 std::string name = newAnnotation->getChild(i).getName();
7178 for (unsigned int j = numChildren-1; j > i; j--)
7179 {
7180 if (name == newAnnotation->getChild(j).getName())
7181 {
7182 resetNecessary = true;
7183 duplicate = true;
7184 if (newNode == NULL)
7185 {
7186 // need to create the new node
7187 newNode = new XMLNode(token);
7188 }
7189 XMLNode* transfer = newAnnotation->removeChild(j);
7190 newNode->addChild(*transfer);
7191 delete transfer;
7192 }
7193 }
7194 if (duplicate)
7195 {
7196 XMLNode* transfer = newAnnotation->removeChild(i);
7197 newNode->addChild(*transfer);
7198 delete transfer;
7199 }
7200 numChildren = newAnnotation->getNumChildren();
7201 }
7202 if (resetNecessary)
7203 {
7204 newAnnotation->addChild(*(newNode));
7205 setAnnotation(newAnnotation);
7206 }
7207 delete newNode;
7208 delete newAnnotation;
7209 }
7210
7211
7212 }
7213 /** @endcond */
7214
7215 /** @cond doxygenLibsbmlInternal */
7216 /*
7217 * Stores the location (line and column) and any XML namespaces (for
7218 * roundtripping) declared on this SBML (XML) element.
7219 */
7220 void
setSBaseFields(const XMLToken & element)7221 SBase::setSBaseFields (const XMLToken& element)
7222 {
7223 mLine = element.getLine ();
7224 mColumn = element.getColumn();
7225
7226 if (element.getNamespaces().getLength() > 0)
7227 {
7228 XMLNamespaces tmpxmlns(element.getNamespaces());
7229 setNamespaces(&tmpxmlns);
7230 }
7231 else
7232 {
7233 setNamespaces(NULL);
7234 }
7235 }
7236 /** @endcond */
7237
7238 /** @cond doxygenLibsbmlInternal */
7239 /*
7240 *
7241 * (Extension)
7242 *
7243 * Sets the XML namespace to which this element belogns to.
7244 * For example, all elements that belong to SBML Level 3 Version 1 Core
7245 * must set the namespace to "http://www.sbml.org/sbml/level3/version1/core";
7246 * all elements that belong to Layout Extension Version 1 for SBML Level 3
7247 * Version 1 Core must set the namespace to
7248 * "http://www.sbml.org/sbml/level3/version1/layout/version1/"
7249 *
7250 */
7251 int
setElementNamespace(const std::string & uri)7252 SBase::setElementNamespace(const std::string &uri)
7253 {
7254 // cout << "[DEBUG] SBase::setElementNamespace() " << uri << endl;
7255 mURI = uri;
7256
7257 return LIBSBML_OPERATION_SUCCESS;
7258 }
7259 /** @endcond */
7260
7261 /** @cond doxygenLibsbmlInternal */
7262 void
updateSBMLNamespace(const std::string & package,unsigned int level,unsigned int version)7263 SBase::updateSBMLNamespace(const std::string& package, unsigned int level,
7264 unsigned int version)
7265 {
7266 if (package.empty() || package == "core")
7267 {
7268 std::string uri;
7269
7270 switch (level)
7271 {
7272 case 1:
7273 uri = SBML_XMLNS_L1;
7274 break;
7275 case 2:
7276 switch (version)
7277 {
7278 case 1:
7279 uri = SBML_XMLNS_L2V1;
7280 break;
7281 case 2:
7282 uri = SBML_XMLNS_L2V2;
7283 break;
7284 case 3:
7285 uri = SBML_XMLNS_L2V3;
7286 break;
7287 case 4:
7288 uri = SBML_XMLNS_L2V4;
7289 break;
7290 case 5:
7291 default:
7292 uri = SBML_XMLNS_L2V5;
7293 break;
7294 }
7295 break;
7296 case 3:
7297 default:
7298 switch (version)
7299 {
7300 case 1:
7301 uri = SBML_XMLNS_L3V1;
7302 break;
7303 case 2:
7304 default:
7305 uri = SBML_XMLNS_L3V2;
7306 break;
7307 }
7308 break;
7309 }
7310 // is there a prefix on the sbml namespace
7311 std::string currentSBMLCoreURI =
7312 SBMLNamespaces::getSBMLNamespaceURI(getLevel(),
7313 getVersion());
7314 std::string currentSBMLCorePrefix = "";
7315
7316 if (mSBMLNamespaces == NULL)
7317 {
7318 mSBMLNamespaces = new SBMLNamespaces(level, version);
7319 }
7320
7321
7322 if (mSBMLNamespaces->getNamespaces() != NULL &&
7323 mSBMLNamespaces->getNamespaces()->getLength() > 0)
7324 {
7325 currentSBMLCorePrefix = mSBMLNamespaces->getNamespaces()->
7326 getPrefix(currentSBMLCoreURI);
7327 mSBMLNamespaces->getNamespaces()->remove(currentSBMLCorePrefix);
7328 mSBMLNamespaces->getNamespaces()->add(uri, currentSBMLCorePrefix);
7329
7330 // it is possible that the ns exists unprefixed as well as prefixed
7331 // the code will return the first it encounters
7332 // so check if the original ns is still there
7333 if (mSBMLNamespaces->getNamespaces()->containsUri(currentSBMLCoreURI) == true)
7334 {
7335 currentSBMLCorePrefix = mSBMLNamespaces->getNamespaces()
7336 ->getPrefix(currentSBMLCoreURI);
7337 mSBMLNamespaces->getNamespaces()->remove(currentSBMLCorePrefix);
7338 mSBMLNamespaces->getNamespaces()->add(uri, currentSBMLCorePrefix);
7339 }
7340 }
7341 else
7342 {
7343 mSBMLNamespaces->addNamespace(uri, currentSBMLCorePrefix);
7344 }
7345
7346 mSBMLNamespaces->setLevel(level);
7347 mSBMLNamespaces->setVersion(version);
7348 if (this->getPackageName().empty() || this->getPackageName() == "core")
7349 setElementNamespace(uri);
7350 }
7351 else
7352 {
7353 std::string uri = this->getSBMLNamespaces()->getNamespaces()->getURI(package);
7354 const SBMLExtension* sbmlext = SBMLExtensionRegistry::getInstance().getExtensionInternal(uri);
7355 // so we have a plugin for this package already enabled
7356 // if there are two version 1 of this package
7357 // we want is to change the uri being used
7358 if (sbmlext && sbmlext->isEnabled())
7359 {
7360 std::string newURI;
7361 newURI.assign(uri);
7362 size_t pos = newURI.find("level3");
7363 if (version == 1)
7364 {
7365 newURI.replace(pos, 15, "level3/version1");
7366 }
7367 else if (version == 2)
7368 {
7369 newURI.replace(pos, 15, "level3/version2");
7370 }
7371
7372 bool found = false;
7373 unsigned int count = 0;
7374 while (!found && count < sbmlext->getNumOfSupportedPackageURI())
7375 {
7376 if (newURI == sbmlext->getSupportedPackageURI(count))
7377 {
7378 found = true;
7379 }
7380 count++;
7381 }
7382
7383 if (found)
7384 {
7385 mSBMLNamespaces->getNamespaces()->remove(uri);
7386 mSBMLNamespaces->getNamespaces()->add(newURI, package);
7387 if (this->getPackageName() == package)
7388 setElementNamespace(newURI);
7389 }
7390 }
7391
7392 }
7393
7394 for (size_t i = 0; i < mPlugins.size(); i++)
7395 {
7396 mPlugins[i]->updateSBMLNamespace(package, level, version);
7397 }
7398
7399 }
7400 /** @endcond */
7401
7402 /** @cond doxygenLibsbmlInternal */
7403 /*
7404 * Returns the XML namespace to which this element belongs to.
7405 */
7406 const std::string&
getElementNamespace() const7407 SBase::getElementNamespace() const
7408 {
7409 return mURI;
7410 }
7411 /** @endcond */
7412
7413 #endif /* __cplusplus */
7414
7415 /** @cond doxygenIgnored */
7416 LIBSBML_EXTERN
7417 int
SBase_addCVTerm(SBase_t * sb,CVTerm_t * term)7418 SBase_addCVTerm(SBase_t *sb, CVTerm_t *term)
7419 {
7420 return (sb != NULL) ? sb->addCVTerm(term) : LIBSBML_INVALID_OBJECT;
7421 }
7422
7423
7424 LIBSBML_EXTERN
7425 int
SBase_addCVTermNewBag(SBase_t * sb,CVTerm_t * term)7426 SBase_addCVTermNewBag(SBase_t *sb, CVTerm_t *term)
7427 {
7428 return (sb != NULL) ? sb->addCVTerm(term, true) : LIBSBML_INVALID_OBJECT;
7429 }
7430
7431
7432 LIBSBML_EXTERN
7433 List_t*
SBase_getCVTerms(SBase_t * sb)7434 SBase_getCVTerms(SBase_t *sb)
7435 {
7436 return (sb != NULL) ? sb->getCVTerms() : 0;
7437 }
7438
7439
7440 LIBSBML_EXTERN
7441 unsigned int
SBase_getNumCVTerms(SBase_t * sb)7442 SBase_getNumCVTerms(SBase_t *sb)
7443 {
7444 return (sb != NULL) ? sb->getNumCVTerms() : SBML_INT_MAX;
7445 }
7446
7447 LIBSBML_EXTERN
7448 CVTerm_t*
SBase_getCVTerm(SBase_t * sb,unsigned int n)7449 SBase_getCVTerm(SBase_t *sb, unsigned int n)
7450 {
7451 return (sb != NULL) ? static_cast <CVTerm_t *> (sb->getCVTerm(n)) : NULL;
7452 }
7453
7454 LIBSBML_EXTERN
7455 int
SBase_unsetCVTerms(SBase_t * sb)7456 SBase_unsetCVTerms(SBase_t *sb)
7457 {
7458 return (sb != NULL) ? sb->unsetCVTerms() : LIBSBML_INVALID_OBJECT;
7459 }
7460
7461
7462 LIBSBML_EXTERN
7463 ModelHistory_t *
SBase_getModelHistory(SBase_t * sb)7464 SBase_getModelHistory(SBase_t *sb)
7465 {
7466 return (sb != NULL) ? sb->getModelHistory() : NULL;
7467 }
7468
7469 LIBSBML_EXTERN
7470 int
SBase_isSetModelHistory(SBase_t * sb)7471 SBase_isSetModelHistory(SBase_t *sb)
7472 {
7473 return (sb != NULL) ? static_cast<int>( sb->isSetModelHistory() ) : 0;
7474 }
7475
7476
7477 LIBSBML_EXTERN
7478 int
SBase_setModelHistory(SBase_t * sb,ModelHistory_t * history)7479 SBase_setModelHistory(SBase_t *sb, ModelHistory_t *history)
7480 {
7481 return (sb != NULL) ? sb->setModelHistory(history) : LIBSBML_INVALID_OBJECT;
7482 }
7483
7484 LIBSBML_EXTERN
7485 int
SBase_unsetModelHistory(SBase_t * sb)7486 SBase_unsetModelHistory(SBase_t *sb)
7487 {
7488 return (sb != NULL) ? sb->unsetModelHistory() : LIBSBML_INVALID_OBJECT;
7489 }
7490
7491
7492 LIBSBML_EXTERN
7493 BiolQualifierType_t
SBase_getResourceBiologicalQualifier(SBase_t * sb,const char * resource)7494 SBase_getResourceBiologicalQualifier(SBase_t *sb, const char * resource)
7495 {
7496 if (sb != NULL)
7497 return (resource != NULL) ?
7498 sb->getResourceBiologicalQualifier(resource) : BQB_UNKNOWN;
7499 else
7500 return BQB_UNKNOWN;
7501 }
7502
7503
7504 LIBSBML_EXTERN
7505 ModelQualifierType_t
SBase_getResourceModelQualifier(SBase_t * sb,const char * resource)7506 SBase_getResourceModelQualifier(SBase_t *sb, const char * resource)
7507 {
7508 if (sb != NULL)
7509 return (resource != NULL) ?
7510 sb->getResourceModelQualifier(resource) : BQM_UNKNOWN;
7511 else
7512 return BQM_UNKNOWN;
7513 }
7514
7515
7516 LIBSBML_EXTERN
7517 const char *
SBase_getMetaId(SBase_t * sb)7518 SBase_getMetaId (SBase_t *sb)
7519 {
7520 return (sb != NULL && sb->isSetMetaId()) ? sb->getMetaId().c_str() : NULL;
7521 }
7522
7523
7524 LIBSBML_EXTERN
7525 const char *
SBase_getIdAttribute(SBase_t * sb)7526 SBase_getIdAttribute (SBase_t *sb)
7527 {
7528 return (sb != NULL && sb->isSetIdAttribute()) ? sb->getIdAttribute().c_str() : NULL;
7529 }
7530
7531
7532 LIBSBML_EXTERN
7533 const char *
SBase_getName(SBase_t * sb)7534 SBase_getName (SBase_t *sb)
7535 {
7536 return (sb != NULL && sb->isSetName()) ? sb->getName().c_str() : NULL;
7537 }
7538
7539
7540 LIBSBML_EXTERN
7541 const SBMLDocument_t *
SBase_getSBMLDocument(SBase_t * sb)7542 SBase_getSBMLDocument (SBase_t *sb)
7543 {
7544 return (sb != NULL) ? sb->getSBMLDocument() : NULL;
7545 }
7546
7547
7548 LIBSBML_EXTERN
7549 const SBase_t *
SBase_getParentSBMLObject(SBase_t * sb)7550 SBase_getParentSBMLObject (SBase_t *sb)
7551 {
7552 return (sb != NULL) ? sb->getParentSBMLObject() : NULL;
7553 }
7554
7555
7556 LIBSBML_EXTERN
7557 const SBase_t *
SBase_getAncestorOfType(SBase_t * sb,int type,const char * pkgName)7558 SBase_getAncestorOfType (SBase_t *sb, int type, const char* pkgName)
7559 {
7560 return (sb != NULL) ? sb->getAncestorOfType(type, pkgName) : NULL;
7561 }
7562
7563
7564 LIBSBML_EXTERN
7565 int
SBase_getSBOTerm(const SBase_t * sb)7566 SBase_getSBOTerm (const SBase_t *sb)
7567 {
7568 return (sb != NULL) ? sb->getSBOTerm() : SBML_INT_MAX;
7569 }
7570
7571
7572 LIBSBML_EXTERN
7573 char*
SBase_getSBOTermID(const SBase_t * sb)7574 SBase_getSBOTermID (const SBase_t *sb)
7575 {
7576 return (sb != NULL && sb->isSetSBOTerm())?
7577 safe_strdup(sb->getSBOTermID().c_str()) : NULL;
7578 }
7579
7580
7581 LIBSBML_EXTERN
7582 char*
SBase_getSBOTermAsURL(const SBase_t * sb)7583 SBase_getSBOTermAsURL (const SBase_t *sb)
7584 {
7585 return (sb != NULL && sb->isSetSBOTerm())?
7586 safe_strdup(sb->getSBOTermAsURL().c_str()) : NULL;
7587 }
7588
7589
7590 LIBSBML_EXTERN
7591 unsigned int
SBase_getLevel(const SBase_t * sb)7592 SBase_getLevel (const SBase_t *sb)
7593 {
7594 return (sb != NULL) ? sb->getLevel() : SBML_INT_MAX;
7595 }
7596
7597
7598 LIBSBML_EXTERN
7599 unsigned int
SBase_getVersion(const SBase_t * sb)7600 SBase_getVersion (const SBase_t *sb)
7601 {
7602 return (sb != NULL) ? sb->getVersion() : SBML_INT_MAX;
7603 }
7604
7605
7606 LIBSBML_EXTERN
7607 XMLNode_t *
SBase_getNotes(SBase_t * sb)7608 SBase_getNotes (SBase_t *sb)
7609 {
7610 return (sb != NULL) ? sb->getNotes() : NULL;
7611 }
7612
7613
7614 LIBSBML_EXTERN
7615 char*
SBase_getNotesString(SBase_t * sb)7616 SBase_getNotesString (SBase_t *sb)
7617 {
7618 return (sb != NULL && sb->isSetNotes()) ?
7619 safe_strdup(sb->getNotesString().c_str()) : NULL;
7620 }
7621
7622
7623 LIBSBML_EXTERN
7624 XMLNode_t *
SBase_getAnnotation(SBase_t * sb)7625 SBase_getAnnotation (SBase_t *sb)
7626 {
7627 return (sb != NULL) ? sb->getAnnotation() : NULL;
7628 }
7629
7630
7631 LIBSBML_EXTERN
7632 char*
SBase_getAnnotationString(SBase_t * sb)7633 SBase_getAnnotationString (SBase_t *sb)
7634 {
7635 return (sb != NULL && sb->isSetAnnotation()) ?
7636 safe_strdup(sb->getAnnotationString().c_str()) : NULL;
7637 }
7638
7639
7640 LIBSBML_EXTERN
7641 int
SBase_isSetMetaId(const SBase_t * sb)7642 SBase_isSetMetaId (const SBase_t *sb)
7643 {
7644 return (sb != NULL) ? static_cast<int>( sb->isSetMetaId() ) : 0;
7645 }
7646
7647
7648 LIBSBML_EXTERN
7649 int
SBase_isSetIdAttribute(const SBase_t * sb)7650 SBase_isSetIdAttribute (const SBase_t *sb)
7651 {
7652 return (sb != NULL) ? static_cast<int>( sb->isSetIdAttribute() ) : 0;
7653 }
7654
7655
7656 LIBSBML_EXTERN
7657 int
SBase_isSetName(const SBase_t * sb)7658 SBase_isSetName (const SBase_t *sb)
7659 {
7660 return (sb != NULL) ? static_cast<int>( sb->isSetName() ) : 0;
7661 }
7662
7663
7664 LIBSBML_EXTERN
7665 int
SBase_isSetNotes(const SBase_t * sb)7666 SBase_isSetNotes (const SBase_t *sb)
7667 {
7668 return (sb != NULL) ? static_cast<int>( sb->isSetNotes() ) : 0;
7669 }
7670
7671
7672 LIBSBML_EXTERN
7673 int
SBase_isSetAnnotation(const SBase_t * sb)7674 SBase_isSetAnnotation (const SBase_t *sb)
7675 {
7676 return (sb != NULL) ? static_cast<int>( sb->isSetAnnotation() ) : 0;
7677 }
7678
7679
7680 LIBSBML_EXTERN
7681 int
SBase_isSetSBOTerm(const SBase_t * sb)7682 SBase_isSetSBOTerm (const SBase_t *sb)
7683 {
7684 return (sb != NULL) ? static_cast<int>( sb->isSetSBOTerm() ) : 0;
7685 }
7686
7687
7688 LIBSBML_EXTERN
7689 int
SBase_setMetaId(SBase_t * sb,const char * metaid)7690 SBase_setMetaId (SBase_t *sb, const char *metaid)
7691 {
7692 if (sb != NULL)
7693 return (metaid == NULL) ? sb->unsetMetaId() : sb->setMetaId(metaid);
7694 else
7695 return LIBSBML_INVALID_OBJECT;
7696 }
7697
7698
7699 LIBSBML_EXTERN
7700 int
SBase_setIdAttribute(SBase_t * sb,const char * id)7701 SBase_setIdAttribute (SBase_t *sb, const char *id)
7702 {
7703 if (sb != NULL)
7704 return (id == NULL) ? sb->unsetIdAttribute() : sb->setIdAttribute(id);
7705 else
7706 return LIBSBML_INVALID_OBJECT;
7707 }
7708
7709
7710 LIBSBML_EXTERN
7711 int
SBase_setName(SBase_t * sb,const char * name)7712 SBase_setName (SBase_t *sb, const char *name)
7713 {
7714 if (sb != NULL)
7715 return (name == NULL) ? sb->unsetName() : sb->setName(name);
7716 else
7717 return LIBSBML_INVALID_OBJECT;
7718 }
7719
7720
7721 LIBSBML_EXTERN
7722 int
SBase_setSBOTerm(SBase_t * sb,int value)7723 SBase_setSBOTerm (SBase_t *sb, int value)
7724 {
7725 if (sb != NULL)
7726 return sb->setSBOTerm(value);
7727 else
7728 return LIBSBML_INVALID_OBJECT;
7729 }
7730
7731
7732 LIBSBML_EXTERN
7733 int
SBase_setSBOTermID(SBase_t * sb,const char * sboid)7734 SBase_setSBOTermID (SBase_t *sb, const char* sboid)
7735 {
7736 if (sb != NULL)
7737 return sb->setSBOTerm(sboid);
7738 else
7739 return LIBSBML_INVALID_OBJECT;
7740 }
7741
7742
7743 LIBSBML_EXTERN
7744 int
SBase_setNamespaces(SBase_t * sb,XMLNamespaces_t * xmlns)7745 SBase_setNamespaces (SBase_t *sb, XMLNamespaces_t *xmlns)
7746 {
7747 if (sb != NULL)
7748 return sb->setNamespaces(xmlns);
7749 else
7750 return LIBSBML_INVALID_OBJECT;
7751 }
7752
7753
7754 LIBSBML_EXTERN
7755 int
SBase_setNotes(SBase_t * sb,XMLNode_t * notes)7756 SBase_setNotes (SBase_t *sb, XMLNode_t *notes)
7757 {
7758 if (sb != NULL)
7759 return sb->setNotes(notes);
7760 else
7761 return LIBSBML_INVALID_OBJECT;
7762 }
7763
7764
7765 LIBSBML_EXTERN
7766 int
SBase_setNotesString(SBase_t * sb,const char * notes)7767 SBase_setNotesString (SBase_t *sb, const char *notes)
7768 {
7769 if (sb != NULL)
7770 {
7771 if(notes == NULL)
7772 {
7773 return sb->unsetNotes();
7774 }
7775 else
7776 {
7777 return sb->setNotes(notes);
7778 }
7779 }
7780 else
7781 return LIBSBML_INVALID_OBJECT;
7782 }
7783
7784
7785 LIBSBML_EXTERN
7786 int
SBase_setNotesStringAddMarkup(SBase_t * sb,const char * notes)7787 SBase_setNotesStringAddMarkup (SBase_t *sb, const char *notes)
7788 {
7789 if (sb != NULL)
7790 {
7791 if(notes == NULL)
7792 {
7793 return sb->unsetNotes();
7794 }
7795 else
7796 {
7797 return sb->setNotes(notes, true);
7798 }
7799 }
7800 else
7801 return LIBSBML_INVALID_OBJECT;
7802 }
7803
7804
7805 LIBSBML_EXTERN
7806 int
SBase_appendNotes(SBase_t * sb,XMLNode_t * notes)7807 SBase_appendNotes (SBase_t *sb, XMLNode_t *notes)
7808 {
7809 if (sb != NULL)
7810 return sb->appendNotes(notes);
7811 else
7812 return LIBSBML_INVALID_OBJECT;
7813 }
7814
7815
7816 LIBSBML_EXTERN
7817 int
SBase_appendNotesString(SBase_t * sb,const char * notes)7818 SBase_appendNotesString (SBase_t *sb, const char *notes)
7819 {
7820 if (sb != NULL)
7821 {
7822 if (notes != NULL)
7823 return sb->appendNotes(notes);
7824 else
7825 return LIBSBML_INVALID_OBJECT;
7826 }
7827 else
7828 return LIBSBML_INVALID_OBJECT;
7829 }
7830
7831
7832 LIBSBML_EXTERN
7833 int
SBase_setAnnotation(SBase_t * sb,XMLNode_t * annotation)7834 SBase_setAnnotation (SBase_t *sb, XMLNode_t *annotation)
7835 {
7836 if (sb != NULL)
7837 return sb->setAnnotation(annotation);
7838 else
7839 return LIBSBML_INVALID_OBJECT;
7840 }
7841
7842
7843 LIBSBML_EXTERN
7844 int
SBase_setAnnotationString(SBase_t * sb,const char * annotation)7845 SBase_setAnnotationString (SBase_t *sb, const char *annotation)
7846 {
7847 if (sb != NULL)
7848 {
7849 if(annotation == NULL)
7850 {
7851 return sb->unsetAnnotation();
7852 }
7853 else
7854 {
7855 return sb->setAnnotation(annotation);
7856 }
7857 }
7858 else
7859 return LIBSBML_INVALID_OBJECT;
7860 }
7861
7862
7863 LIBSBML_EXTERN
7864 int
SBase_appendAnnotation(SBase_t * sb,XMLNode_t * annotation)7865 SBase_appendAnnotation (SBase_t *sb, XMLNode_t *annotation)
7866 {
7867 if (sb != NULL)
7868 return sb->appendAnnotation(annotation);
7869 else
7870 return LIBSBML_INVALID_OBJECT;
7871 }
7872
7873
7874 LIBSBML_EXTERN
7875 int
SBase_appendAnnotationString(SBase_t * sb,const char * annotation)7876 SBase_appendAnnotationString (SBase_t *sb, const char *annotation)
7877 {
7878 if (sb != NULL)
7879 {
7880 if (annotation != NULL)
7881 return sb->appendAnnotation(annotation);
7882 else
7883 return LIBSBML_INVALID_OBJECT;
7884 }
7885 else
7886 return LIBSBML_INVALID_OBJECT;
7887 }
7888
7889 LIBSBML_EXTERN
7890 int
SBase_removeTopLevelAnnotationElement(SBase_t * sb,const char * name)7891 SBase_removeTopLevelAnnotationElement (SBase_t *sb, const char *name)
7892 {
7893 if (sb != NULL)
7894 {
7895 if (name != NULL)
7896 return sb->removeTopLevelAnnotationElement(name);
7897 else
7898 return LIBSBML_INVALID_OBJECT;
7899 }
7900 else
7901 return LIBSBML_INVALID_OBJECT;
7902 }
7903
7904
7905 LIBSBML_EXTERN
7906 int
SBase_removeTopLevelAnnotationElementWithURI(SBase_t * sb,const char * name,const char * uri)7907 SBase_removeTopLevelAnnotationElementWithURI (SBase_t *sb, const char *name,
7908 const char *uri)
7909 {
7910 if (sb != NULL)
7911 {
7912 if (name != NULL && uri != NULL)
7913 return sb->removeTopLevelAnnotationElement(name, uri);
7914 else
7915 return LIBSBML_INVALID_OBJECT;
7916 }
7917 else
7918 return LIBSBML_INVALID_OBJECT;
7919 }
7920
7921
7922 LIBSBML_EXTERN
7923 int
SBase_replaceTopLevelAnnotationElement(SBase_t * sb,XMLNode_t * annotation)7924 SBase_replaceTopLevelAnnotationElement (SBase_t *sb, XMLNode_t *annotation)
7925 {
7926 if (sb != NULL)
7927 {
7928 if (annotation != NULL)
7929 return sb->replaceTopLevelAnnotationElement(annotation);
7930 else
7931 return LIBSBML_INVALID_OBJECT;
7932 }
7933 else
7934 return LIBSBML_INVALID_OBJECT;
7935 }
7936
7937
7938 LIBSBML_EXTERN
7939 int
SBase_replaceTopLevelAnnotationElementString(SBase_t * sb,const char * annotation)7940 SBase_replaceTopLevelAnnotationElementString (SBase_t *sb, const char *annotation)
7941 {
7942 if (sb != NULL)
7943 {
7944 if (annotation != NULL)
7945 return sb->replaceTopLevelAnnotationElement(annotation);
7946 else
7947 return LIBSBML_INVALID_OBJECT;
7948 }
7949 else
7950 return LIBSBML_INVALID_OBJECT;
7951 }
7952
7953
7954 LIBSBML_EXTERN
7955 int
SBase_unsetMetaId(SBase_t * sb)7956 SBase_unsetMetaId (SBase_t *sb)
7957 {
7958 if (sb != NULL)
7959 return sb->unsetMetaId();
7960 else
7961 return LIBSBML_INVALID_OBJECT;
7962 }
7963
7964
7965 LIBSBML_EXTERN
7966 int
SBase_unsetIdAttribute(SBase_t * sb)7967 SBase_unsetIdAttribute (SBase_t *sb)
7968 {
7969 if (sb != NULL)
7970 return sb->unsetIdAttribute();
7971 else
7972 return LIBSBML_INVALID_OBJECT;
7973 }
7974
7975
7976 LIBSBML_EXTERN
7977 int
SBase_unsetName(SBase_t * sb)7978 SBase_unsetName (SBase_t *sb)
7979 {
7980 if (sb != NULL)
7981 return sb->unsetName();
7982 else
7983 return LIBSBML_INVALID_OBJECT;
7984 }
7985
7986
7987 ///*
7988 //* Unsets the "id" attribute of the given object.
7989 //*
7990 //* @param sb the SBase_t structure.
7991 //*
7992 //* @copydetails doc_returns_success_code
7993 //* @li @link OperationReturnValues_t#LIBSBML_OPERATION_SUCCESS LIBSBML_OPERATION_SUCCESS @endlink
7994 //* @li @link OperationReturnValues_t#LIBSBML_OPERATION_FAILED LIBSBML_OPERATION_FAILED @endlink
7995 //*/
7996 //LIBSBML_EXTERN
7997 //int
7998 //SBase_unsetId (SBase_t *sb)
7999 //{
8000 // return sb->unsetId();
8001 //}
8002 //
8003
8004 LIBSBML_EXTERN
8005 int
SBase_unsetNotes(SBase_t * sb)8006 SBase_unsetNotes (SBase_t *sb)
8007 {
8008 if (sb != NULL)
8009 return sb->unsetNotes();
8010 else
8011 return LIBSBML_INVALID_OBJECT;
8012 }
8013
8014
8015 LIBSBML_EXTERN
8016 int
SBase_unsetAnnotation(SBase_t * sb)8017 SBase_unsetAnnotation (SBase_t *sb)
8018 {
8019 if (sb != NULL)
8020 return sb->unsetAnnotation();
8021 else
8022 return LIBSBML_INVALID_OBJECT;
8023 }
8024
8025
8026 LIBSBML_EXTERN
8027 int
SBase_unsetSBOTerm(SBase_t * sb)8028 SBase_unsetSBOTerm (SBase_t *sb)
8029 {
8030 if (sb != NULL)
8031 return sb->unsetSBOTerm();
8032 else
8033 return LIBSBML_INVALID_OBJECT;
8034 }
8035
8036
8037 LIBSBML_EXTERN
8038 const Model_t *
SBase_getModel(const SBase_t * sb)8039 SBase_getModel (const SBase_t *sb)
8040 {
8041 return (sb != NULL) ? sb->getModel() : NULL;
8042 }
8043
8044 LIBSBML_EXTERN
8045 int
SBase_getTypeCode(const SBase_t * sb)8046 SBase_getTypeCode (const SBase_t *sb)
8047 {
8048 return (sb != NULL) ? sb->getTypeCode() : SBML_UNKNOWN;
8049 }
8050
8051
8052 LIBSBML_EXTERN
8053 const char *
SBase_getElementName(const SBase_t * sb)8054 SBase_getElementName (const SBase_t *sb)
8055 {
8056 return (sb != NULL && !(sb->getElementName().empty())) ?
8057 sb->getElementName().c_str() : NULL;
8058 }
8059
8060
8061 LIBSBML_EXTERN
8062 char *
SBase_getPackageName(const SBaseExtensionPoint_t * sb)8063 SBase_getPackageName(const SBaseExtensionPoint_t *sb)
8064 {
8065 if (sb == NULL) return NULL;
8066 return safe_strdup(sb->getPackageName().c_str());
8067 }
8068
8069
8070 LIBSBML_EXTERN
8071 unsigned int
SBase_getLine(const SBase_t * sb)8072 SBase_getLine (const SBase_t *sb)
8073 {
8074 return (sb != NULL) ? sb->getLine() : 0;
8075 }
8076
8077
8078 LIBSBML_EXTERN
8079 unsigned int
SBase_getColumn(const SBase_t * sb)8080 SBase_getColumn (const SBase_t *sb)
8081 {
8082 return (sb != NULL) ? sb->getColumn() : 0;
8083 }
8084
8085
8086 LIBSBML_EXTERN
8087 int
SBase_hasValidLevelVersionNamespaceCombination(SBase_t * sb)8088 SBase_hasValidLevelVersionNamespaceCombination(SBase_t *sb)
8089 {
8090 return (sb != NULL) ?
8091 static_cast <int> (sb->hasValidLevelVersionNamespaceCombination()) : 0;
8092 }
8093
8094
8095 LIBSBML_EXTERN
8096 int
SBase_getNumPlugins(SBase_t * sb)8097 SBase_getNumPlugins(SBase_t *sb)
8098 {
8099 return (sb != NULL) ? (int)sb->getNumPlugins() : 0;
8100 }
8101
8102
8103 LIBSBML_EXTERN
8104 SBasePlugin_t*
SBase_getPlugin(SBase_t * sb,const char * package)8105 SBase_getPlugin(SBase_t *sb, const char *package)
8106 {
8107 return (sb != NULL) ? sb->getPlugin(package) : NULL;
8108 }
8109
8110 LIBSBML_EXTERN
8111 int
SBase_setUserData(SBase_t * sb,void * userData)8112 SBase_setUserData(SBase_t* sb, void *userData)
8113 {
8114 if (sb == NULL) return LIBSBML_INVALID_OBJECT;
8115 return sb->setUserData(userData);
8116 }
8117
8118
8119 LIBSBML_EXTERN
8120 void *
SBase_getUserData(const SBase_t * sb)8121 SBase_getUserData(const SBase_t* sb)
8122 {
8123 if (sb == NULL) return NULL;
8124 return sb->getUserData();
8125 }
8126
8127 LIBSBML_EXTERN
8128 int
SBase_isSetUserData(const SBase_t * sb)8129 SBase_isSetUserData(const SBase_t* sb)
8130 {
8131 if (sb == NULL) return 0;
8132 return static_cast <int>(sb->isSetUserData());
8133 }
8134
8135 LIBSBML_EXTERN
8136 int
SBase_unsetUserData(SBase_t * sb)8137 SBase_unsetUserData(SBase_t* sb)
8138 {
8139 if (sb == NULL) return LIBSBML_INVALID_OBJECT;
8140 return sb->unsetUserData();
8141 }
8142
8143 LIBSBML_EXTERN
8144 SBase_t*
SBase_getElementBySId(SBase_t * sb,const char * id)8145 SBase_getElementBySId(SBase_t* sb, const char* id)
8146 {
8147 if (sb == NULL) return NULL;
8148 return sb->getElementBySId(id);
8149 }
8150
8151 LIBSBML_EXTERN
8152 SBase_t*
SBase_getElementByMetaId(SBase_t * sb,const char * metaid)8153 SBase_getElementByMetaId(SBase_t* sb, const char* metaid)
8154 {
8155 if (sb == NULL) return NULL;
8156 return sb->getElementByMetaId(metaid);
8157 }
8158
8159 LIBSBML_EXTERN
8160 List_t*
SBase_getAllElements(SBase_t * sb)8161 SBase_getAllElements(SBase_t* sb)
8162 {
8163 if (sb == NULL) return NULL;
8164 return sb->getAllElements();
8165 }
8166
8167 LIBSBML_EXTERN
8168 void
SBase_renameSIdRefs(SBase_t * sb,const char * oldid,const char * newid)8169 SBase_renameSIdRefs(SBase_t* sb, const char* oldid, const char* newid)
8170 {
8171 if (sb == NULL) return;
8172 return sb->renameSIdRefs(oldid, newid);
8173 }
8174
8175 LIBSBML_EXTERN
8176 void
SBase_renameMetaIdRefs(SBase_t * sb,const char * oldid,const char * newid)8177 SBase_renameMetaIdRefs(SBase_t* sb, const char* oldid, const char* newid)
8178 {
8179 if (sb == NULL) return;
8180 return sb->renameMetaIdRefs(oldid, newid);
8181 }
8182
8183 LIBSBML_EXTERN
8184 void
SBase_renameUnitSIdRefs(SBase_t * sb,const char * oldid,const char * newid)8185 SBase_renameUnitSIdRefs(SBase_t* sb, const char* oldid, const char* newid)
8186 {
8187 if (sb == NULL) return;
8188 return sb->renameUnitSIdRefs(oldid, newid);
8189 }
8190
8191 LIBSBML_EXTERN
8192 SBase_t*
SBase_getElementFromPluginsBySId(SBase_t * sb,const char * id)8193 SBase_getElementFromPluginsBySId(SBase_t* sb, const char* id)
8194 {
8195 if (sb == NULL) return NULL;
8196 return sb->getElementFromPluginsBySId(id);
8197 }
8198
8199 LIBSBML_EXTERN
8200 SBase_t*
SBase_getElementFromPluginsByMetaId(SBase_t * sb,const char * metaid)8201 SBase_getElementFromPluginsByMetaId(SBase_t* sb, const char* metaid)
8202 {
8203 if (sb == NULL) return NULL;
8204 return sb->getElementFromPluginsByMetaId(metaid);
8205 }
8206
8207 LIBSBML_EXTERN
8208 List_t*
SBase_getAllElementsFromPlugins(SBase_t * sb)8209 SBase_getAllElementsFromPlugins(SBase_t* sb)
8210 {
8211 if (sb == NULL) return NULL;
8212 return sb->getAllElementsFromPlugins();
8213 }
8214 /** @endcond */
8215
8216 LIBSBML_CPP_NAMESPACE_END
8217