Project

General

Profile

« Previous | Next » 

Revision 3424

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

View differences:

lib/xml_func.py
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
bin/map
335 335
                
336 336
                # Strip XML functions not in the DB
337 337
                special_funcs = db_xml.put_table_special_funcs | rel_funcs
338
                xml_func.process(root, rel_funcs=special_funcs)
338
                xml_func.process(root, is_rel_func=lambda f: f in special_funcs)
339 339
                if debug: log_debug('Putting stripped:\n'+str(root))
340 340
                    # only calc if debug
341 341
                
......
422 422
                pool.share_vars(locals())
423 423
                
424 424
                row_root = root.cloneNode(True) # deep copy so don't modify root
425
                xml_func.process(row_root, on_error, rel_funcs, out_db)
425
                xml_func.process(row_root, on_error, lambda f: f in rel_funcs,
426
                    out_db)
426 427
                if not xml_dom.is_empty(row_root):
427 428
                    assert xml_dom.has_one_child(row_root)
428 429
                    try:

Also available in: Unified diff