Skip to content

Commit c920c75

Browse files
authored
validate ssv files against schema (#1261)
* validate ssv files * validate ssm files * validate modelDescription.xml in FMU
1 parent e34d2b9 commit c920c75

30 files changed

Lines changed: 759 additions & 53 deletions

src/OMSimulatorLib/Scope.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ oms_status_enu_t oms::Scope::importModel(const std::string& filename, char** _cr
198198
return logError("failed to extract \"SystemStructure.ssd\" from \"" + std::string(filename) + "\"");
199199

200200
XercesValidator xercesValidator;
201-
xercesValidator.validateSSD(systemStructure, filename);
201+
xercesValidator.validateSSP(systemStructure, filename);
202202

203203
Snapshot snapshot;
204204
oms_status_enu_t status = snapshot.importResourceMemory("SystemStructure.ssd", systemStructure);

src/OMSimulatorLib/Values.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#include "Logging.h"
3636
#include "ssd/Tags.h"
3737
#include "Util.h"
38+
#include "XercesValidator.h"
3839

3940
#include <iostream>
4041
#include <map>
@@ -841,6 +842,14 @@ oms_status_enu_t oms::Values::importFromSnapshot(const pugi::xml_node& node, con
841842
std::string ssvFile = parameterBindingNode.attribute("source").as_string();
842843
if (!ssvFile.empty()) // parameter binding provided with .ssv file
843844
{
845+
// validate ssv files against SSP schem, only if the file exists, because it is possible we use importSnapShot API
846+
// to go back to old states and in this case we should not validate those ssv files in memory until it is exported to a ssp
847+
if (filesystem::exists(ssvFile))
848+
{
849+
XercesValidator xercesValidator;
850+
xercesValidator.validateSSP("", ssvFile);
851+
}
852+
844853
//resourceFiles.push_back(ssvFile);
845854
pugi::xml_node parameterSet = snapshot.getResourceNode(ssvFile);
846855
if (!parameterSet)
@@ -857,6 +866,12 @@ oms_status_enu_t oms::Values::importFromSnapshot(const pugi::xml_node& node, con
857866
std::string ssmFileSource = ssd_parameterMapping.attribute("source").as_string();
858867
if (!ssmFileSource.empty())
859868
{
869+
// validate ssm file only if it exists
870+
if (filesystem::exists(ssmFileSource))
871+
{
872+
XercesValidator xercesValidator;
873+
xercesValidator.validateSSP("", ssmFileSource);
874+
}
860875
pugi::xml_node ssm_parameterMapping = snapshot.getResourceNode(ssmFileSource);
861876
if (!ssm_parameterMapping)
862877
return logError("loading <oms:file> \"" + ssmFileSource + "\" from <oms:snapshot> failed");
@@ -1476,6 +1491,10 @@ oms_status_enu_t oms::Values::parseModelDescription(const filesystem::path& root
14761491

14771492
const char* modelDescription = ::miniunz_onefile_to_memory(root.generic_string().c_str(), "modelDescription.xml");
14781493

1494+
// validate modeldescription.xml against schema fmi2ModelDescription.xsd
1495+
XercesValidator xercesValidator;
1496+
xercesValidator.validateFMU(modelDescription, root.generic_string());
1497+
14791498
Snapshot snapshot;
14801499
oms_status_enu_t status = snapshot.importResourceMemory("modelDescription.xml", modelDescription);
14811500
::miniunz_free(modelDescription);

src/OMSimulatorLib/XercesValidator.cpp

Lines changed: 109 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#include "Logging.h"
3636
#include "OMSFileSystem.h"
3737
#include "OMSString.h"
38+
#include <iostream>
3839

3940
#include <xercesc/parsers/XercesDOMParser.hpp>
4041
#include <xercesc/dom/DOM.hpp>
@@ -122,8 +123,14 @@ std::string oms::XercesValidator::getExecutablePath()
122123
return executablePath;
123124
}
124125

125-
oms_status_enu_t oms::XercesValidator::validateSSD(const char *ssd, const std::string& filePath)
126+
oms_status_enu_t oms::XercesValidator::validateSSP(const char *ssd, const std::string& filePath)
126127
{
128+
129+
std::string extension = filesystem::path(filePath).extension().generic_string();
130+
131+
if (extension != ".ssp" && extension != ".ssv" && extension != ".ssm")
132+
return logWarning("filename extension must be \".ssp\" or \".ssv\" or \".ssm\" ; no other formats are supported for SSP validation");
133+
127134
try
128135
{
129136
XMLPlatformUtils::Initialize();
@@ -142,24 +149,40 @@ oms_status_enu_t oms::XercesValidator::validateSSD(const char *ssd, const std::s
142149
return logError("executable path could not be found");
143150

144151
filesystem::path schemaRootPath (path);
145-
filesystem::path schemaFilePath;
152+
filesystem::path schemaSSDPath, schemaSSVPath, schemaSSMPath;
153+
154+
schemaSSDPath = schemaRootPath / "../share/OMSimulator/schema/ssp/SystemStructureDescription.xsd";
155+
schemaSSVPath = schemaRootPath / "../share/OMSimulator/schema/ssp/SystemStructureParameterValues.xsd";
156+
schemaSSMPath = schemaRootPath / "../share/OMSimulator/schema/ssp/SystemStructureParameterMapping.xsd";
146157

147-
schemaFilePath = schemaRootPath / "../share/OMSimulator/schema/ssp/SystemStructureDescription.xsd";
148158
// std::cout << "schemaPath: " << schemaFilePath.generic_string() << "\n" << filesystem::absolute(schemaFilePath).generic_string() << "\n";
149159

150160
// this is done if we run the OMSimulator using python extension (e.g) python3 test.py and in this case the executable path is the dll path
151161
// for windows and mingw "libOMSimulator.dll" is put in "install/bin" directory and for linux and other platforms
152162
// the shared libraries are put in "install/lib/x86_64-linux-gnu/", so to find the schema location we have to move two directories back
153-
if (!filesystem::exists(schemaFilePath))
154-
schemaFilePath = schemaRootPath / "../../share/OMSimulator/schema/ssp/SystemStructureDescription.xsd";
163+
if (!filesystem::exists(schemaSSDPath))
164+
{
165+
schemaSSDPath = schemaRootPath / "../../share/OMSimulator/schema/ssp/SystemStructureDescription.xsd";
166+
schemaSSVPath = schemaRootPath / "../../share/OMSimulator/schema/ssp/SystemStructureParameterValues.xsd";
167+
schemaSSMPath = schemaRootPath / "../../share/OMSimulator/schema/ssp/SystemStructureParameterMapping.xsd";
168+
}
155169

156170
XercesDOMParser domParser;
157171

158172
// load the schema
159-
if (domParser.loadGrammar(schemaFilePath.generic_string().c_str(), Grammar::SchemaGrammarType) == NULL)
160-
return logError("could not load the ssd schema file: " + filesystem::absolute(schemaFilePath).generic_string());
173+
if (domParser.loadGrammar(schemaSSDPath.generic_string().c_str(), Grammar::SchemaGrammarType) == NULL)
174+
return logError("could not load the ssd schema file: " + filesystem::absolute(schemaSSDPath).generic_string());
175+
176+
std::string sspVariant = "";
177+
178+
if (extension == ".ssp")
179+
sspVariant = "SystemStructureDescription";
180+
else if (extension == ".ssv")
181+
sspVariant = "SystemStructureParameterValues";
182+
else if (extension == ".ssm")
183+
sspVariant = "SystemStructureParameterMapping";
161184

162-
ParserErrorHandler parserErrorHandler("SystemStructure.ssd", filePath.c_str());
185+
ParserErrorHandler parserErrorHandler(sspVariant.c_str(), filePath.c_str());
163186

164187
domParser.setErrorHandler(&parserErrorHandler);
165188
domParser.cacheGrammarFromParse(true);
@@ -169,14 +192,88 @@ oms_status_enu_t oms::XercesValidator::validateSSD(const char *ssd, const std::s
169192
domParser.setValidationSchemaFullChecking(true);
170193
domParser.setValidationConstraintFatal(true);
171194
// domParser.setExternalNoNamespaceSchemaLocation(schemaFilePath); // set this for noNameSpace
172-
std::string ssdTargetNameSpacePath = "http://ssp-standard.org/SSP1/SystemStructureDescription " + schemaFilePath.generic_string();
195+
std::string ssdTargetNameSpacePath = "http://ssp-standard.org/SSP1/SystemStructureDescription " + schemaSSDPath.generic_string();
196+
ssdTargetNameSpacePath = ssdTargetNameSpacePath + " http://ssp-standard.org/SSP1/SystemStructureParameterValues " + schemaSSVPath.generic_string();
197+
ssdTargetNameSpacePath = ssdTargetNameSpacePath + " http://ssp-standard.org/SSP1/SystemStructureParameterMapping " + schemaSSMPath.generic_string();
198+
173199
domParser.setExternalSchemaLocation(ssdTargetNameSpacePath.c_str());
174200

175-
xercesc::MemBufInputSource pMemBufIS((const XMLByte*)ssd, std::string(ssd).size() , "ssdfile");
201+
if (strlen(ssd) > 0)
202+
{
203+
xercesc::MemBufInputSource pMemBufIS((const XMLByte *)ssd, std::string(ssd).size(), "ssdfile");
204+
domParser.parse(pMemBufIS);
205+
}
206+
else
207+
{
208+
domParser.parse(filePath.c_str());
209+
}
210+
211+
if (domParser.getErrorCount() > 0)
212+
return logWarning( "\"" + sspVariant + "\"" + " does not conform to the SSP standard schema");
213+
214+
return oms_status_ok;
215+
}
216+
217+
oms_status_enu_t oms::XercesValidator::validateFMU(const char *modeldescription, const std::string& filePath)
218+
{
219+
220+
std::string extension = filesystem::path(filePath).extension().generic_string();
221+
222+
if (extension != ".fmu")
223+
return logWarning("filename extension must be \".fmu\" ; no other formats are supported for fmu validation");
224+
225+
try
226+
{
227+
XMLPlatformUtils::Initialize();
228+
}
229+
catch (const XMLException &toCatch)
230+
{
231+
char *message = XMLString::transcode(toCatch.getMessage());
232+
logError("Xerces error during initialization: "+ std::string(message));
233+
XMLString::release(&message);
234+
return oms_status_error;
235+
}
236+
237+
std::string path = getExecutablePath();
238+
239+
if (path.empty())
240+
return logError("executable path could not be found");
241+
242+
filesystem::path schemaRootPath (path);
243+
filesystem::path schemaFmiModeldescriptionPath;
244+
245+
schemaFmiModeldescriptionPath = schemaRootPath / "../share/OMSimulator/schema/fmi2/fmi2ModelDescription.xsd";
246+
247+
// this is done if we run the OMSimulator using python extension (e.g) python3 test.py and in this case the executable path is the dll path
248+
// for windows and mingw "libOMSimulator.dll" is put in "install/bin" directory and for linux and other platforms
249+
// the shared libraries are put in "install/lib/x86_64-linux-gnu/", so to find the schema location we have to move two directories back
250+
if (!filesystem::exists(schemaFmiModeldescriptionPath))
251+
{
252+
schemaFmiModeldescriptionPath = schemaRootPath / "../../share/OMSimulator/schema/fmi2/fmi2ModelDescription.xsd";
253+
}
254+
255+
XercesDOMParser domParser;
256+
257+
// load the schema
258+
if (domParser.loadGrammar(schemaFmiModeldescriptionPath.generic_string().c_str(), Grammar::SchemaGrammarType) == NULL)
259+
return logError("could not load the ssd schema file: " + filesystem::absolute(schemaFmiModeldescriptionPath).generic_string());
260+
261+
ParserErrorHandler parserErrorHandler("modeldescription.xml", filePath.c_str());
262+
263+
domParser.setErrorHandler(&parserErrorHandler);
264+
domParser.cacheGrammarFromParse(true);
265+
domParser.setValidationScheme(XercesDOMParser::Val_Always);
266+
domParser.setDoNamespaces(true);
267+
domParser.setDoSchema(true);
268+
domParser.setValidationSchemaFullChecking(true);
269+
domParser.setValidationConstraintFatal(true);
270+
domParser.setExternalNoNamespaceSchemaLocation(schemaFmiModeldescriptionPath.generic_string().c_str()); // set this for noNameSpace
271+
272+
xercesc::MemBufInputSource pMemBufIS((const XMLByte *)modeldescription, std::string(modeldescription).size(), "modeldescriptionfile");
176273
domParser.parse(pMemBufIS);
177274

178275
if (domParser.getErrorCount() > 0)
179-
return logWarning("\"SystemStructure.ssd\" does not conform to the SSP standard schema");
276+
return logWarning("\"modeldescription.xml\" does not conform to the FMI-2.0 standard schema");
180277

181278
return oms_status_ok;
182-
}
279+
}

src/OMSimulatorLib/XercesValidator.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ namespace oms
4646
public:
4747
XercesValidator();
4848
~XercesValidator();
49-
oms_status_enu_t validateSSD(const char * ssd, const std::string& filePath);
49+
oms_status_enu_t validateSSP(const char * ssd, const std::string& filePath);
50+
oms_status_enu_t validateFMU(const char * modeldescription, const std::string& filePath);
5051
std::string getExecutablePath();
5152
};
5253
}

testsuite/AircraftVehicleDemonstrator/embrace.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,15 +67,17 @@
6767
oms.delete("embrace")
6868

6969
## Result:
70-
## warning: invalid "SystemStructure.ssd" detected in file "../../resources/embrace.ssp" at line: 17 column: 26, missing required attribute 'name'
71-
## warning: "SystemStructure.ssd" does not conform to the SSP standard schema
70+
## warning: invalid "SystemStructureDescription" detected in file "../../resources/embrace.ssp" at line: 17 column: 26, missing required attribute 'name'
71+
## warning: "SystemStructureDescription" does not conform to the SSP standard schema
72+
## warning: invalid "SystemStructureParameterValues" detected in file "resources/RAPID_Systems_2021-03-29_Test_1.ssv" at line: 3 column: 10, element 'Units' must be qualified
73+
## warning: "SystemStructureParameterValues" does not conform to the SSP standard schema
7274
## info: Result file: sim_results.mat (bufferSize=1)
7375
## info: Initialize:
7476
## info: embrace.root.ECS_HW.coolinPackAir.looptype: 2
7577
## info: embrace.root.ECS_HW.eCS.MaxCoolPower.k : 5.0
7678
## info: embrace.root.ECS_HW.pipeC.L : 1.0
7779
## info: embrace.root.ECS_HW.pipeB.L : 0.976535328081166
7880
## info: embrace.root.ECS_HW.pipeA.L : 0.976535328081166
79-
## info: 2 warnings
81+
## info: 4 warnings
8082
## info: 0 errors
8183
## endResult

testsuite/AircraftVehicleDemonstrator/embrace_test2Conf.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,15 +76,17 @@
7676
oms.delete("model")
7777

7878
## Result:
79-
## warning: invalid "SystemStructure.ssd" detected in file "../../resources/embrace_TwoConf.ssp" at line: 17 column: 26, missing required attribute 'name'
80-
## warning: "SystemStructure.ssd" does not conform to the SSP standard schema
79+
## warning: invalid "SystemStructureDescription" detected in file "../../resources/embrace_TwoConf.ssp" at line: 17 column: 26, missing required attribute 'name'
80+
## warning: "SystemStructureDescription" does not conform to the SSP standard schema
81+
## warning: invalid "SystemStructureParameterValues" detected in file "resources/ECS_Conf2.ssv" at line: 3 column: 10, element 'Units' must be qualified
82+
## warning: "SystemStructureParameterValues" does not conform to the SSP standard schema
8183
## info: Result file: sim_results_ECS_Conf1.mat (bufferSize=1)
8284
## info: Initialize:
8385
## info: model.root.ECS_HW.coolinPackAir.looptype: 2
8486
## info: model.root.ECS_HW.eCS.MaxCoolPower.k : 5.0
8587
## info: model.root.ECS_HW.pipeC.L : 1.0
8688
## info: model.root.ECS_HW.pipeB.L : 7.41248272578546
8789
## info: model.root.ECS_HW.pipeA.L : 7.39290438403619
88-
## info: 2 warnings
90+
## info: 4 warnings
8991
## info: 0 errors
9092
## endResult

testsuite/resources/Makefile

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ fmi_attributes_19 \
2121
HelloWorld \
2222
HelloWorldWithInput \
2323
Int1 \
24+
invalidModeldescription \
2425
Lin2DimODE \
2526
Modelica.Blocks.Continuous.Integrator \
2627
Modelica.Blocks.Math.Add \
@@ -73,7 +74,9 @@ import_export_parameters1 \
7374
import_export_parameters2 \
7475
import_export_parameters3 \
7576
importExportAllResources \
76-
invalidSSP \
77+
invalidSSD \
78+
invalidSSV \
79+
invalidSSM \
7780
replaceSubmodel4 \
7881
replaceSubmodel5 \
7982

testsuite/resources/embrace/resources/RAPID_Systems_2021-03-29_Test_1.ssv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
<ssv:ParameterSet xmlns:ssv="http://ssp-standard.org/SSP1/SystemStructureParameterValues" xmlns:ssc="http://ssp-standard.org/SSP1/SystemStructureCommon" name="product_mainAssembly">
2+
<ssv:ParameterSet xmlns:ssv="http://ssp-standard.org/SSP1/SystemStructureParameterValues" xmlns:ssc="http://ssp-standard.org/SSP1/SystemStructureCommon" version="1.0" name="product_mainAssembly">
33
<Units>
44
<Unit name="m">
55
<BaseUnit m="1"/>

testsuite/resources/embrace_TwoConf/resources/ECS_Conf1.ssv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
<ssv:ParameterSet xmlns:ssv="http://ssp-standard.org/SSP1/SystemStructureParameterValues" xmlns:ssc="http://ssp-standard.org/SSP1/SystemStructureCommon" name="product_ECS">
2+
<ssv:ParameterSet xmlns:ssv="http://ssp-standard.org/SSP1/SystemStructureParameterValues" xmlns:ssc="http://ssp-standard.org/SSP1/SystemStructureCommon" version="1.0" name="product_ECS">
33
<Units>
44
<Unit name="m">
55
<BaseUnit m="1"/>

testsuite/resources/embrace_TwoConf/resources/ECS_Conf2.ssv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
<ssv:ParameterSet xmlns:ssv="http://ssp-standard.org/SSP1/SystemStructureParameterValues" xmlns:ssc="http://ssp-standard.org/SSP1/SystemStructureCommon" name="product_ECS2">
2+
<ssv:ParameterSet xmlns:ssv="http://ssp-standard.org/SSP1/SystemStructureParameterValues" xmlns:ssc="http://ssp-standard.org/SSP1/SystemStructureCommon" version="1.0" name="product_ECS2">
33
<Units>
44
<Unit name="m">
55
<BaseUnit m="1"/>

0 commit comments

Comments
 (0)