tdaq-develop-2025-02-12
XmlDocument.cc
1 #include "otsdaq/XmlUtilities/XmlDocument.h"
2 #include "otsdaq/Macros/CoutMacros.h"
3 #include "otsdaq/Macros/MessageTools.h"
4 #include "otsdaq/Macros/StringMacros.h"
5 #include "otsdaq/MessageFacility/MessageFacility.h"
6 #include "otsdaq/XmlUtilities/ConvertFromXML.h"
7 #include "otsdaq/XmlUtilities/ConvertToXML.h"
8 
9 #include <stdexcept>
10 #include <xercesc/dom/DOM.hpp>
11 #include <xercesc/dom/DOMDocument.hpp>
12 #include <xercesc/dom/DOMDocumentType.hpp>
13 #include <xercesc/dom/DOMElement.hpp>
14 #include <xercesc/dom/DOMImplementation.hpp>
15 #include <xercesc/dom/DOMImplementationLS.hpp>
16 #include <xercesc/dom/DOMImplementationRegistry.hpp>
17 #include <xercesc/parsers/XercesDOMParser.hpp>
18 // #include <xercesc/dom/DOMLSSerializer.hpp>
19 // #include <xercesc/dom/DOMLSOutput.hpp>
20 #include <xercesc/dom/DOMNodeIterator.hpp>
21 #include <xercesc/dom/DOMNodeList.hpp>
22 #include <xercesc/dom/DOMText.hpp>
23 #include <xercesc/validators/common/Grammar.hpp>
24 
25 #include <xercesc/parsers/XercesDOMParser.hpp>
26 #include <xercesc/util/XMLUni.hpp>
27 #include <xercesc/util/XercesDefs.hpp>
28 
29 #include <xercesc/framework/LocalFileFormatTarget.hpp>
30 #include <xercesc/util/OutOfMemoryException.hpp>
31 
32 #include <boost/regex.hpp>
33 
34 #include <iostream>
35 #include <list>
36 #include <sstream>
37 
38 #include <errno.h>
39 #include <sys/stat.h>
40 #include <sys/types.h>
41 #include <unistd.h>
42 
43 using namespace ots;
44 
45 //==============================================================================
46 XmlDocument::XmlDocument(const std::string& rootName) : rootTagName_(rootName)
47 {
48  //__COUT__ << "in" << std::endl;
49  initDocument();
50 
51  rootElement_ = theDocument_->getDocumentElement();
52  //__COUT__ << "out" << std::endl;
53 }
54 
55 //==============================================================================
56 XmlDocument::XmlDocument(const XmlDocument& doc) : rootTagName_(doc.rootTagName_)
57 {
58  //__COUT__ << "in" << std::endl;
59  *this = doc;
60  //__COUT__ << "out" << std::endl;
61 }
62 
63 //==============================================================================
64 XmlDocument& XmlDocument::operator=(const XmlDocument& doc)
65 {
66  __COUT__ << "in" << std::endl;
67  initDocument();
68  rootElement_ = theDocument_->getDocumentElement();
69  recursiveElementCopy(doc.rootElement_, rootElement_);
70  __COUT__ << "out" << std::endl;
71  return *this;
72 }
73 
74 //==============================================================================
75 XmlDocument::~XmlDocument(void)
76 {
77  //__COUT__ << "Xml Destructor" << std::endl;
78  terminatePlatform();
79 }
80 
81 //==============================================================================
82 void XmlDocument::initDocument(void)
83 {
84  initPlatform();
85 
86  theImplementation_ =
87  xercesc::DOMImplementationRegistry::getDOMImplementation(CONVERT_TO_XML("Core"));
88 
89  if(theImplementation_)
90  {
91  try
92  {
93  theDocument_ = theImplementation_->createDocument(
94  CONVERT_TO_XML("http://www.w3.org/2001/XMLSchema-instance"), // root
95  // element
96  // namespace
97  // URI.
98  CONVERT_TO_XML(rootTagName_), // root element name
99  0); // theDocument_ type object (DTD).
100  }
101  catch(const xercesc::OutOfMemoryException&)
102  {
103  __SS__ << "OutOfMemoryException" << __E__;
104  __SS_THROW__;
105  }
106  catch(const xercesc::DOMException& e)
107  {
108  __SS__ << "DOMException code is: " << e.code << __E__;
109  __SS_THROW__;
110  }
111  catch(const xercesc::XMLException& e)
112  {
113  __SS__ << "Error Message: " << XML_TO_CHAR(e.getMessage()) << __E__;
114  __SS_THROW__;
115  }
116  catch(...)
117  {
118  __SS__ << "An error occurred creating the theDocument_" << __E__;
119  try
120  {
121  throw;
122  } //one more try to printout extra info
123  catch(const std::exception& e)
124  {
125  ss << "Exception message: " << e.what();
126  }
127  catch(...)
128  {
129  }
130  __SS_THROW__;
131  }
132  }
133  else
134  {
135  __SS__ << "Requested theImplementation_ is not supported" << __E__;
136  __SS_THROW__;
137  }
138  darioXMLStyle_ = false;
139  isALeaf_[true] = "true";
140  isALeaf_[false] = "false";
141 }
142 
143 //==============================================================================
144 void XmlDocument::initPlatform(void)
145 {
146  try
147  {
148  xercesc::XMLPlatformUtils::Initialize(); // Initialize Xerces infrastructure
149  //__COUT__ << "Initialized new
150  // theDocument_" << std::endl;
151  }
152  catch(xercesc::XMLException& e)
153  {
154  __COUT__ << "XML toolkit initialization error: " << XML_TO_CHAR(e.getMessage())
155  << std::endl;
156  }
157 }
158 
159 //==============================================================================
160 void XmlDocument::terminatePlatform(void)
161 {
162  try
163  {
164  //__COUT__ << "Releasing the document" << std::endl;
165  theDocument_->release();
166  //__COUT__ << "document released" << std::endl;
167  }
168  catch(...)
169  {
170  XERCES_STD_QUALIFIER cerr << "An error occurred destroying the theDocument_"
171  << XERCES_STD_QUALIFIER endl;
172  }
173 
174  try
175  {
176  xercesc::XMLPlatformUtils::Terminate(); // Terminate after release of memory
177  }
178  catch(xercesc::XMLException& e)
179  {
180  __COUT__ << "XML toolkit teardown error: " << XML_TO_CHAR(e.getMessage())
181  << std::endl;
182  // XMLString::release(&message);
183  }
184 }
185 
186 //==============================================================================
190 xercesc::DOMElement* XmlDocument::addTextElementToParent(const std::string& childName,
191  const std::string& childText,
192  xercesc::DOMElement* parent)
193 {
194  if(parent == 0)
195  {
196  __SS__ << "Illegal Null Parent Pointer!" << __E__;
197  __SS_THROW__;
198  // return 0;
199  }
200  xercesc::DOMElement* child = nullptr;
201  try
202  {
203  child = theDocument_->createElement(CONVERT_TO_XML(childName));
204  }
205  catch(xercesc::DOMException& e)
206  {
207  __COUT__ << "Can't use the name: " << childName
208  << " to create the child element because the exception says: "
209  << XML_TO_CHAR(e.getMessage())
210  << ". Very likely you have a name that starts with a number and that's "
211  "not allowed!"
212  << std::endl;
213  }
214  parent->appendChild(child);
215 
216  try
217  {
218  child->appendChild(theDocument_->createTextNode(CONVERT_TO_XML(childText)));
219  }
220  catch(...) // sometimes see TranscodingException
221  {
222  __COUT__ << StringMacros::stackTrace() << std::endl;
223  __COUT_ERR__ << "Error caught attempting to create a text node for this text: "
224  << childText << ". Converting instead to 'Illegal text..'"
225  << std::endl;
226  child->appendChild(theDocument_->createTextNode(
227  CONVERT_TO_XML("Illegal text content blocked.")));
228  }
229 
230  return child;
231 }
232 
233 //==============================================================================
237 xercesc::DOMElement* XmlDocument::addTextElementToParent(const std::string& childName,
238  const std::string& childText,
239  const std::string& parentName,
240  unsigned int parentIndex)
241 {
242  xercesc::DOMNodeList* nodeList =
243  theDocument_->getElementsByTagName(CONVERT_TO_XML(parentName));
244 
245  if(parentIndex >= nodeList->getLength())
246  {
247  __COUT__ << "WARNING: Illegal parent index attempted in tags with name: "
248  << parentName << ", index: " << parentIndex << std::endl;
249  return 0; // illegal index attempted
250  }
251 
252  return addTextElementToParent(
253  childName, childText, (xercesc::DOMElement*)(nodeList->item(parentIndex)));
254 }
255 
256 //==============================================================================
257 void XmlDocument::copyDocument(const xercesc::DOMDocument* toCopy,
258  xercesc::DOMDocument* copy)
259 {
260  recursiveElementCopy(toCopy->getDocumentElement(), copy->getDocumentElement());
261 }
262 
263 //==============================================================================
264 void XmlDocument::recursiveElementCopy(const xercesc::DOMElement* toCopy,
265  xercesc::DOMElement* copy)
266 {
267  xercesc::DOMNodeList* nodeListToCopy =
268  toCopy->getChildNodes(); // get all children of the list to copy
269  xercesc::DOMNode* iNode;
270  xercesc::DOMDocument* copyDocument = copy->getOwnerDocument();
271  for(unsigned int i = 0; i < nodeListToCopy->getLength(); i++)
272  {
273  iNode = nodeListToCopy->item(i);
274  xercesc::DOMElement* child = copyDocument->createElement(iNode->getNodeName());
275  copy->appendChild(child);
276  if(child->getFirstChild() != NULL)
277  {
278  if(iNode->getFirstChild() != 0 &&
279  iNode->getFirstChild()->getNodeType() ==
280  xercesc::DOMNode::TEXT_NODE) // if has a text node first, insert as
281  // value attribute
282  {
283  child->appendChild(
284  copyDocument->createTextNode(child->getFirstChild()->getNodeValue()));
285  }
286  recursiveElementCopy((xercesc::DOMElement*)(iNode), child);
287  }
288  }
289 }
290 
291 //==============================================================================
298 /*
299 unsigned int XmlDocument::addElementToParent(std::string field, std::string value,
300 xercesc::DOMElement *parentEl, bool verbose)
301 {
302  DOMNodeList *nodeList = parentEl->getChildNodes(); //get all children
303 
304  if(verbose)
305  {
306  //display parent info
307  //__COUT__ << "Parent Name: " << XML_TO_CHAR(parentEl->getNodeName()) << " Field:
308 " << field << " Value: " << value << std::endl; if( parentEl->getFirstChild() != NULL &&
309 parentEl->getFirstChild()->getNodeType() == DOMNode::TEXT_NODE)
310  __COUT__ << "Parent's First Child Node Value: " <<
311 XML_TO_CHAR(parentEl->getFirstChild()->getNodeValue()) << std::endl;
312  }
313 
314  //add field/value element
315  DOMElement *newEl = theDocument_->createElement(CONVERT_TO_XML(field));
316  parentEl->appendChild(newEl);
317 
318  DOMText* valueStr = theDocument_->createTextNode(CONVERT_TO_XML(value));
319  newEl->appendChild(valueStr);
320 
321  if( parentEl->getFirstChild() != NULL && parentEl->getFirstChild()->getNodeType() ==
322 DOMNode::TEXT_NODE) return nodeList->getLength() - 2; //return child index among parent's
323 children, not counting first child text node return nodeList->getLength() - 1; //return
324 child index among parent's children
325 }
326 */
327 //==============================================================================
335 /*
336 unsigned int XmlDocument::addDataElement ( std::string field, std::string value,
337 std::string parentName, unsigned int parentNameIndex)
338 {
339  DOMNodeList *nodeList =
340 theDocument_->getElementsByTagName(CONVERT_TO_XML(parentName));
341 
342  if(parentNameIndex >= nodeList->getLength()) {
343  __COUT__ << "illegal parent index attempted in tags with name: " << parentName <<
344 ", index: " << parentNameIndex << std::endl; return -1; //illegal index attempted
345  }
346 
347  return addElementToParent(field,value,(DOMElement*)(nodeList->item(parentNameIndex)));
348 }
349 */
350 //==============================================================================
360 /*
361 unsigned int XmlDocument::addDataElement ( std::string field, std::string value, unsigned
362 int *parentIndexArray, unsigned int parentIndexArraySize)
363 {
364 
365  //__COUT__ << "field: " << field << ", value: " << value << ", parent: " <<
366 parentIndexArraySize << std::endl;
367 
368  DOMElement *parentEl = dataElement; // initialize parent to <DATA>
369 
370  if(parentIndexArray) //if there passed an array find parent relative to data element
371  {
372  //__COUT__ << "Using Parent Index Array" << std::endl;
373 
374  DOMNodeList *nodeList;
375 
376  //iterate through nested parents based on parentIndexArray
377  unsigned int tmpi,cntNotTxt;
378  for(unsigned int i=0;i<parentIndexArraySize;++i)
379  {
380  nodeList = parentEl->getChildNodes(); //get all children
381  cntNotTxt = 0;
382 
383  //get cntNotTxt to proper non text node
384  for(tmpi=0;tmpi<nodeList->getLength();++tmpi)
385  {
386  if(((DOMElement*)(nodeList->item(tmpi)))->getNodeType() ==
387 DOMNode::TEXT_NODE) continue; //skip text nodes
388 
389  if(cntNotTxt == parentIndexArray[i]) break; //at proper parent node!
390  ++cntNotTxt; //else look for next
391  }
392 
393  //in theory, only first child can be text - ignore text node children
394  //if(parentEl->getFirstChild() != NULL &&
395 parentEl->getFirstChild()->getNodeType() == DOMNode::TEXT_NODE) ++tmpi;
396 
397  if(tmpi >= nodeList->getLength()) {
398  __COUT__ << "illegal child index attempted in nested parents: " <<
399 parentIndexArray[i] << ", depth: " << i << ", tmpi: " << tmpi << std::endl; return -1;
401  }
402 
403  parentEl = (DOMElement*)(nodeList->item(tmpi));
404  }
405  }
406 
407  return addElementToParent(field,value,parentEl);
408 }
409 */
410 //==============================================================================
415 /*
416 unsigned int XmlDocument::addXmlData (XmlDocument *xmldoc)
417 {
418  //
419 
420  int retIndex = dataElement->getChildNodes()->getLength(); //will be index of first
421 appended data element
422 
423  //add all first level child elements of data and recurse on them
424  DOMNodeList *nodeList = xmldoc->dataElement->getChildNodes(); //get all children
425 within data for(unsigned int i = 0; i<nodeList->getLength();++i)
426  {
427  if(nodeList->item(i)->getNodeType() == DOMNode::TEXT_NODE) //ignore text node
428 children continue;
429 
430  recursiveAddElementToParent((DOMElement*)(nodeList->item(i)),dataElement);
431  }
432 
433  return retIndex;
434 }
435 */
436 //==============================================================================
439 /*
440 void XmlDocument::recursiveAddElementToParent (DOMElement *currEl, DOMElement *parentEl)
441 {
442 std::string field, value = "";
443 
444  //char *tmpField =
445  field = XML_TO_CHAR(currEl->getNodeName());//XML_TO_CHAR(currEl->getNodeName());
446  //field = tmpField;
447  //XMLString::release( &tmpField );
448 
449  if( currEl->getFirstChild() != NULL && currEl->getFirstChild()->getNodeType() ==
450 DOMNode::TEXT_NODE) //if has a text node first, insert as value attribute value =
451 StringMacros::escapeString(XML_TO_CHAR(currEl->getFirstChild()->getNodeValue()));
452 
453  //insert currEl
454  addElementToParent(field,value,parentEl);
455 
456  //insert rest of currEl tree
457  DOMNodeList *nodeList = currEl->getChildNodes(); //get all children of currEl
458  for(unsigned int i = 0; i<nodeList->getLength();++i)
459  {
460  if(nodeList->item(i)->getNodeType() == DOMNode::TEXT_NODE) //ignore text node
461 children continue;
462 
463  recursiveAddElementToParent((DOMElement*)(nodeList->item(i)),currEl);
464  }
465 }
466 */
467 //==============================================================================
471 void XmlDocument::outputXmlDocument(std::ostringstream* out, bool dispStdOut)
472 {
473  recursiveOutputXmlDocument(theDocument_->getDocumentElement(), out, dispStdOut);
474 }
475 
476 //==============================================================================
477 void XmlDocument::setDocument(xercesc::DOMDocument* doc) { theDocument_ = doc; }
478 //==============================================================================
481 void XmlDocument::recursiveOutputXmlDocument(xercesc::DOMElement* currEl,
482  std::ostringstream* out,
483  bool dispStdOut,
484  const std::string& tabStr)
485 {
486  // open field tag
487  if(dispStdOut)
488  {
489  __COUT__ << tabStr << "<" << XML_TO_CHAR(currEl->getNodeName());
490  }
491  if(out)
492  {
493  *out << tabStr << "<" << XML_TO_CHAR(currEl->getNodeName());
494  }
495 
496  // insert value if text node child
497  if(currEl->getFirstChild() != NULL &&
498  currEl->getFirstChild()->getNodeType() ==
499  xercesc::DOMNode::TEXT_NODE) // if has a text node first, insert as value
500  // attribute
501  {
502  if(dispStdOut)
503  std::cout << " value='"
504  << (XML_TO_CHAR(currEl->getFirstChild()->getNodeValue())) << "'";
505  if(out)
506  *out << " value='" << (XML_TO_CHAR(currEl->getFirstChild()->getNodeValue()))
507  << "'";
508  }
509 
510  xercesc::DOMNodeList* nodeList = currEl->getChildNodes(); // get all children
511 
512  // close opening field tag
513  if(dispStdOut)
514  std::cout << ((nodeList->getLength() == 0 ||
515  (nodeList->getLength() == 1 &&
516  currEl->getFirstChild()->getNodeType() ==
517  xercesc::DOMNode::TEXT_NODE))
518  ? "/"
519  : "")
520  << ">" << std::endl;
521  if(out)
522  *out << ((nodeList->getLength() == 0 ||
523  (nodeList->getLength() == 1 &&
524  currEl->getFirstChild()->getNodeType() == xercesc::DOMNode::TEXT_NODE))
525  ? "/"
526  : "")
527  << ">" << std::endl;
528 
529  // insert children
530  std::string newTabStr = tabStr + "\t";
531  for(unsigned int i = 0; i < nodeList->getLength(); ++i)
532  if(nodeList->item(i)->getNodeType() !=
533  xercesc::DOMNode::TEXT_NODE) // ignore text node children
535  (xercesc::DOMElement*)(nodeList->item(i)), out, dispStdOut, newTabStr);
536 
537  // close tag if children
538  if(nodeList->getLength() > 1 ||
539  (nodeList->getLength() == 1 &&
540  currEl->getFirstChild()->getNodeType() != xercesc::DOMNode::TEXT_NODE))
541  {
542  if(dispStdOut)
543  __COUT__ << tabStr << "</" << XML_TO_CHAR(currEl->getNodeName()) << ">"
544  << std::endl;
545  if(out)
546  *out << tabStr << "</" << XML_TO_CHAR(currEl->getNodeName()) << ">"
547  << std::endl;
548  }
549 }
550 
551 //==============================================================================
555 /*
556 std::string XmlDocument::getDataElement (const std::string field, const unsigned int
557 occurance)
558 {
559  unsigned int count = 0;
560  return recursiveFindElement(theDocument_->getDocumentElement(),field,occurance,count);
561 }
562 */
563 //==============================================================================
566 /*
567 std::string XmlDocument::recursiveFindElement (DOMElement *currEl, const std::string
568 field, const unsigned int occurance, unsigned int &count)
569 {
570  if (XML_TO_CHAR(currEl->getNodeName()) == field && occurance == count++) //found,
571 done!!
572  {
573  if( currEl->getFirstChild() != NULL && currEl->getFirstChild()->getNodeType() ==
574 DOMNode::TEXT_NODE) //if has a text node first, return as value attribute return
575 StringMacros::escapeString(XML_TO_CHAR(currEl->getFirstChild()->getNodeValue())); else return "";
577  }
578 
579  std::string retStr;
580  //look through children recursively
581  DOMNodeList *nodeList = currEl->getChildNodes(); //get all children
582  for(unsigned int i = 0; i<nodeList->getLength();++i)
583  if(nodeList->item(i)->getNodeType() != DOMNode::TEXT_NODE) //ignore text node
584 children
585  {
586  retStr = recursiveFindElement
587 ((DOMElement*)(nodeList->item(i)),field,occurance,count); if(retStr != "") return retStr;
589  //else continue search within children recursively
590  }
591  return ""; //nothing found
592 }
593 */
594 //==============================================================================
598 /*
599 std::vector<std::string> XmlDocument::getAllDataElements (std::string field)
600 {
601  vector<string> retVec;
602 
603  recursiveFindAllElements(theDocument_->getDocumentElement(),field,&retVec);
604 
605  return retVec;
606 }
607 */
608 //==============================================================================
611 /*
612 void XmlDocument::recursiveFindAllElements (DOMElement *currEl, const std::string
613 field,std::vector<std::string> *retVec)
614 {
615  if (XML_TO_CHAR(currEl->getNodeName()) == field &&
616  currEl->getFirstChild() != NULL && currEl->getFirstChild()->getNodeType() ==
617 DOMNode::TEXT_NODE) //if has a text node first, return as value attribute
618  retVec->push_back(XML_TO_CHAR(currEl->getFirstChild()->getNodeValue()));
619 
620 
621  //look through children recursively
622  DOMNodeList *nodeList = currEl->getChildNodes(); //get all children
623  for(unsigned int i = 0; i<nodeList->getLength();++i)
624  if(nodeList->item(i)->getNodeType() != DOMNode::TEXT_NODE) //ignore text node
625 children recursiveFindAllElements ((DOMElement*)(nodeList->item(i)),field,retVec);
626 }
627 */
628 
629 //==============================================================================
632 void XmlDocument::recursiveRemoveChild(xercesc::DOMElement* childEl,
633  xercesc::DOMElement* parentEl)
634 {
635  // release child's children first
636  xercesc::DOMNodeList* nodeList =
637  childEl->getChildNodes(); // get all children within data
638  for(unsigned int i = 0; i < nodeList->getLength(); ++i)
640  (xercesc::DOMElement*)(nodeList->item(nodeList->getLength() - 1 - i)),
641  childEl);
642 
643  // then release child
644  parentEl->removeChild(childEl);
645  childEl->release();
646 }
647 
648 //==============================================================================
652 void XmlDocument::saveXmlDocument(const std::string& filePath)
653 {
654  __COUT__ << "Saving theDocument_ to file: " << filePath << std::endl;
655  // Return the first registered theImplementation_ that has the desired features. In
656  // this case, we are after a DOM theImplementation_ that has the LS feature... or
657  // Load/Save. DOMImplementation *theImplementation_ =
658  // DOMImplementationRegistry::getDOMImplementation(L"LS");
659  xercesc::DOMImplementation* saveImplementation =
660  xercesc::DOMImplementationRegistry::getDOMImplementation(CONVERT_TO_XML("LS"));
661 
662  //__COUT__ << "XERCES Version: " << _XERCES_VERSION << std::endl;
663 
664 #if _XERCES_VERSION >= 30000
665 
666  //__COUT__ << "making file" << filePath << std::endl;
667  // Create a DOMLSSerializer which is used to serialize a DOM tree into an XML
668  // theDocument_.
669  xercesc::DOMLSSerializer* serializer =
670  ((xercesc::DOMImplementationLS*)saveImplementation)->createLSSerializer();
671 
672  // Make the output more human readable by inserting line feeds.
673  if(serializer->getDomConfig()->canSetParameter(
674  xercesc::XMLUni::fgDOMWRTFormatPrettyPrint, true))
675  serializer->getDomConfig()->setParameter(
676  xercesc::XMLUni::fgDOMWRTFormatPrettyPrint, true);
677 
678  // The end-of-line sequence of characters to be used in the XML being written out.
679  serializer->setNewLine(CONVERT_TO_XML("\r\n"));
680 
681  // Convert the path into Xerces compatible XMLCh*.
682  // XMLCh *tempFilePath = const_cast<XMLCh*>(CONVERT_TO_XML(filePath));
683 
684  // Specify the target for the XML output.
685  xercesc::XMLFormatTarget* formatTarget;
686  try
687  {
688  // formatTarget = new xercesc::LocalFileFormatTarget(tempFilePath);
689  formatTarget = new xercesc::LocalFileFormatTarget(filePath.c_str());
690  }
691  catch(...)
692  {
693  __COUT__ << "Inaccessible file path: " << filePath << std::endl;
694  serializer->release();
695  // xercesc::XMLString::release(&tempFilePath);
696 
697  return;
698  }
699 
700  // Create a new empty output destination object.
701  xercesc::DOMLSOutput* output =
702  ((xercesc::DOMImplementationLS*)saveImplementation)->createLSOutput();
703 
704  // Set the stream to our target.
705  output->setByteStream(formatTarget);
706  // Write the serialized output to the destination.
707  serializer->write(theDocument_, output);
708  serializer->release();
709  // xercesc::XMLString::release(&tempFilePath);
710  delete formatTarget;
711 #else
712 
713  xercesc::DOMWriter* serializer =
714  ((xercesc::DOMImplementationLS*)saveImplementation)->createDOMWriter();
715  serializer->setFeature(xercesc::XMLUni::fgDOMWRTFormatPrettyPrint, true);
716 
717  /*
718  Choose a location for the serialized output. The 3 options are:
719  1) StdOutFormatTarget (std output stream - good for debugging)
720  2) MemBufFormatTarget (to Memory)
721  3) LocalFileFormatTarget (save to file)
722  (Note: You'll need a different header file for each one)
723  */
724  // XMLFormatTarget* pTarget = new StdOutFormatTarget();
725  // Convert the path into Xerces compatible XMLCh*.
726  XMLCh* tempFilePath = xercesc::XMLString::transcode(filePath.c_str());
727  xercesc::XMLFormatTarget* formatTarget;
728  try
729  {
730  formatTarget = new xercesc::LocalFileFormatTarget(tempFilePath);
731  }
732  catch(...)
733  {
734  __COUT__ << "Inaccessible file path: " << filePath << std::endl;
735  serializer->release();
736  xercesc::XMLString::release(&tempFilePath);
737  return;
738  }
739 
740  // Write the serialized output to the target.
741 
742  serializer->writeNode(formatTarget, *theDocument_);
743  serializer->release();
744  xercesc::XMLString::release(&tempFilePath);
745  delete formatTarget;
746 #endif
747 
748  // Cleanup.
749  //__COUT__ << "delete format target" << std::endl;
750 
751 #if _XERCES_VERSION >= 30000
752 
753  //__COUT__ << "delete output0" << std::endl;
754  output->release();
755  //__COUT__ << "delete output1" << std::endl;
756 
757 #endif
758 }
759 
760 //==============================================================================
761 bool XmlDocument::loadXmlDocument(const std::string& filePath)
762 {
763  __COUT__ << "Loading theDocument_ from file: " << filePath << std::endl;
764 
765  struct stat fileStatus;
766 
767  if(stat(filePath.c_str(), &fileStatus) != 0)
768  {
769  __COUT__ << "File not accessible." << std::endl;
770  return false;
771  }
772 
773  terminatePlatform();
774  initPlatform();
775 
776  xercesc::XercesDOMParser* parser = new xercesc::XercesDOMParser;
777  parser->setValidationScheme(xercesc::XercesDOMParser::Val_Auto);
778  parser->setDoNamespaces(true);
779  parser->setDoSchema(true);
780  parser->useCachedGrammarInParse(false);
781 
782  try
783  {
784  parser->parse(filePath.c_str());
785 
786  // theDocument_ memory object owned by the parent parser object
787  theDocument_ = parser->adoptDocument(); // instead of getDocument() so parser
788  // will not free theDocument_ when
789  // released
790 
791  // Get the top-level element: Name is "root". No attributes for "root"
792  rootElement_ = theDocument_->getDocumentElement();
793  if(!rootElement_)
794  throw(std::runtime_error("empty XML theDocument_"));
795  }
796  catch(xercesc::XMLException& e)
797  {
798  __COUT__ << "Error parsing file." << std::endl;
799  return false;
800  }
801  delete parser;
802 
803  return true;
804 }
805 // clang-format off
806 //============================================================================
807 void XmlDocument::setAnchors(const std::string& fSystemPath,
808  const std::string& fRootPath)
809 {
810  fSystemPath_ = fSystemPath;
811  fRootPath_ = fRootPath;
812 }
813 
814 //============================================================================
815 void XmlDocument::makeDirectoryBinaryTree(const std::string& fSystemPath,
816  const std::string& fRootPath,
817  int indent,
818  xercesc::DOMElement* anchorNode)
819 {
820  DIR* dir;
821  struct dirent* entry;
822 
823  std::string newFullPath = "";
824  char fchar = '.';
825  char schar = '.';
826 
827  fSystemPath_ = fSystemPath;
828  fRootPath_ = fRootPath;
829 
830  std::string fullPathName = fSystemPath_ +
831  std::string("/") +
832  fRootPath_ +
833  std::string("/") +
834  fFoldersPath_;
835 
836  if (!anchorNode) anchorNode = rootElement_;
837 
838  if (!(dir = opendir(fullPathName.c_str()))) return;
839 
840  while ((entry = readdir(dir)) != NULL)
841  {
842  std::string sName = std::string(entry->d_name);
843  fchar = sName.at(0);
844  if ( sName.size() == 2) schar = sName.at(1);
845  if (((sName.size() == 1) && fchar == '.') ||
846  ((sName.size() == 2) && schar == '.'))
847  {
848  continue; // do not consider . and .. pseudo-folders
849  }
850 
851  if (entry->d_type == DT_DIR)
852  {
853  fThisFolderPath_ = std::string(entry->d_name);
854  newFullPath = fSystemPath_ +
855  fRootPath +
856  std::string("/") +
857  fThisFolderPath_;
858  hierarchyPaths_.push_back(std::string(entry->d_name) + std::string(""));
859  fFoldersPath_ += hierarchyPaths_.back() + "/";
860  xercesc::DOMElement* node = this->populateBinaryTreeNode(
861  anchorNode,
862  std::string(entry->d_name),
863  indent,
864  false
865  );
866  this->makeDirectoryBinaryTree(fSystemPath, fRootPath, indent + 1, node);
867  if (hierarchyPaths_.size() > 0) hierarchyPaths_.pop_back();
868  if (hierarchyPaths_.size() > 0)
869  {
870  fFoldersPath_ = hierarchyPaths_.back() + "/";
871  }
872  else
873  {
874  fFoldersPath_ = "/";
875  }
876 
877  }
878  else
879  {
880  newFullPath = fSystemPath_ + std::string("/") + std::string(entry->d_name);
881  boost::smatch what;
882  boost::regex re{ ".*\\.root$" };
883  if (boost::regex_search(newFullPath, what, re))
884  {
885  fFileName_ = std::string(entry->d_name);
886  fFoldersPath_ = "" ;
887  for(unsigned int i=0; i<hierarchyPaths_.size(); ++i)
888  {
889  fFoldersPath_ += hierarchyPaths_[i] + std::string("/") ;
890  }
891  this->populateBinaryTreeNode(
892  anchorNode,
893  fFileName_,
894  indent,
895  true
896  );
897  }
898  }
899  }
900  closedir(dir);
901 }
902 
903 //==========================================================================================
904 xercesc::DOMElement* XmlDocument::populateBinaryTreeNode(xercesc::DOMElement* anchorNode,
905  const std::string& name,
906  int indent,
907  bool isLeaf)
908 {
909  std::string nm = "unassigned";
910  xercesc::DOMElement* nodes = NULL;
911 
912  // if( isLeaf )
913  // {
914  // STDLINE("","") ;
915  // if( theNodes_.find(indent) != theNodes_.end() ) nodes = theNodes_.find(indent)->second ;
916  // if( theNames_.find(indent) != theNames_.end() ) nm = theNames_.find(indent)->second ;
917  // ss_.str("") ; ss_ << "Attaching " << name << " to " << nm << " size: " << theNames_.size();
918  // STDLINE(ss_.str(),ACGreen) ;
919  // }
920  // else
921  // {
922  if (theNodes_.find(indent) != theNodes_.end()) // a new node
923  {
924  if (theNodes_.find(indent) != theNodes_.end()) nodes = theNodes_.find(indent)->second;
925  if (theNames_.find(indent) != theNames_.end()) nm = theNames_.find(indent)->second;
926  }
927  else
928  {
929  nodes = theDocument_->createElement(xercesc::XMLString::transcode("nodes"));
930  theNodes_[indent] = nodes;
931  theNames_[indent] = name;
932  anchorNode->appendChild(nodes);
933  }
934  // }
935  xercesc::DOMElement* node = theDocument_->createElement(xercesc::XMLString::transcode("node"));
936  nodes->appendChild(node);
937 
938  xercesc::DOMElement* nChilds = theDocument_->createElement(xercesc::XMLString::transcode("nChilds"));
939  node->appendChild(nChilds);
940 
941  xercesc::DOMText* nChildsVal = theDocument_->createTextNode(xercesc::XMLString::transcode("x"));
942  nChilds->appendChild(nChildsVal);
943 
944  xercesc::DOMElement* fSystemPathNode = theDocument_->createElement(xercesc::XMLString::transcode("fSystemPath"));
945  node->appendChild(fSystemPathNode);
946 
947  xercesc::DOMText* fSystemPathVal = theDocument_->createTextNode(xercesc::XMLString::transcode(fSystemPath_.c_str()));
948  fSystemPathNode->appendChild(fSystemPathVal);
949 
950  xercesc::DOMElement* fRootPathNode = theDocument_->createElement(xercesc::XMLString::transcode("fRootPath"));
951  node->appendChild(fRootPathNode);
952 
953  xercesc::DOMText* fRootPathVal = theDocument_->createTextNode(xercesc::XMLString::transcode(fRootPath_.c_str()));
954  fRootPathNode->appendChild(fRootPathVal);
955 
956  xercesc::DOMElement* fFoldersPathNode = theDocument_->createElement(xercesc::XMLString::transcode("fFoldersPath"));
957  node->appendChild(fFoldersPathNode);
958 
959  xercesc::DOMText* foldersPathVal = theDocument_->createTextNode(xercesc::XMLString::transcode(fFoldersPath_.c_str()));
960  fFoldersPathNode->appendChild(foldersPathVal);
961 
962  xercesc::DOMElement* fThisFolderPath = NULL;
963  xercesc::DOMElement* fFileOrHistName = NULL;
964  xercesc::DOMText* fileOrDirNameVal = NULL;
965  xercesc::DOMText* thisFolderNameVal = NULL;
966 
967  fThisFolderPath = theDocument_->createElement(xercesc::XMLString::transcode("fDisplayName"));
968 
969  if (isLeaf)
970  {
971  fFileOrHistName = theDocument_->createElement(xercesc::XMLString::transcode("fFileName"));
972  fileOrDirNameVal = theDocument_->createTextNode(xercesc::XMLString::transcode(name.c_str()));
973  thisFolderNameVal = theDocument_->createTextNode(xercesc::XMLString::transcode(name.c_str()));
974  ss_.str(""); ss_ << "name: " << ACRed << name << ACPlain << "/" << ACGreen << name;
975  STDLINE(ss_.str(), "");
976  }
977  else
978  {
979  std::string blank;
980  fFileOrHistName = theDocument_->createElement(xercesc::XMLString::transcode("fFileName"));
981  fileOrDirNameVal = theDocument_->createTextNode(xercesc::XMLString::transcode(blank.c_str()));
982  thisFolderNameVal = theDocument_->createTextNode(xercesc::XMLString::transcode(fThisFolderPath_.c_str()));
983  ss_.str(""); ss_ << "name: " << ACRed << fThisFolderPath_ << ACPlain << "/" << ACGreen << name;
984  STDLINE(ss_.str(), "");
985  }
986 
987  node->appendChild(fFileOrHistName);
988  fFileOrHistName->appendChild(fileOrDirNameVal);
989 
990  node->appendChild(fThisFolderPath);
991  fThisFolderPath->appendChild(thisFolderNameVal);
992 
993  xercesc::DOMElement* leaf = theDocument_->createElement(xercesc::XMLString::transcode("leaf"));
994  node->appendChild(leaf);
995 
996  xercesc::DOMText* leafVal = theDocument_->createTextNode(xercesc::XMLString::transcode(isALeaf_[isLeaf].c_str()));
997  leaf->appendChild(leafVal);
998 
999  return node;
1000 }
1001 //==========================================================================================
1002 void XmlDocument::setDarioStyle(bool darioStyle)
1003 {
1004  darioXMLStyle_ = darioStyle;
1005 }
1006 // clang-format on
1007 //==============================================================================
1010 /*
1011 void XmlDocument::recursiveFixTextFields(DOMElement *currEl)
1012 {
1013  DOMNodeList *nodeList = currEl->getChildNodes(); //get all children
1014 
1015  //recurse through children
1016  for(unsigned int i = 0; i<nodeList->getLength();++i)
1017  if(nodeList->item(i)->getNodeType() == DOMNode::TEXT_NODE) //fix text nodes
1018  ((DOMElement*)(nodeList->item(i)))->setTextContent(CONVERT_TO_XML(
1020  StringMacros::escapeString(XML_TO_CHAR(((DOMElement*)(nodeList->item(i)))->getNodeValue()))));
1021  else
1022  recursiveFixTextFields ((DOMElement*)(nodeList->item(i)));
1023 }
1024 */
xercesc::DOMElement * addTextElementToParent(const std::string &childName, const std::string &childText, xercesc::DOMElement *parent)
Definition: XmlDocument.cc:190
void copyDocument(const xercesc::DOMDocument *toCopy, xercesc::DOMDocument *copy)
Definition: XmlDocument.cc:257
void recursiveRemoveChild(xercesc::DOMElement *childEl, xercesc::DOMElement *parentEl)
Definition: XmlDocument.cc:632
XmlDocument(const std::string &rootName="ROOT")
Definition: XmlDocument.cc:46
void saveXmlDocument(const std::string &filePath)
Definition: XmlDocument.cc:652
void outputXmlDocument(std::ostringstream *out, bool dispStdOut=false)
Definition: XmlDocument.cc:471
void recursiveOutputXmlDocument(xercesc::DOMElement *currEl, std::ostringstream *out, bool dispStdOut=false, const std::string &tabStr="")
Definition: XmlDocument.cc:481
static std::string stackTrace(void)