Add an XSD validation scheme and implement ParameterManager::CheckDocument(), function is used in the parameter editor

This commit is contained in:
wmayer
2019-10-14 22:56:03 +02:00
parent eff400620c
commit bd76bbd625
5 changed files with 136 additions and 2 deletions

View File

@@ -89,6 +89,7 @@ generate_from_xml(PlacementPy)
generate_from_xml(AxisPy)
generate_from_xml(UnitPy)
generate_from_xml(QuantityPy)
generate_from_any(Parameter.xsd Parameter.inl xmlSchemeString)
if(SWIG_FOUND)
# Create the file swigpyrun.hh and then compare with the file swigpyrun.h.
@@ -254,6 +255,7 @@ SET(FreeCADBase_CPP_SRCS
Matrix.cpp
MatrixPyImp.cpp
MemDebug.cpp
Parameter.xsd
Parameter.cpp
ParameterPy.cpp
Persistence.cpp

View File

@@ -39,6 +39,8 @@
# include <xercesc/framework/StdOutFormatTarget.hpp>
# include <xercesc/framework/LocalFileFormatTarget.hpp>
# include <xercesc/framework/LocalFileInputSource.hpp>
# include <xercesc/framework/MemBufFormatTarget.hpp>
# include <xercesc/framework/MemBufInputSource.hpp>
# include <xercesc/parsers/XercesDOMParser.hpp>
# include <xercesc/util/XMLUni.hpp>
# include <xercesc/util/XMLUniDefs.hpp>
@@ -62,6 +64,7 @@
#endif
#include "Parameter.h"
#include "Parameter.inl"
#include "Exception.h"
#include "Console.h"
@@ -1369,6 +1372,7 @@ void ParameterManager::SaveDocument(XMLFormatTarget* pFormatTarget) const
#else
try {
std::unique_ptr<DOMPrintFilter> myFilter;
std::unique_ptr<DOMErrorHandler> myErrorHandler;
// get a serializer, an instance of DOMWriter
XMLCh tempStr[100];
@@ -1378,8 +1382,7 @@ void ParameterManager::SaveDocument(XMLFormatTarget* pFormatTarget) const
// set user specified end of line sequence and output encoding
theSerializer->setNewLine(gMyEOLSequence);
DOMConfiguration* config = theSerializer->getDomConfig();
config->setParameter(XStr("format-pretty-print").unicodeForm(),true);
//
// do the serialization through DOMWriter::writeNode();
@@ -1396,8 +1399,25 @@ void ParameterManager::SaveDocument(XMLFormatTarget* pFormatTarget) const
theSerializer->setFilter(myFilter.get());
}
// plug in user's own error handler
myErrorHandler.reset(new DOMPrintErrorHandler());
DOMConfiguration* config = theSerializer->getDomConfig();
config->setParameter(XMLUni::fgDOMErrorHandler, myErrorHandler.get());
// set feature if the serializer supports the feature/mode
if (config->canSetParameter(XMLUni::fgDOMWRTSplitCdataSections, gSplitCdataSections))
config->setParameter(XMLUni::fgDOMWRTSplitCdataSections, gSplitCdataSections);
if (config->canSetParameter(XMLUni::fgDOMWRTDiscardDefaultContent, gDiscardDefaultContent))
config->setParameter(XMLUni::fgDOMWRTDiscardDefaultContent, gDiscardDefaultContent);
if (config->canSetParameter(XMLUni::fgDOMWRTFormatPrettyPrint, gFormatPrettyPrint))
config->setParameter(XMLUni::fgDOMWRTFormatPrettyPrint, gFormatPrettyPrint);
theOutput->setByteStream(pFormatTarget);
theSerializer->write(_pDocument, theOutput);
theOutput->release();
}
theSerializer->release();
@@ -1429,7 +1449,59 @@ void ParameterManager::CreateDocument(void)
void ParameterManager::CheckDocument() const
{
if (!_pDocument)
return;
try {
//
// Plug in a format target to receive the resultant
// XML stream from the serializer.
//
// LocalFileFormatTarget prints the resultant XML stream
// to a file once it receives any thing from the serializer.
//
MemBufFormatTarget myFormTarget;
SaveDocument(&myFormTarget);
// Either use the file saved on disk or write the current XML into a buffer in memory
// const char* xmlFile = "...";
MemBufInputSource xmlFile(myFormTarget.getRawBuffer(), myFormTarget.getLen(), "(memory)");
// Either load the XSD file from disk or use the built-in string
// const char* xsdFile = "...";
std::string xsdStr(xmlSchemeString);
MemBufInputSource xsdFile(reinterpret_cast<const XMLByte*>(xsdStr.c_str()), xsdStr.size(), "Parameter.xsd");
// See http://apache-xml-project.6118.n7.nabble.com/validating-xml-with-xsd-schema-td17515.html
//
XercesDOMParser parser;
Grammar* grammar = parser.loadGrammar(xsdFile, Grammar::SchemaGrammarType, true);
if (!grammar) {
Base::Console().Error("Grammar file cannot be loaded.\n");
return;
}
parser.setExternalNoNamespaceSchemaLocation("Parameter.xsd");
//parser.setExitOnFirstFatalError(true);
//parser.setValidationConstraintFatal(true);
parser.cacheGrammarFromParse(true);
parser.setValidationScheme(XercesDOMParser::Val_Auto);
parser.setDoNamespaces(true);
parser.setDoSchema(true);
DOMTreeErrorReporter errHandler;
parser.setErrorHandler(&errHandler);
parser.parse(xmlFile);
if (parser.getErrorCount() > 0) {
Base::Console().Error("Unexpected XML structure detected: %d errors\n", parser.getErrorCount());
}
}
catch (XMLException& e) {
std::cerr << "An error occurred while checking document. Msg is:"
<< std::endl
<< StrX(e.getMessage()) << std::endl;
}
}

