21#include "BDSException.hh"
22#include "BDSGDMLPreprocessor.hh"
23#include "BDSTemporaryFiles.hh"
24#include "BDSUtilities.hh"
26#include <xercesc/dom/DOM.hpp>
27#include <xercesc/framework/LocalFileFormatTarget.hpp>
28#include <xercesc/framework/StdOutFormatTarget.hpp>
29#include <xercesc/parsers/XercesDOMParser.hpp>
30#include <xercesc/sax/HandlerBase.hpp>
31#include <xercesc/util/PlatformUtils.hpp>
32#include <xercesc/util/XMLString.hpp>
36#include "G4Version.hh"
48using namespace xercesc;
50G4String BDS::PreprocessGDML(
const G4String& file,
51 const G4String& prefix,
52 G4bool preprocessSchema)
55 {
throw BDSException(__METHOD_NAME__,
"trying to read a GMAD file (\"" + file +
"\") as a GDML file - check file or change extension.");}
63G4String BDS::PreprocessGDMLSchemaOnly(
const G4String& file)
67 {
throw BDSException(__METHOD_NAME__,
"trying to read a GMAD file (\"" + file +
"\") as a GDML file - check file or change extension.");}
68 std::ifstream inputFile;
69 inputFile.open(file.c_str());
70 if (!inputFile.is_open())
71 {
throw BDSException(__METHOD_NAME__,
"Invalid file \"" + file +
"\"");}
73 {G4cout << __METHOD_NAME__ <<
"updating GDML Schema to local copy for file:\n \"" << file <<
"\"" << G4endl;}
78 std::ofstream outFile;
79 outFile.open(newFile);
83 std::regex gdmlTag(
"\\<gdml");
85 while (std::getline(inputFile, line))
89 if (std::regex_search(line, gdmlTag))
91 std::regex schema(
"xsi:noNamespaceSchemaLocation=\"(\\S+)\"");
93 std::string prefix =
"xsi:noNamespaceSchemaLocation=\"";
94 std::regex_replace(std::back_inserter(newLine), line.begin(), line.end(), schema, prefix+localSchema+
"\"$2");
113 G4String localPath = bdsimExecPath +
"src-external/gdml/schema/gdml.xsd";
114 G4String installPath = bdsimExecPath +
"../share/bdsim/gdml/schema/gdml.xsd";
115 if (FILE *file = fopen(localPath.c_str(),
"r"))
120 else if ( (file = fopen(installPath.c_str(),
"r")) )
126 {
throw BDSException(__METHOD_NAME__,
"ERROR: local GDML schema could not be found!");}
129BDSGDMLPreprocessor::BDSGDMLPreprocessor()
135BDSGDMLPreprocessor::~BDSGDMLPreprocessor()
139 const G4String& prefix,
140 G4bool preprocessSchema)
142 G4cout << __METHOD_NAME__ <<
"Preprocessing GDML file " << file << G4endl;
145 {XMLPlatformUtils::Initialize();}
146 catch (
const XMLException& toCatch)
148 char* message = XMLString::transcode(toCatch.getMessage());
149 std::stringstream messageSS;
150 messageSS <<
"Error during initialization! :\n" << message <<
"\n";
151 XMLString::release(&message);
159 XercesDOMParser* parser =
new XercesDOMParser();
160 parser->setValidationScheme(XercesDOMParser::Val_Always);
161 parser->setDoNamespaces(
true);
163 ErrorHandler* errHandler = (ErrorHandler*)
new HandlerBase();
164 parser->setErrorHandler(errHandler);
167 {parser->parse(file.c_str());}
168 catch (
const XMLException& toCatch)
170 char* message = XMLString::transcode(toCatch.getMessage());
171 std::stringstream messageSS;
172 messageSS <<
"Exception message is: \n" << message <<
"\n";
173 XMLString::release(&message);
176 catch (
const DOMException& toCatch)
178 char* message = XMLString::transcode(toCatch.msg);
179 std::stringstream messageSS;
180 messageSS <<
"Exception message is: \n" << message <<
"\n";
181 XMLString::release(&message);
185 {
throw BDSException(__METHOD_NAME__,
"Unexpected Exception - possibly malformed GDML file: " + filename);}
188 DOMDocument* doc = parser->getDocument();
189 DOMElement* docRootNode = doc->getDocumentElement();
190 DOMNodeIterator* docWalker = doc->createNodeIterator(docRootNode, DOMNodeFilter::SHOW_ELEMENT,
nullptr,
true);
192 ReadDoc(docWalker, preprocessSchema);
196 docWalker = doc->createNodeIterator(docRootNode, DOMNodeFilter::SHOW_ELEMENT,
nullptr,
true);
199 ProcessDoc(docWalker, prefix);
205 DOMImplementation* pImplement = DOMImplementationRegistry::getDOMImplementation(XMLString::transcode(
"LS"));
206 DOMLSSerializer* pSerializer = (
static_cast<DOMImplementationLS*
>(pImplement))->createLSSerializer();
207 DOMConfiguration* pDomConfiguration = pSerializer->getDomConfig();
208 pDomConfiguration->setParameter(XMLUni::fgDOMWRTFormatPrettyPrint,
true);
209 XMLFormatTarget* pTarget =
new LocalFileFormatTarget(newFile);
210 DOMLSOutput* pDomLsOutput = (
static_cast<DOMImplementationLS*
>(pImplement))->createLSOutput();
211 pDomLsOutput->setByteStream(pTarget);
212 pSerializer->write(doc, pDomLsOutput);
213 pSerializer->release();
215 G4cout << __METHOD_NAME__ <<
"Preprocessing complete" << G4endl;
224void BDSGDMLPreprocessor::ReadDoc(DOMNodeIterator* docIterator,
225 G4bool processSchema)
227 for (DOMNode* currentNode = docIterator->nextNode(); currentNode != 0; currentNode = docIterator->nextNode())
228 {ReadNode(currentNode, processSchema);}
231void BDSGDMLPreprocessor::ReadNode(DOMNode* node,
232 G4bool processSchema)
237 std::string thisNodeName = XMLString::transcode(node->getNodeName());
238 if (thisNodeName ==
"gdml" && processSchema)
240 ProcessGDMLNode(node->getAttributes());
247 {ReadAttributes(node->getAttributes());}
250void BDSGDMLPreprocessor::ProcessGDMLNode(DOMNamedNodeMap* attributeMap)
255 for (XMLSize_t i = 0; i < attributeMap->getLength(); i++)
257 DOMNode* attr = attributeMap->item(i);
258 std::string nodeName = XMLString::transcode(attr->getNodeName());
259 if (nodeName ==
"xsi:noNamespaceSchemaLocation")
261 G4String nodeValue = G4String(XMLString::transcode(attr->getNodeValue()));
262 G4String newNodeValue;
263 if (nodeValue.substr(0,2) ==
"./")
265 G4String remainder = nodeValue.substr(2);
266#if G4VERSION_NUMBER > 1099
269 newNodeValue = remainder.prepend(
parentDir);
274 attr->setNodeValue(XMLString::transcode(newNodeValue.c_str()));
279void BDSGDMLPreprocessor::ReadAttributes(DOMNamedNodeMap* attributeMap)
284 for (XMLSize_t i = 0; i < attributeMap->getLength(); i++)
286 DOMNode* attr = attributeMap->item(i);
287 std::string name = XMLString::transcode(attr->getNodeValue());
291 if (XMLString::compareIString(attr->getNodeName(), XMLString::transcode(
"name")) == 0)
293 names.push_back(name);
299void BDSGDMLPreprocessor::ProcessDoc(DOMNodeIterator* docIterator,
300 const G4String& prefix)
302 for (DOMNode* currentNode = docIterator->nextNode(); currentNode != 0; currentNode = docIterator->nextNode())
303 {ProcessNode(currentNode, prefix);}
306void BDSGDMLPreprocessor::ProcessNode(DOMNode* node,
307 const G4String& prefix)
312 std::string thisNodeName = XMLString::transcode(node->getNodeName());
317 {ProcessAttributes(node->getAttributes(), prefix);}
321 const G4String& prefix)
322{
return prefix +
"_" + nodeName;}
324void BDSGDMLPreprocessor::ProcessAttributes(DOMNamedNodeMap* attributeMap,
325 const G4String& prefix)
330 for (XMLSize_t i = 0; i < attributeMap->getLength(); i++)
332 DOMNode* attr = attributeMap->item(i);
333 std::string name = XMLString::transcode(attr->getNodeValue());
339 if (XMLString::compareIString(attr->getNodeName(),
340 XMLString::transcode(
"name")) == 0)
343 attr->setNodeValue(XMLString::transcode(newName.c_str()));
347 std::string expression = XMLString::transcode(attr->getNodeValue());
349 for (
const auto& defined_name :
names)
353 std::regex whole_name(std::string(
"\\b") + defined_name +
"\\b");
354 expression = std::regex_replace(expression, whole_name, prefix +
"_$&");
356 attr->setNodeValue(XMLString::transcode((expression).c_str()));
363void _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.
void SplitPathAndFileName(const G4String &filePath, G4String &path, G4String &filename)
std::string GetBDSIMExecPath()