bool CellmlFile::doLoad(const QString &pFileName, const QString &pFileContents, ObjRef<iface::cellml_api::Model> *pModel, CellmlFileIssues &pIssues) { // Make sure that pIssues is empty pIssues.clear(); // Get a bootstrap object and its model loader ObjRef<iface::cellml_api::CellMLBootstrap> cellmlBootstrap = CreateCellMLBootstrap(); ObjRef<iface::cellml_api::DOMModelLoader> modelLoader = cellmlBootstrap->modelLoader(); // Try to create the model try { if (pFileContents.isEmpty()) *pModel = modelLoader->loadFromURL(QUrl::fromPercentEncoding(QUrl::fromLocalFile(pFileName).toEncoded()).toStdWString()); else *pModel = modelLoader->createFromText(pFileContents.toStdWString()); } catch (iface::cellml_api::CellMLException &exception) { // Something went wrong with the loading of the model if (pFileContents.isEmpty()) { pIssues << CellmlFileIssue(CellmlFileIssue::Error, QObject::tr("the model could not be loaded (%1)").arg(Core::formatMessage(QString::fromStdWString(exception.explanation)))); } else { pIssues << CellmlFileIssue(CellmlFileIssue::Error, QObject::tr("the model could not be created (%1)").arg(Core::formatMessage(QString::fromStdWString(exception.explanation)))); } return false; } // Update the base URI, should the CellML file be a remote one or its // contents be directly passed onto us Core::FileManager *fileManagerInstance = Core::FileManager::instance(); ObjRef<iface::cellml_api::URI> baseUri = (*pModel)->xmlBase(); if (fileManagerInstance->isRemote(pFileName)) { // We are dealing with a remote file, so its XML base value should point // to its remote location baseUri->asText(fileManagerInstance->url(pFileName).toStdWString()); } else if (!pFileContents.isEmpty()) { // We are dealing with a file which contents was directly passed onto // us, so its XML base value should point to its actual location baseUri->asText(pFileName.toStdWString()); } return true; }
QString CellmlFile::xmlBase() { // Return the CellML file's base URI if (load()) { ObjRef<iface::cellml_api::URI> baseUri = mModel->xmlBase(); return QString::fromStdWString(baseUri->asText()); } else { return QString(); } }
bool CellmlFile::isValid() { if (!mValidNeeded) // The file has already been validated, so... return mValid; // Load (but not reload!) the file, if needed if (load()) { // The file was properly loaded (or was already loaded), so check // whether it is CellML valid // Note: validateModel() is somewhat slow, but there is (unfortunately) // nothing we can do about it. Then, there is getPositionInXML() // which is painfully slow, but unlike for validateModel() its use // is not essential (even though it would be nice from an // end-user's perspective). So, rather than retrieve the // line/column of every single warning/error, we only keep track // of the various warnings/errors and only retrieve their // corresponding line/column when requested (definitely not neat // from an end-user's perspective, but we just can't afford the // time it takes to fully validate a model that has many // warnings/errors)... ObjRef<iface::cellml_services::VACSService> vacssService = CreateVACSService(); ObjRef<iface::cellml_services::CellMLValidityErrorSet> cellmlValidityErrorSet = vacssService->validateModel(mModel); // Determine the number of errors and warnings // Note: CellMLValidityErrorSet::nValidityErrors() returns any type of // validation issue, be it an error or a warning, so we need to // determine the number of true errors int cellmlErrorsCount = 0; for (int i = 0, iMax = cellmlValidityErrorSet->nValidityErrors(); i < iMax; ++i) { ObjRef<iface::cellml_services::CellMLValidityError> cellmlValidityIssue = cellmlValidityErrorSet->getValidityError(i); ObjRef<iface::cellml_services::CellMLRepresentationValidityError> cellmlRepresentationValidityError = QueryInterface(cellmlValidityIssue); // Determine the issue's location uint32_t line = 0; uint32_t column = 0; QString importedFile = QString(); if (cellmlRepresentationValidityError) { // We are dealing with a CellML representation issue, so // determine its line and column ObjRef<iface::dom::Node> errorNode = cellmlRepresentationValidityError->errorNode(); line = vacssService->getPositionInXML(errorNode, cellmlRepresentationValidityError->errorNodalOffset(), &column); } else { // We are not dealing with a CellML representation issue, so // check whether we are dealing with a semantic one ObjRef<iface::cellml_services::CellMLSemanticValidityError> cellmlSemanticValidityError = QueryInterface(cellmlValidityIssue); if (cellmlSemanticValidityError) { // We are dealing with a CellML semantic issue, so determine // its line and column ObjRef<iface::cellml_api::CellMLElement> cellmlElement = cellmlSemanticValidityError->errorElement(); ObjRef<iface::cellml_api::CellMLDOMElement> cellmlDomElement = QueryInterface(cellmlElement); ObjRef<iface::dom::Element> domElement = cellmlDomElement->domElement(); line = vacssService->getPositionInXML(domElement, 0, &column); // Also determine its imported file, if any forever { // Retrieve the CellML element's parent ObjRef<iface::cellml_api::CellMLElement> cellmlElementParent = cellmlElement->parentElement(); if (!cellmlElementParent) break; // Check whether the parent is an imported file ObjRef<iface::cellml_api::Model> importedCellmlFile = QueryInterface(cellmlElementParent); if (!importedCellmlFile) break; // Retrieve the imported CellML element ObjRef<iface::cellml_api::CellMLElement> importedCellmlElement = importedCellmlFile->parentElement(); if (!importedCellmlElement) break; // Check whether the imported CellML element is an // import CellML element ObjRef<iface::cellml_api::CellMLImport> importCellmlElement = QueryInterface(importedCellmlElement); if (!importCellmlElement) break; ObjRef<iface::cellml_api::URI> xlinkHref = importCellmlElement->xlinkHref(); importedFile = QString::fromStdWString(xlinkHref->asText()); break; } } } // Determine the issue's type CellmlFileIssue::Type issueType; if (cellmlValidityIssue->isWarningOnly()) { // We are dealing with a warning issueType = CellmlFileIssue::Warning; } else { // We are dealing with an error ++cellmlErrorsCount; issueType = CellmlFileIssue::Error; } // Append the issue to our list mIssues << CellmlFileIssue(issueType, QString::fromStdWString(cellmlValidityIssue->description()), line, column, importedFile); } if (cellmlErrorsCount) // There are CellML errors, so... mValid = false; else // Everything went as expected, so... mValid = true; mValidNeeded = false; return mValid; } else { // Something went wrong with the loading of the file, so... return false;
bool CellmlFile::doIsValid(iface::cellml_api::Model *pModel, CellmlFileIssues &pIssues) { // Check whether the given model is CellML valid // Note: validateModel() is somewhat slow, but there is (unfortunately) // nothing we can do about it. Then, there is getPositionInXML() which // is painfully slow, but unlike for validateModel() its use is not // essential (even though it would be nice from an end-user's // perspective). So, rather than retrieve the line/column of every // single warning/error, we only keep track of the various // warnings/errors and only retrieve their corresponding line/column // when requested (definitely not neat from an end-user's perspective, // but we just can't afford the time it takes to fully validate a // model that has many warnings/errors)... // Make sure that pIssues is empty pIssues.clear(); // Determine the number of errors and warnings // Note: CellMLValidityErrorSet::nValidityErrors() returns any type of // validation issue, be it an error or a warning, so we need to // determine the number of true errors ObjRef<iface::cellml_services::VACSService> vacssService = CreateVACSService(); ObjRef<iface::cellml_services::CellMLValidityErrorSet> cellmlValidityErrorSet = vacssService->validateModel(pModel); int cellmlErrorsCount = 0; for (int i = 0, iMax = cellmlValidityErrorSet->nValidityErrors(); i < iMax; ++i) { ObjRef<iface::cellml_services::CellMLValidityError> cellmlValidityIssue = cellmlValidityErrorSet->getValidityError(i); ObjRef<iface::cellml_services::CellMLRepresentationValidityError> cellmlRepresentationValidityError = QueryInterface(cellmlValidityIssue); // Determine the issue's location uint32_t line = 0; uint32_t column = 0; QString importedFile = QString(); if (cellmlRepresentationValidityError) { // We are dealing with a CellML representation issue, so determine // its line and column ObjRef<iface::dom::Node> errorNode = cellmlRepresentationValidityError->errorNode(); line = vacssService->getPositionInXML(errorNode, cellmlRepresentationValidityError->errorNodalOffset(), &column); } else { // We are not dealing with a CellML representation issue, so check // whether we are dealing with a semantic one ObjRef<iface::cellml_services::CellMLSemanticValidityError> cellmlSemanticValidityError = QueryInterface(cellmlValidityIssue); if (cellmlSemanticValidityError) { // We are dealing with a CellML semantic issue, so determine its // line and column ObjRef<iface::cellml_api::CellMLElement> cellmlElement = cellmlSemanticValidityError->errorElement(); ObjRef<iface::cellml_api::CellMLDOMElement> cellmlDomElement = QueryInterface(cellmlElement); ObjRef<iface::dom::Element> domElement = cellmlDomElement->domElement(); line = vacssService->getPositionInXML(domElement, 0, &column); // Also determine its imported file, if any ObjRef<iface::cellml_api::CellMLElement> cellmlElementParent = cellmlElement->parentElement(); if (cellmlElementParent) { // Check whether the parent is an imported file ObjRef<iface::cellml_api::Model> importedCellmlFile = QueryInterface(cellmlElementParent); if (importedCellmlFile) { // Retrieve the imported CellML element ObjRef<iface::cellml_api::CellMLElement> importedCellmlElement = importedCellmlFile->parentElement(); if (importedCellmlElement) { // Check whether the imported CellML element is an // import CellML element ObjRef<iface::cellml_api::CellMLImport> importCellmlElement = QueryInterface(importedCellmlElement); if (importCellmlElement) { ObjRef<iface::cellml_api::URI> xlinkHref = importCellmlElement->xlinkHref(); importedFile = QString::fromStdWString(xlinkHref->asText()); } } } } } } // Determine the issue's type CellmlFileIssue::Type issueType; if (cellmlValidityIssue->isWarningOnly()) { // We are dealing with a warning issueType = CellmlFileIssue::Warning; } else { // We are dealing with an error ++cellmlErrorsCount; issueType = CellmlFileIssue::Error; } // Append the issue to our list pIssues << CellmlFileIssue(issueType, line, column, QString::fromStdWString(cellmlValidityIssue->description()), importedFile); } // Sort our issues std::sort(pIssues.begin(), pIssues.end()); return !cellmlErrorsCount; }
bool CellmlFile::fullyInstantiateImports(iface::cellml_api::Model *pModel, CellmlFileIssues &pIssues) { // Fully instantiate all the imports, but only if we are dealing with a non // CellML 1.0 model, and then keep track of that fact (so we don't fully // instantiate everytime we come here) Version cellmlVersion = version(pModel); if ( mFullInstantiationNeeded && (cellmlVersion != Unknown) && (cellmlVersion != Cellml_1_0)) { try { // Note: the below is based on CDA_Model::fullyInstantiateImports(). // Indeed, CDA_Model::fullyInstantiateImports() doesn't work // with CellML imports that rely on https (see issue #417), so // rather than calling CDA_CellMLImport::instantiate(), we // call CDA_CellMLImport::instantiateFromText() instead, which // requires loading the imported CellML file. Otherwise, to // speed things up as much as possible, we cache the contents // of the URLs that we load... // Retrieve the list of imports, together with their XML base values ObjRef<iface::cellml_api::URI> baseUri = pModel->xmlBase(); QList<iface::cellml_api::CellMLImport *> importList = QList<iface::cellml_api::CellMLImport *>(); QStringList importXmlBaseList = QStringList(); retrieveImports(QString::fromStdWString(baseUri->asText()), pModel, importList, importXmlBaseList); // Instantiate all the imports in our list while (!importList.isEmpty()) { // Retrieve the first import and instantiate it, if needed ObjRef<iface::cellml_api::CellMLImport> import = importList.first(); QString importXmlBase = importXmlBaseList.first(); importList.removeFirst(); importXmlBaseList.removeFirst(); if (!import->wasInstantiated()) { // Note: CDA_CellMLImport::instantiate() would normally be // called, but it doesn't work with https, so we // retrieve the contents of the import ourselves and // instantiate it from text instead... ObjRef<iface::cellml_api::URI> xlinkHref = import->xlinkHref(); QString url = QUrl(importXmlBase).resolved(QString::fromStdWString(xlinkHref->asText())).toString(); bool isLocalFile; QString fileNameOrUrl; Core::checkFileNameOrUrl(url, isLocalFile, fileNameOrUrl); if (!fileNameOrUrl.compare(mFileName)) // We want to import ourselves, so... throw(std::exception()); else if (mImportContents.contains(fileNameOrUrl)) { // We have already loaded the import contents, so // directly instantiate the import with it import->instantiateFromText(mImportContents.value(fileNameOrUrl).toStdWString()); } else { // We haven't already loaded the import contents, so do // so now QString fileContents; if ( ( isLocalFile && Core::readTextFromFile(fileNameOrUrl, fileContents)) || (!isLocalFile && Core::readTextFromUrl(fileNameOrUrl, fileContents))) { // We were able to retrieve the import contents, so // instantiate the import with it import->instantiateFromText(fileContents.toStdWString()); // Keep track of the import contents mImportContents.insert(fileNameOrUrl, fileContents); } else { throw(std::exception()); } } // Now that the import is instantiated, add its own imports // to our list ObjRef<iface::cellml_api::Model> importModel = import->importedModel(); if (!importModel) throw(std::exception()); retrieveImports(isLocalFile? QUrl::fromLocalFile(fileNameOrUrl).toString(): fileNameOrUrl, importModel, importList, importXmlBaseList); } } mFullInstantiationNeeded = false; } catch (...) { // Something went wrong with the full instantiation of the imports pIssues << CellmlFileIssue(CellmlFileIssue::Error, QObject::tr("the imports could not be fully instantiated")); return false; } } return true; }