Project

General

Profile

1 13 aaronmk
# 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 15 aaronmk
def isfield(node_name): return node_name.find('.') >= 0
24 13 aaronmk
25
def field_name(node_name):
26 15 aaronmk
    if isfield(node_name): return node_name.partition('.')[2]
27 13 aaronmk
    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 15 aaronmk
    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 13 aaronmk
        for child in xml_util.NodeElemIter(node):
50 15 aaronmk
            if not xml_util.is_text(child): obj(child) # not XML metadata
51 13 aaronmk
52 15 aaronmk
    def obj(node):
53 13 aaronmk
        table = name_of(node)
54
        db_util.check_name(table)
55 15 aaronmk
        pkey_ = pkey(table)
56 13 aaronmk
        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 15 aaronmk
            if isfield(name_of(child)): row.update([field(child)])
68 13 aaronmk
            else: children.append(child)
69
70
        # Add fkey to parent
71
        parent_id = xml_util.get_id(node.parentNode)
72 15 aaronmk
        if parent_id != '': row[pkey(name_of(node.parentNode))] = parent_id
73 13 aaronmk
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 15 aaronmk
                    pkey_, row_ct_ref))
79 13 aaronmk
                break
80
            except db_util.NullValueException, ex:
81
                if try_num > 0: raise # exception still raised after retry
82 14 aaronmk
                # Search for required column in ancestors and their children
83 13 aaronmk
                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 15 aaronmk
        for child in children: obj(child)
89 13 aaronmk
90 15 aaronmk
    def field(node):
91 13 aaronmk
        if xml_util.is_text(node): value = xml_util.value(node)
92
        else:
93
            child = xml_util.first_elem(node)
94 15 aaronmk
            obj(child)
95 13 aaronmk
            value = xml_util.get_id(child)
96
        return (field_name(name_of(node)), value)
97
98
    row_ct_ref = [0]
99 15 aaronmk
    main(node)
100 13 aaronmk
    return row_ct_ref[0]