75 |
75 |
|
76 |
76 |
def is_xml_func(node): return is_xml_func_name(node.tagName)
|
77 |
77 |
|
78 |
|
def process(node, on_error=exc.raise_, rel_funcs=None, db=None):
|
|
78 |
def process(node, on_error=exc.raise_, is_rel_func=None, db=None):
|
79 |
79 |
'''Evaluates the XML functions in an XML tree.
|
80 |
|
@param rel_funcs None|set(str...) Relational functions
|
81 |
|
* container can be any iterable type
|
|
80 |
@param is_rel_func None|f(str) Tests if a name is a relational function.
|
82 |
81 |
* If != None: Non-relational functions are removed, or relational
|
83 |
82 |
functions are treated specially, depending on the db param (below).
|
84 |
83 |
@param db
|
... | ... | |
88 |
87 |
* If != None: Relational functions are evaluated directly. This is used
|
89 |
88 |
in row-based mode to combine relational and XML functions.
|
90 |
89 |
'''
|
91 |
|
has_rel_funcs = rel_funcs != None
|
|
90 |
has_rel_funcs = is_rel_func != None
|
92 |
91 |
assert db == None or has_rel_funcs # rel_funcs required if db set
|
93 |
92 |
|
94 |
93 |
for child in xml_dom.NodeElemIter(node):
|
95 |
|
process(child, on_error, rel_funcs, db)
|
|
94 |
process(child, on_error, is_rel_func, db)
|
96 |
95 |
merge_tagged(node)
|
97 |
96 |
|
98 |
97 |
name = node.tagName
|
99 |
98 |
if not is_func_name(name): return node # not any kind of function
|
100 |
99 |
|
101 |
|
# Change rel_funcs *after* processing child nodes, which needs orig value
|
102 |
|
if not has_rel_funcs: rel_funcs = set()
|
103 |
|
rel_funcs = set(rel_funcs)
|
104 |
|
|
105 |
100 |
row_mode = has_rel_funcs and db != None
|
106 |
101 |
column_mode = has_rel_funcs and db == None
|
107 |
102 |
items = list(xml_dom.NodeTextEntryIter(node))
|
... | ... | |
110 |
105 |
if len(items) == 1 and items[0][0].isdigit(): # has single numeric param
|
111 |
106 |
# pass-through optimization for aggregating functions with one arg
|
112 |
107 |
value = items[0][1] # pass through first arg
|
113 |
|
elif row_mode and name in rel_funcs: # row-based mode: evaluate using DB
|
|
108 |
elif row_mode and is_rel_func(name): # row-based mode: evaluate using DB
|
114 |
109 |
value = sql_io.put(db, name, dict(items))
|
115 |
110 |
elif column_mode and not name in structural_funcs: # column-based mode
|
116 |
|
if name in rel_funcs: return # preserve relational functions
|
|
111 |
if is_rel_func(name): return # preserve relational functions
|
117 |
112 |
# otherwise XML-only, so just replace with last param
|
118 |
113 |
value = pop_value(items, None)
|
119 |
114 |
else: # local XML function
|
xml_func.py: process(): Changed rel_funcs param to a callback is_rel_func, so that caller can specify any dynamic function to determine if a name is a relational function rather than having to list out all known relational functions