Project

General

Profile

1
# XML-database conversion
2

    
3
from xml.dom import Node
4

    
5
import db_util
6
import xml_util
7
from xml_util import name_of
8

    
9
ptr_suffix = '_id'
10

    
11
def is_ptr(node_name): return node_name.endswith(ptr_suffix)
12

    
13
def ptr_type(node_name):
14
    assert is_ptr(node_name)
15
    return node_name[:-len(ptr_suffix)]
16

    
17
def ptr_target(node):
18
    assert is_ptr(name_of(node))
19
    return xml_util.first_elem(node)
20

    
21
def pkey_name(node_name): return node_name+ptr_suffix
22

    
23
def is_field(node_name): return node_name.find('.') >= 0
24

    
25
def field_name(node_name):
26
    if is_field(node_name): return node_name.partition('.')[2]
27
    else: return node_name
28

    
29
def is_db_export(node_name): return node_name.find('.') >= 1 # has prefix
30

    
31
def find_by_name(node, name):
32
    for parent in xml_util.NodeParentIter(node):
33
        if name_of(parent) == name: return parent
34
        else:
35
            for child in xml_util.NodeElemIter(parent):
36
                child_name = field_name(name_of(child))
37
                if is_ptr(child_name):
38
                    if ptr_type(child_name) == name: return ptr_target(child)
39
                elif child_name == name: return child
40
    return None
41

    
42
def xml2db(node, db):
43
    def _main(node):
44
        for child in xml_util.NodeElemIter(node):
45
            if not xml_util.is_text(child): _obj(child) # not XML metadata
46
    
47
    def _obj(node):
48
        table = name_of(node)
49
        db_util.check_name(table)
50
        pkey = pkey_name(table)
51
        row = {}
52
        children = []
53
        iter_ = xml_util.NodeElemIter(node)
54
        
55
        # Skip any pkey
56
        child_name = name_of(iter_.curr()) # first child
57
        if is_db_export(child_name) and is_ptr(child_name)\
58
        or field_name(child_name) == pkey: iter_.next()
59
        
60
        # Divide children into fields and children with fkeys to parent
61
        for child in iter_:
62
            if is_field(name_of(child)): row.update([_field(child)])
63
            else: children.append(child)
64
        
65
        # Add fkey to parent
66
        parent_id = xml_util.get_id(node.parentNode)
67
        if parent_id != '': row[pkey_name(name_of(node.parentNode))] = parent_id
68
        
69
        # Insert node
70
        for try_num in range(2):
71
            try:
72
                xml_util.set_id(node, db_util.insert_or_get(db, table, row,
73
                    pkey, row_ct_ref))
74
                break
75
            except db_util.NullValueException, ex:
76
                if try_num > 0: raise # exception still raised after retry
77
                # Search for required column in ancestors and their children
78
                target = find_by_name(node, ptr_type(ex.col))
79
                if target == None: raise
80
                row[ex.col] = xml_util.get_id(target)
81
        
82
        # Insert children with fkeys to parent
83
        for child in children: _obj(child)
84
    
85
    def _field(node):
86
        if xml_util.is_text(node): value = xml_util.value(node)
87
        else:
88
            child = xml_util.first_elem(node)
89
            _obj(child)
90
            value = xml_util.get_id(child)
91
        return (field_name(name_of(node)), value)
92
    
93
    row_ct_ref = [0]
94
    _main(node)
95
    return row_ct_ref[0]
(7-7/8)