20#include "BDSException.hh"
21#include "BDSGDMLPreprocessor.hh"
22#include "BDSTemporaryFiles.hh"
23#include "BDSUtilities.hh"
25#include <xercesc/dom/DOM.hpp>
26#include <xercesc/framework/LocalFileFormatTarget.hpp>
27#include <xercesc/framework/StdOutFormatTarget.hpp>
28#include <xercesc/parsers/XercesDOMParser.hpp>
29#include <xercesc/sax/HandlerBase.hpp>
30#include <xercesc/util/PlatformUtils.hpp>
31#include <xercesc/util/XMLString.hpp>
35#include "G4Version.hh"
47using namespace xercesc;
49G4String BDS::PreprocessGDML(
const G4String& file,
50 const G4String& prefix,
51 G4bool preprocessSchema)
54 {
throw BDSException(__METHOD_NAME__,
"trying to read a GMAD file (\"" + file +
"\") as a GDML file - check file or change extension.");}
62G4String BDS::PreprocessGDMLSchemaOnly(
const G4String& file)
66 {
throw BDSException(__METHOD_NAME__,
"trying to read a GMAD file (\"" + file +
"\") as a GDML file - check file or change extension.");}
67 std::ifstream inputFile;
68 inputFile.open(file.c_str());
69 if (!inputFile.is_open())
70 {
throw BDSException(__METHOD_NAME__,
"Invalid file \"" + file +
"\"");}
72 {G4cout << __METHOD_NAME__ <<
"updating GDML Schema to local copy for file:\n \"" << file <<
"\"" << G4endl;}
77 std::ofstream outFile;
78 outFile.open(newFile);
82 std::regex gdmlTag(
"\\<gdml");
84 while (std::getline(inputFile, line))
88 if (std::regex_search(line, gdmlTag))
90 std::regex schema(
"xsi:noNamespaceSchemaLocation=\"(\\S+)\"");
92 std::string prefix =
"xsi:noNamespaceSchemaLocation=\"";
93 std::regex_replace(std::back_inserter(newLine), line.begin(), line.end(), schema, prefix+localSchema+
"\"$2");
112 G4String localPath = bdsimExecPath +
"src-external/gdml/schema/gdml.xsd";
113 G4String installPath = bdsimExecPath +
"../share/bdsim/gdml/schema/gdml.xsd";
114 if (FILE *file = fopen(localPath.c_str(),
"r"))
119 else if ( (file = fopen(installPath.c_str(),
"r")) )
127 G4String libraryInstallPath = bdsimLibraryPath +
"../share/bdsim/gdml/schema/gdml.xsd";
128 if ( (file = fopen(libraryInstallPath.c_str(),
"r")) )
131 return libraryInstallPath;
134 {
throw BDSException(__METHOD_NAME__,
"ERROR: local GDML schema could not be found!");}
138BDSGDMLPreprocessor::BDSGDMLPreprocessor()
144BDSGDMLPreprocessor::~BDSGDMLPreprocessor()
148 const G4String& prefix,
149 G4bool preprocessSchema)
151 G4cout << __METHOD_NAME__ <<
"Preprocessing GDML file " << file << G4endl;
154 {XMLPlatformUtils::Initialize();}
155 catch (
const XMLException& toCatch)
157 char* message = XMLString::transcode(toCatch.getMessage());
158 std::stringstream messageSS;
159 messageSS <<
"Error during initialization! :\n" << message <<
"\n";
160 XMLString::release(&message);
168 XercesDOMParser* parser =
new XercesDOMParser();
169 parser->setValidationScheme(XercesDOMParser::Val_Always);
170 parser->setDoNamespaces(
true);
172 ErrorHandler* errHandler = (ErrorHandler*)
new HandlerBase();
173 parser->setErrorHandler(errHandler);
176 {parser->parse(file.c_str());}
177 catch (
const XMLException& toCatch)
179 char* message = XMLString::transcode(toCatch.getMessage());
180 std::stringstream messageSS;
181 messageSS <<
"Exception message is: \n" << message <<
"\n";
182 XMLString::release(&message);
185 catch (
const DOMException& toCatch)
187 char* message = XMLString::transcode(toCatch.msg);
188 std::stringstream messageSS;
189 messageSS <<
"Exception message is: \n" << message <<
"\n";
190 XMLString::release(&message);
194 {
throw BDSException(__METHOD_NAME__,
"Unexpected Exception - possibly malformed GDML file: " + filename);}
197 DOMDocument* doc = parser->getDocument();
198 DOMElement* docRootNode = doc->getDocumentElement();
199 DOMNodeIterator* docWalker = doc->createNodeIterator(docRootNode, DOMNodeFilter::SHOW_ELEMENT,
nullptr,
true);
201 ReadDoc(docWalker, preprocessSchema);
205 docWalker = doc->createNodeIterator(docRootNode, DOMNodeFilter::SHOW_ELEMENT,
nullptr,
true);
208 ProcessDoc(docWalker, prefix);
214 DOMImplementation* pImplement = DOMImplementationRegistry::getDOMImplementation(XMLString::transcode(
"LS"));
215 DOMLSSerializer* pSerializer = (
static_cast<DOMImplementationLS*
>(pImplement))->createLSSerializer();
216 DOMConfiguration* pDomConfiguration = pSerializer->getDomConfig();
217 pDomConfiguration->setParameter(XMLUni::fgDOMWRTFormatPrettyPrint,
true);
218 XMLFormatTarget* pTarget =
new LocalFileFormatTarget(newFile);
219 DOMLSOutput* pDomLsOutput = (
static_cast<DOMImplementationLS*
>(pImplement))->createLSOutput();
220 pDomLsOutput->setByteStream(pTarget);
221 pSerializer->write(doc, pDomLsOutput);
222 pSerializer->release();
224 G4cout << __METHOD_NAME__ <<
"Preprocessing complete" << G4endl;
233void BDSGDMLPreprocessor::ReadDoc(DOMNodeIterator* docIterator,
234 G4bool processSchema)
236 for (DOMNode* currentNode = docIterator->nextNode(); currentNode != 0; currentNode = docIterator->nextNode())
237 {ReadNode(currentNode, processSchema);}
240void BDSGDMLPreprocessor::ReadNode(DOMNode* node,
241 G4bool processSchema)
246 std::string thisNodeName = XMLString::transcode(node->getNodeName());
247 if (thisNodeName ==
"gdml" && processSchema)
249 ProcessGDMLNode(node->getAttributes());
256 {ReadAttributes(node->getAttributes());}
259void BDSGDMLPreprocessor::ProcessGDMLNode(DOMNamedNodeMap* attributeMap)
264 for (XMLSize_t i = 0; i < attributeMap->getLength(); i++)
266 DOMNode* attr = attributeMap->item(i);
267 std::string nodeName = XMLString::transcode(attr->getNodeName());
268 if (nodeName ==
"xsi:noNamespaceSchemaLocation")
270 G4String nodeValue = G4String(XMLString::transcode(attr->getNodeValue()));
271 G4String newNodeValue;
272 if (nodeValue.substr(0,2) ==
"./")
274 G4String remainder = nodeValue.substr(2);
275#if G4VERSION_NUMBER > 1099
278 newNodeValue = remainder.prepend(
parentDir);
283 attr->setNodeValue(XMLString::transcode(newNodeValue.c_str()));
288void BDSGDMLPreprocessor::ReadAttributes(DOMNamedNodeMap* attributeMap)
293 for (XMLSize_t i = 0; i < attributeMap->getLength(); i++)
295 DOMNode* attr = attributeMap->item(i);
296 std::string name = XMLString::transcode(attr->getNodeValue());
300 if (XMLString::compareIString(attr->getNodeName(), XMLString::transcode(
"name")) == 0)
302 names.push_back(name);
308void BDSGDMLPreprocessor::ProcessDoc(DOMNodeIterator* docIterator,
309 const G4String& prefix)
311 for (DOMNode* currentNode = docIterator->nextNode(); currentNode != 0; currentNode = docIterator->nextNode())
312 {ProcessNode(currentNode, prefix);}
315void BDSGDMLPreprocessor::ProcessNode(DOMNode* node,
316 const G4String& prefix)
321 std::string thisNodeName = XMLString::transcode(node->getNodeName());
325 else if (thisNodeName ==
"property")
327 ProcessAttributes(node->getAttributes(), prefix,
true);
330 {ProcessAttributes(node->getAttributes(), prefix);}
334 const G4String& prefix)
335{
return prefix +
"_" + nodeName;}
337void BDSGDMLPreprocessor::ProcessAttributes(DOMNamedNodeMap* attributeMap,
338 const G4String& prefix,
344 for (XMLSize_t i = 0; i < attributeMap->getLength(); i++)
346 DOMNode* attr = attributeMap->item(i);
347 std::string name = XMLString::transcode(attr->getNodeValue());
355 if (XMLString::compareIString(attr->getNodeName(),
356 XMLString::transcode(
"name")) == 0 && property)
359 if (XMLString::compareIString(attr->getNodeName(),
360 XMLString::transcode(
"name")) == 0)
363 attr->setNodeValue(XMLString::transcode(newName.c_str()));
367 std::string expression = XMLString::transcode(attr->getNodeValue());
369 for (
const auto& defined_name :
names)
373 std::regex whole_name(std::string(
"\\b") + defined_name +
"\\b");
374 expression = std::regex_replace(expression, whole_name, prefix +
"_$&");
376 attr->setNodeValue(XMLString::transcode((expression).c_str()));
383void _SymbolToPreventWarningGDML(){;}
General exception with possible name of object and message.
Process a GDML file to allow multiple file loading.
static G4String ProcessedNodeName(const G4String &nodeName, const G4String &prefix)
std::vector< std::string > ignoreNodes
Nodes to ignore.
G4String PreprocessFile(const G4String &file, const G4String &prefix, G4bool preprocessSchema=true)
std::vector< std::string > names
Names to replace.
std::map< std::string, int > count
Debugging.
std::vector< std::string > ignoreAttrs
Attributes to ignore.
G4String parentDir
Directory of main gdml file.
static BDSTemporaryFiles * Instance()
Singleton accessor.
G4String CreateTemporaryFile(const G4String &originalFilePath, G4String fileNamePrefix="", G4String fileNameSuffix="")
G4bool EndsWith(const std::string &expression, const std::string &suffix)
Return true if a string "expression" ends with "suffix".
G4String GDMLSchemaLocation()
Get GDML Schema location included with BDSIM.
std::string GetBDSIMLibraryPath()
Returns the path from which the BDSIM library is loaded.
void SplitPathAndFileName(const G4String &filePath, G4String &path, G4String &filename)
std::string GetBDSIMExecPath()