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 isfield(node_name): return node_name.find('.') >= 0
24

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