forked from python-openxml/cxml
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtranslator.py
More file actions
202 lines (170 loc) · 6.17 KB
/
translator.py
File metadata and controls
202 lines (170 loc) · 6.17 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
# encoding: utf-8
"""
Translator taking a CXML abstract syntax tree (AST) and producing an object
graph rooted in a |RootElement| object.
"""
from __future__ import (
absolute_import, division, print_function, unicode_literals
)
from .model import (
Element, NamespaceDeclaration, RootElement, StringAttribute
)
from .symbols import attrs, qname
class CxmlTranslator(object):
"""
Constructs a |RootElement| object (with its graph) corresponding to
a Compact XML Expression Language (CXML) abstract syntax tree (AST).
"""
@classmethod
def translate(cls, tree):
"""
Return a |RootElement| object corresponding to the AST in *tree*,
containing all the right children, with all the right attributes,
etc.
"""
cxml_translator = cls()
return cxml_translator.evaluate(tree)
# -----------------------------------------------------------------------
# node evaluation methods
# -----------------------------------------------------------------------
# The role of a node evaluation method is to reduce an AST node to the
# graph subtree appropriate to the translator, like a StringAttribute
# object, etc.
# -----------------------------------------------------------------------
def evaluate(self, node):
"""
Return the value obtained by dispatching *node* to the appropriate
eval method.
"""
eval_method = getattr(self, node.name)
return eval_method(node)
def nsdecl(self, node):
"""
Return a |NamespaceDeclaration| object constructed from the
token.lexemes in *node*.
"""
name_token, _ = node.child_nodes
nspfx = name_token.lexeme
return NamespaceDeclaration(nspfx)
def qname(self, node):
"""
Return the qualified name in *node* as a single string, e.g.
'w:rPr'.
"""
return ''.join(token.lexeme for token in node.child_nodes)
def str_attr(self, node):
"""
Return a |StringAttribute| object constructed from the AST *node*.
"""
qname_node, _, text_token = node.child_nodes
qname = self.evaluate(qname_node)
value = text_token.lexeme
return StringAttribute.new(qname, value)
def attr(self, node):
"""
Return a |StringAttribute| or |NamespaceDeclaration| object,
depending on the production in *node*.
"""
str_attr_or_nsdecl_node, = node.child_nodes
return self.evaluate(str_attr_or_nsdecl_node)
def attr_list(self, node):
"""
Return a list of attribute objects produced from *node*.
"""
nodes = node.child_nodes
if len(nodes) == 1:
attr_node, = nodes
return [self.evaluate(attr_node)]
attr_node, _, attr_list_node = nodes
attr = self.evaluate(attr_node)
attr_list = self.evaluate(attr_list_node)
return [attr] + attr_list
def attrs(self, node):
"""
Return a list of attribute objects produced from *node*.
"""
_, attr_list_node, _ = node.child_nodes
return self.evaluate(attr_list_node)
def element(self, node):
"""
Return an |Element| object constructed from the values in *node*.
"""
qname_val, attrs_val, text = None, [], ''
for node in node.child_nodes:
symbol = node.symbol
if symbol == qname:
qname_val = self.evaluate(node)
elif symbol == attrs:
attrs_val = self.evaluate(node)
else:
# node is a TEXT token
text = node.lexeme
return Element.new(qname_val, attrs_val, text)
def tree(self, node):
"""
Return an (element, trees) pair constructed from the values in
*node*. The root element of each tree in *trees* is added to
*element* as a child.
"""
nodes = node.child_nodes
if len(nodes) == 1:
element_node, = nodes
return self.evaluate(element_node), []
element_node, _, trees_node = nodes
element = self.evaluate(element_node)
trees = self.evaluate(trees_node)
for child, _ in trees:
element.add_child(child)
return element, trees
def tree_list(self, node):
"""
Return a list of tree objects produced from *node*.
"""
nodes = node.child_nodes
if len(nodes) == 1:
tree_node, = nodes
return [self.evaluate(tree_node)]
tree_node, _, tree_list_node = nodes
tree = self.evaluate(tree_node)
tree_list = self.evaluate(tree_list_node)
return [tree] + tree_list
def trees(self, node):
"""
Return a list of linked tree objects produced from *node*.
"""
nodes = node.child_nodes
if len(nodes) == 1:
tree_node, = nodes
return [self.evaluate(tree_node)]
_, tree_list_node, _ = nodes
return self.evaluate(tree_list_node)
def root_element(self, node):
"""
Return a |RootElement| object constructed from the values in *node*.
"""
qname_val, attrs_val, text = None, [], ''
for node in node.child_nodes:
symbol = node.symbol
if symbol == qname:
qname_val = self.evaluate(node)
elif symbol == attrs:
attrs_val = self.evaluate(node)
else:
# node is a TEXT token
text = node.lexeme
return RootElement.new(qname_val, attrs_val, text)
def root(self, node):
"""
Return a |RootElement| object, having linked its children to it.
"""
nodes = node.child_nodes
if len(nodes) == 2: # root_element + SNTL
root_element_node, _ = nodes
root_element = self.evaluate(root_element_node)
return root_element
root_element_node, slash_token, trees_node, _ = nodes
root_element = self.evaluate(root_element_node)
trees = self.evaluate(trees_node)
for child, _ in trees:
root_element.add_child(child)
return root_element