CMS 3D CMS Logo

root2sqlite.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 from __future__ import print_function
3 import re
4 import json
5 import ROOT
6 import sqlite3
7 import argparse
8 
9 parser = argparse.ArgumentParser(description="Convert arbitrary ROOT file to SQLite database, mapping TTrees to tables and converting TObjects to JSON.")
10 
11 parser.add_argument('inputfile', help='ROOT file to read')
12 parser.add_argument('-o', '--output', help='SQLite file to write', default='root.sqlite')
13 args = parser.parse_args()
14 
15 f = ROOT.TFile.Open(args.inputfile)
16 db = sqlite3.connect(args.output)
17 
18 basic_objects = {}
19 
20 inf = re.compile("([- \[])inf([,}\]])")
21 nan = re.compile("([- \[])nan([,}\]])")
22 
23 def tosqlite(x):
24  if isinstance(x, ROOT.string):
25  try:
26  return unicode(x.data())
27  except:
28  return buffer(x.data())
29  if isinstance(x, int):
30  return x
31  if isinstance(x, float):
32  return x
33  if isinstance(x, long):
34  return x
35  else:
36  try:
37  rootobj = unicode(ROOT.TBufferJSON.ConvertToJSON(x))
38  # turns out ROOT does not generate valid JSON for NaN/inf
39  clean = nan.sub('\\g<1>0\\g<2>', inf.sub('\\g<1>1e38\\g<2>', rootobj))
40  obj = json.loads(clean)
41  jsonobj = json.dumps(obj, allow_nan=False)
42  return jsonobj
43  except Exception as e:
44  return json.dumps({"root2sqlite_error": e.__repr__(), "root2sqlite_object": x.__repr__()})
45 
46 def columnescape(s):
47  # add whatever is not a valid column name here
48  SQLKWDs = ["index"]
49  if s.lower() in SQLKWDs:
50  return s + "_"
51  else:
52  return s
53 
54 def treetotable(ttree, name):
55  name = name.replace("/", "_")
56  branches = [b.GetName() for b in ttree.GetListOfBranches()]
57  colnames = ", ".join(columnescape(b) for b in branches)
58  create = "CREATE TABLE %s(%s);" % (name, colnames)
59  print(create)
60  db.execute(create)
61  data = []
62  for i in range(ttree.GetEntries()):
63  ttree.GetEntry(i)
64  vals = tuple([tosqlite(getattr(ttree, b)) for b in branches])
65  data.append(vals)
66  insert = "INSERT INTO %s(%s) VALUES (%s);" % (name, colnames, ",".join(["?"] * len(branches)))
67  print(insert)
68  db.executemany(insert, data)
69 
70 def read_objects_root(rootfile):
71  xml_re = re.compile(r"^<(.+)>(.+)=(.+)<\/\1>$")
72  def parse_directory(di):
73  directory = rootfile.GetDirectory(di)
74  for key in directory.GetListOfKeys():
75  entry = key.GetName()
76  rtype = key.GetClassName()
77  fullpath = "%s/%s" % (di, entry) if di != "" else entry
78  if (rtype == "TDirectoryFile"):
79  for k, v, t in parse_directory(fullpath):
80  yield (k, v, t)
81  else:
82  obj = rootfile.Get(fullpath)
83  if obj:
84  yield (fullpath, obj, rtype)
85  else:
86  # special case to parse the xml abomination
87  m = xml_re.search(entry)
88  if m:
89  name = m.group(1)
90  typecode = m.group(2)
91  value = m.group(3)
92  fp = "%s/%s" % (di, name)
93  yield (fp, value, rtype)
94  else:
95  raise Exception("Invalid xml:" + entry)
96  path_fix = re.compile(r"^\/Run \d+")
97  for fullname, obj, rtype in parse_directory(""):
98  yield fullname, obj, rtype
99 
100 def save_keyvalue(dictionary, name):
101  name = name.replace("/", "_")
102  create = "CREATE TABLE %s(key, value);" % name
103  print(create)
104  db.execute(create)
105  data = []
106  for k, v in dictionary.iteritems():
107  vals = (unicode(k), tosqlite(v))
108  data.append(vals)
109  insert = "INSERT INTO %s(key, value) VALUES (?,?);" % name
110  print(insert)
111  db.executemany(insert, data)
112 
113 
114 for name, obj, rtype in read_objects_root(f):
115  print(name, obj, rtype)
116  if rtype == "TTree":
117  treetotable(obj, name)
118  else:
119  basic_objects[name] = obj
120 
121 save_keyvalue(basic_objects, "TDirectory")
def save_keyvalue(dictionary, name)
Definition: root2sqlite.py:100
S & print(S &os, JobReport::InputFile const &f)
Definition: JobReport.cc:66
def read_objects_root(rootfile)
Definition: root2sqlite.py:70
def tosqlite(x)
Definition: root2sqlite.py:23
def treetotable(ttree, name)
Definition: root2sqlite.py:54
static std::string join(char **cmd)
Definition: RemoteFile.cc:18
def columnescape(s)
Definition: root2sqlite.py:46