Project

General

Profile

« Previous | Next » 

Revision 2602

xml_func.py: process(): Refactored to emphasize special handling for row-based and column-based modes. In row-based mode, always use a DB relational function over a local XML function when possible, to faciliate testing of DB relational functions in row-based mode. (The shadowed local XML version will still be tested in non-DB modes, such as outputting to intermediate XML files.)

View differences:

lib/xml_func.py
65 65

  
66 66
def is_xml_func(node): return is_xml_func_name(node.tagName)
67 67

  
68
def process(node, on_error=exc.raise_, db=None, preserve=set(), strip=False):
68
def process(node, on_error=exc.raise_, rel_funcs=None, db=None):
69 69
    '''Evaluates the XML functions in an XML tree.
70
    @param preserve set(str...) XML functions not to remove.
70
    @param rel_funcs None|set(str...) Relational functions
71 71
        * container can be any iterable type
72
    @param strip Whether to instead replace most XML functions with their last
73
        parameter (usually the value) and evaluate only structural functions
72
        * If != None: Non-relational functions are removed, or relational
73
          functions are treated specially, depending on the db param (below).
74
    @param db
75
        * If None: Non-relational functions other than structural functions are
76
          replaced with their last parameter (usually the value), not evaluated.
77
          This is used in column-based mode to remove XML-only functions.
78
        * If != None: Relational functions are evaluated directly. This is used
79
          in row-based mode to combine relational and XML functions.
74 80
    '''
75
    preserve = set(preserve)
81
    has_rel_funcs = rel_funcs != None
82
    assert db == None or has_rel_funcs # rel_funcs required if db set
76 83
    
77 84
    for child in xml_dom.NodeElemIter(node):
78
        process(child, on_error, db, preserve, strip)
85
        process(child, on_error, rel_funcs, db)
86
    
79 87
    name = node.tagName
80
    if not is_xml_func_name(name) or name in preserve: pass
81
    elif strip and name not in structural_funcs: # just replace with last param
82
        value = pop_value(list(xml_dom.NodeTextEntryIter(node)), None)
83
        xml_dom.replace_with_text(node, value)
84
    else:
85
        try:
86
            items = xml_dom.NodeTextEntryIter(node)
87
            try: func = funcs[name]
88
            except KeyError:
89
                if db != None: # DB with relational functions available
90
                    value = sql.put(db, name, dict(items))
91
                else: value = pop_value(list(items)) # pass value through
92
            else: value = func(items, node) # local XML function
93
            
94
            xml_dom.replace_with_text(node, value)
88
    if not is_func_name(name): return # not any kind of function
89
    
90
    # Change rel_funcs *after* processing child nodes, which needs orig value
91
    if not has_rel_funcs: rel_funcs = set()
92
    rel_funcs = set(rel_funcs)
93
    
94
    row_mode = has_rel_funcs and db != None
95
    column_mode = has_rel_funcs and db == None
96
    items = xml_dom.NodeTextEntryIter(node)
97
    
98
    if row_mode and name in rel_funcs: # row-based mode: evaluate using DB
99
        value = sql.put(db, name, dict(items))
100
    elif column_mode and not name in structural_funcs: # column-based mode
101
        if name in rel_funcs: return # preserve relational functions
102
        # otherwise XML-only, so just replace with last param
103
        value = pop_value(list(items), None)
104
    else: # local XML function
105
        try: value = funcs[name](items, node)
95 106
        except Exception, e: # also catch non-wrapped exceptions (XML func bugs)
96 107
            # Save in case another exception raised, overwriting sys.exc_info()
97 108
            exc.add_traceback(e)
......
101 112
                '\n'+term.emph_multiline(str_)))
102 113
                
103 114
            on_error(e)
115
            return # in case on_error() returns
116
    xml_dom.replace_with_text(node, value)
104 117

  
105 118
##### XML functions
106 119

  
bin/map
163 163
    
164 164
    if out_is_db:
165 165
        out_db = connect_db(out_db_config)
166
        relational_funcs = set(sql.tables(out_db, schema_like='%',
166
        rel_funcs = set(sql.tables(out_db, schema_like='%',
167 167
            table_like=r'\__%'))
168 168
    
169 169
    def process_input(root, row_ready, map_path):
......
323 323
                map_table(col_names, []) # just create the template
324 324
                
325 325
                # Strip XML functions not in the DB
326
                preserve = db_xml.put_table_special_funcs | relational_funcs
327
                xml_func.process(root, preserve=preserve, strip=True)
326
                special_funcs = db_xml.put_table_special_funcs | rel_funcs
327
                xml_func.process(root, rel_funcs=special_funcs)
328 328
                if debug: log_debug('Putting stripped:\n'+str(root))
329 329
                    # only calc if debug
330 330
                
......
405 405
                pool.share_vars(locals())
406 406
                
407 407
                row_root = root.cloneNode(True) # deep copy so don't modify root
408
                xml_func.process(row_root, on_error)
408
                xml_func.process(row_root, on_error, rel_funcs, out_db)
409 409
                if not xml_dom.is_empty(row_root):
410 410
                    assert xml_dom.has_one_child(row_root)
411 411
                    try:

Also available in: Unified diff