StRoot  1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
StlXmlTree.cxx
1 #ifndef NoXmlTreeReader
2 #include <iostream>
3 #include <limits.h>
4 #include "StlXmlTree.h"
5 #include "ChapiStringUtilities.h"
6 
7 using std::string;
8 using std::vector;
9 using std::map;
10 using std::multimap;
11 using namespace chapi_string_utilities;
12 using stl_xml_tree::sep; // separation symbol
13 using stl_xml_tree::NO_ERROR;
14 using stl_xml_tree::NO_XML_BASE;
15 using stl_xml_tree::BAD_XML;
16 using std::cout;
17 using std::cerr;
18 #ifndef __STDB_STANDALONE__
19 #include "StMessMgr.h"
20 #else
21 #define LOG_DEBUG cout
22 #define LOG_INFO cout
23 #define LOG_WARN cout
24 #define LOG_ERROR cerr
25 #define LOG_FATAL cerr
26 #define LOG_QA cout
27 #define endm "\n"
28 #endif
29 
30 
31 
32 typedef vector<string>::const_iterator VCI;
33 typedef map<string,string>::const_iterator MCI;
34 typedef multimap<string,string>::const_iterator MMCI;
35 
36 
37 
39 StlXmlTree::StlXmlTree():
40  Filter(0),
41  XmlTree(multimap<string,string>()),
42  Depth(0),
43  PreviousDepth(0),
44  MaxDepthWanted(INT_MAX),
45  XmlTreeNodeName(""),
46  MyStatus(NO_XML_BASE)
47 {
48 }
50 StlXmlTree::StlXmlTree(const string xmlfilename, StlXmlTree* filter) :
51  Filter(filter),
52  XmlTree(multimap<string,string>()),
53  Depth(0),
54  PreviousDepth(0),
55  MaxDepthWanted(INT_MAX),
56  XmlTreeNodeName(""),
57  MyStatus(NO_ERROR)
58 {
59  int ret;
60  reader = xmlNewTextReaderFilename(xmlfilename.c_str());
61  if (reader != NULL)
62  {
63  ret = xmlTextReaderRead(reader);
64  while (ret == 1)
65  {
66  ProcessNode();
67  // ProcessNodeDebug();
68  ret = xmlTextReaderRead(reader);
69  }
70  xmlFreeTextReader(reader);
71  if (ret != 0)
72  {
73  LOG_ERROR<<"StlXmlTree::StlXmlTree: failed to parse "<< xmlfilename<<endm;
74  MyStatus = BAD_XML;
75  }
76  }
77  else
78  {
79  LOG_ERROR<<"StlXmlTree::StlXmlTree: unable to open "<< xmlfilename<< endm;
80  MyStatus = NO_XML_BASE;
81  }
82 }
84 void StlXmlTree::ShowTree()
85 {
86  LOG_INFO << "-----------------------------------------"<<endm;
87  LOG_INFO << "XmlTree contains"<<endm;
88  for (MMCI I=XmlTree.begin(); I!=XmlTree.end(); ++I)
89  {
90  LOG_INFO << (*I).first <<" -- "<<(*I).second <<endm;
91  }
92  LOG_INFO << "-----------------------------------------"<<endm;
93 }
95 string StlXmlTree::MakeKey(string FullyQualifiedParent, string Child)
96 {
97  return FullyQualifiedParent + sep + Child;
98 }
100 string StlXmlTree::QualifyParent(string Parent, string Attributes)
101 {
102  string rtrn = Parent + "(" + Attributes + ")";
103  return rtrn;
104 }
106 vector<string> StlXmlTree::LookUpValueByKey(string key)
107 {
108  vector<string> rtrn;
109  MMCI f = XmlTree.find(key);
110  if (f!=XmlTree.end())
111  {
112  MMCI b = XmlTree.lower_bound(key);
113  MMCI e = XmlTree.upper_bound(key);
114 
115  for (MMCI i = b; i!=e; ++i)
116  {
117  rtrn.push_back((*i).second);
118  }
119  }
120  return rtrn;
121 }
123 vector<string> StlXmlTree::LookUpValueByKey
124 (string& Parent, string ParentAttributes, string Child)
125 {
126  string qp = QualifyParent(Parent,ParentAttributes);
127  string key = MakeKey(qp,Child);
128 #ifdef DEBUG
129  LOG_INFO << "StlXmlTree::LookUpValueByKey key is " << key <<endm;
130 #endif
131  vector<string> rtrn = LookUpValueByKey(key);
132  Parent = key; // return key to the calling module -- enable recursion
133  return rtrn;
134 }
136 void StlXmlTree::InsertKeyValuePair(string Key, string Value)
137 {
138  OnTheTree = XmlTree.insert(make_pair(Key,Value));
139 }
141 bool StlXmlTree::AttributesContain(string A, string N, string V)
142 {
143  // as input, expect any of the strings returned by LookUpValueByKey
144  if ((N=="" && V=="") || N=="")
145  {
146  return false;
147  }
148  map<string,string> nv = ParseAttributeString(A);
149  map<string,string>::iterator I = nv.find(N);
150  if (I==nv.end())
151  {
152  return false;
153  }
154  else
155  {
156  if ((*I).second==V)
157  {
158  return true;
159  }
160  else
161  {
162  return false;
163  }
164  }
165 }
167 #ifdef DEBUG
168 void StlXmlTree::ProcessNodeDebug()
169 {
170  /*
171 From http://dotgnu.org/pnetlib-doc/System/Xml/XmlNodeType.html
172 
173 xmlTextReaderNodeType returns the following values:
174 None = 0
175 Element = 1
176 Attribute = 2
177 Text = 3
178 EntityReference = 5
179 Entity = 6
180 SignificantWhitespace = 14
181 EndElement = 15
182 EndEntity = 16
183  */
184  const xmlChar *name, *value;
185 
186  // name = xmlTextReaderConstName(reader);
187  name = xmlTextReaderName(reader);
188  if (name == NULL)
189  name = BAD_CAST "--";
190 
191  // value = xmlTextReaderConstValue(reader);
192  value = xmlTextReaderValue(reader);
193 
194  LOG_INFO << xmlTextReaderDepth(reader) <<" "<<xmlTextReaderNodeType(reader)<<" "<<name<<" "<<xmlTextReaderIsEmptyElement(reader)<<" "<< xmlTextReaderHasValue(reader)<<endm;
195  if (value == NULL)
196  {
197  LOG_INFO <<endm;
198  }
199  else
200  {
201  if (xmlStrlen(value) > 40)
202  {
203  LOG_INFO<<value<<".40s..."<endm;
204  }
205  else
206  {
207  LOG_INFO<<" "<<value<<endm;
208  }
209  }
210 
211  short HasAttributes = xmlTextReaderHasAttributes(reader);
212  if (HasAttributes)
213  {
214  while (xmlTextReaderMoveToNextAttribute(reader))
215  {
216  ProcessNodeDebug();
217  }
218  }
219 }
220 #endif
221 void StlXmlTree::UpdateDepth()
223 {
224  PreviousDepth = Depth;
225  Depth = xmlTextReaderDepth(reader);
226 }
228 void StlXmlTree::ProcessAttribute()
229 {
230 
231 /* attributes are on the same
232 depth as value text of the node, one level below the name of the node.
233 The difference between attribute value and regular value is that for
234 the attribute, the name and value are read out in one step.*/
235 
236  int NodeType = xmlTextReaderNodeType(reader);
237 
238  UpdateDepth();
239 
240  if (NodeType!=XML_READER_TYPE_ATTRIBUTE)
241  {
242  return;
243  }
244 
245  xmlChar* atname = xmlTextReaderName(reader);
246  string AttributeName;
247  if ( atname != NULL ) {
248  AttributeName = (char*)atname;
249  xmlFree(atname);
250  atname = NULL;
251  }
252 
253  xmlChar* tmp = xmlTextReaderValue(reader);
254  string NodeValue;
255  if ( tmp != NULL ) {
256  NodeValue = filter_string((char*)tmp);
257  xmlFree(tmp);
258  tmp = NULL;
259  }
260 
261  IdString += AttributeName + "=" + NodeValue + ";";
262 }
264 void StlXmlTree::ProcessNode()
265 {
266  int NodeType = xmlTextReaderNodeType(reader);
267  short HasValue = xmlTextReaderHasValue(reader);
268  short HasAttributes = xmlTextReaderHasAttributes(reader);
269  xmlChar* name = xmlTextReaderName(reader);
270  if ( name != NULL ) {
271  NodeName = (char*)name;
272  xmlFree(name);
273  name = NULL;
274  }
275 
276  string NodeValue = "";
277 
278  IdString = "";
279  if (HasValue)
280  {
281  xmlChar* tmp = xmlTextReaderValue(reader);
282  if ( tmp != NULL ) {
283  NodeValue = filter_string((char*)tmp);
284  xmlFree(tmp);
285  tmp = NULL;
286  }
287 
288  IdString = NodeName + "=" + NodeValue + ";";
289  }
290 
291  UpdateDepth();
292 
293  if (Depth>MaxDepthWanted)
294  {
295  return;
296  }
297  if (Depth<MaxDepthWanted)
298  {
299  MaxDepthWanted = INT_MAX;
300  }
301 
302  if (Depth<PreviousDepth || NodeType==XML_READER_TYPE_END_ELEMENT)
303  {
304  cut_string_after_sub(XmlTreeNodeName,sep);
305  }
306 
307  if ((NodeType==XML_READER_TYPE_ELEMENT || NodeValue !="") && NodeType != XML_READER_TYPE_COMMENT )
308  {
309  if (NodeType==XML_READER_TYPE_ELEMENT)
310  {
311  XmlTreeNodeName = XmlTreeNodeName + sep + NodeName;
312 
313  if (HasAttributes)
314  {
315 
316  while (xmlTextReaderMoveToNextAttribute(reader))
317  {
318  ProcessAttribute();
319  }
320  }
321  }
322 
323  if (!SkipBasedOnValue(XmlTreeNodeName,IdString))
324  {
325  string key = XmlTreeNodeName;
326  string value = IdString;
327 
328  // XmlTreeNodeName = XmlTreeNodeName + "("+IdString+")";
329  XmlTreeNodeName = QualifyParent(XmlTreeNodeName,IdString);
330 
331  // if (value!="")
332  {
333  OnTheTree = XmlTree.insert(make_pair(key,value));
334  MaxDepthWanted = INT_MAX;
335  }
336  }
337  else
338  {
339  MaxDepthWanted = Depth-1;
340  }
341  }
342 
343 
344 }
346 map<string,string> StlXmlTree::ParseAttributeString(string in)
347 {
348  vector<string> v = slice(in,";");
349  map<string,string> m = associate_pieces(v,"=");
350  return m;
351 }
353 bool StlXmlTree::SkipBasedOnValue(const string key, const string value)
354 {
355  if (!Filter)
356  {
357  return false;
358  }
359 
360  map<string,string> m = ParseAttributeString(value);
361 
362 #ifdef DEBUG
363  LOG_INFO << "StlXmlTree::SkipBasedOnValue key = "<<key<<" value = "<<value<<endm;
364 #endif
365  MMCI b = Filter->XmlTree.lower_bound(key);
366  MMCI e = Filter->XmlTree.upper_bound(key);
367 
368  bool rtrn = false;
369 
370  /* skip if all values mismatch the key <==> if there is even a
371 single match, take it. If there is no key, take it !*/
372 
373 
374 
375  if (b!=e)
376  {
377  for (MMCI i=b; i!=e; ++i)
378  {
379  map<string,string> f = ParseAttributeString((*i).second);
380 
381  /* use info in the filter: a single mismatching value vetoes */
382 
383  for (MCI ii = f.begin(); ii != f.end(); ++ii)
384  {
385  string search_key = (*ii).first;
386 
387  MCI mykey = m.find(search_key);
388 
389  if (mykey!=m.end())
390  {
391  /* generalizing for the attribute which is in itself a comma-separated sequence.
392  In that case, split into comma-separated elements and match element-by-element.
393  Return true if not a single match is found.
394  */
395 
396  vector<string> mykey_v = slice((*mykey).second,",");
397  vector<string> f_v = slice((*ii).second,",");
398 
399  rtrn = true;
400  VCI m_v_i = mykey_v.begin();
401  while (m_v_i != mykey_v.end() && rtrn)
402  {
403  VCI f_v_i = f_v.begin();
404 
405  while (f_v_i != f_v.end() && rtrn)
406  {
407 #ifdef DEBUG
408  LOG_INFO <<" compare " <<*m_v_i <<" and "<<*f_v_i <<endm;
409 #endif
410  if (*m_v_i == *f_v_i)
411  {
412  rtrn = false;
413  }
414 
415  ++f_v_i;
416  }
417  ++m_v_i;
418  }
419 
420  if (rtrn)
421  {
422 #ifdef DEBUG
423  LOG_INFO << "StlXmlTree::SkipBasedOnValue "<< rtrn <<endm;
424 #endif
425  return rtrn;
426  }
427  }
428  }
429  }
430  }
431  else
432  {
433  rtrn = false; /* otherwise will need to have a prototype structure in
434  a filter file to enable parsing*/
435  }
436 
437 #ifdef DEBUG
438  LOG_INFO << "StlXmlTree::SkipBasedOnValue "<< rtrn <<endm;
439 #endif
440  return rtrn;
441 }
442 
443 #endif
444