57
src/Base/Parameter.xsd Normal file
View File

@@ -0,0 +1,57 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
To verify the user.cfg file against the XSD scheme add the following to the FCParameters element:
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="XSD_FILE_PATH"
-->
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="FCParameters">
<xs:complexType>
<xs:sequence>
<!-- This is the top-level parameter group -->
<xs:element ref="FCParamGroup" minOccurs="1" maxOccurs="1"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="FCParamGroup">
<xs:complexType>
<xs:choice maxOccurs="unbounded">
<xs:element ref="FCParamGroup" minOccurs="0" maxOccurs="unbounded"/>
<xs:element minOccurs="0" maxOccurs="unbounded" name="FCText">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="Name" type="xs:string" use="required" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
<xs:element minOccurs="0" maxOccurs="unbounded" name="FCBool">
<xs:complexType>
<xs:attribute name="Name" type="xs:string" use="required" />
<xs:attribute name="Value" type="xs:unsignedByte" use="required" />
</xs:complexType>
</xs:element>
<xs:element minOccurs="0" maxOccurs="unbounded" name="FCInt">
<xs:complexType>
<xs:attribute name="Name" type="xs:string" use="required" />
<xs:attribute name="Value" type="xs:int" use="required" />
</xs:complexType>
</xs:element>
<xs:element minOccurs="0" maxOccurs="unbounded" name="FCFloat">
<xs:complexType>
<xs:attribute name="Name" type="xs:string" use="required" />
<xs:attribute name="Value" type="xs:decimal" use="required" />
</xs:complexType>
</xs:element>
<xs:element minOccurs="0" maxOccurs="unbounded" name="FCUInt">
<xs:complexType>
<xs:attribute name="Name" type="xs:string" use="required" />
<xs:attribute name="Value" type="xs:unsignedInt" use="required" />
</xs:complexType>
</xs:element>
</xs:choice>
<xs:attribute name="Name" type="xs:string" use="required" />
</xs:complexType>
</xs:element>
</xs:schema>

View File

@@ -84,6 +84,8 @@
#include <xercesc/framework/StdOutFormatTarget.hpp>
#include <xercesc/framework/LocalFileFormatTarget.hpp>
#include <xercesc/framework/LocalFileInputSource.hpp>
#include <xercesc/framework/MemBufFormatTarget.hpp>
#include <xercesc/framework/MemBufInputSource.hpp>
#include <xercesc/parsers/XercesDOMParser.hpp>
#include <xercesc/util/XMLUni.hpp>
#include <xercesc/util/XMLUniDefs.hpp>

View File

@@ -266,6 +266,7 @@ void DlgParameterImp::onChangeParameterSet(int index)
if (!rcParMngr)
return;
rcParMngr->CheckDocument();
ui->buttonSaveToDisk->setEnabled(rcParMngr->HasSerializer());
// remove all labels