forked from zengxs/py-kms
-
Notifications
You must be signed in to change notification settings - Fork 113
/
xmltok.py
144 lines (124 loc) · 3.56 KB
/
xmltok.py
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
TEXT = "TEXT"
START_TAG = "START_TAG"
#START_TAG_DONE = "START_TAG_DONE"
END_TAG = "END_TAG"
PI = "PI"
#PI_DONE = "PI_DONE"
ATTR = "ATTR"
#ATTR_VAL = "ATTR_VAL"
class XMLSyntaxError(Exception):
pass
class XMLTokenizer:
def __init__(self, f):
self.f = f
self.nextch()
def curch(self):
return self.c
def getch(self):
c = self.c
self.nextch()
return c
def eof(self):
return self.c == ""
def nextch(self):
self.c = self.f.read(1)
if not self.c:
raise StopIteration
return self.c
def skip_ws(self):
while self.curch().isspace():
self.nextch()
def isident(self):
self.skip_ws()
return self.curch().isalpha()
def getident(self):
self.skip_ws()
ident = ""
while True:
c = self.curch()
if not(c.isalpha() or c.isdigit() or c in "_-."):
break
ident += self.getch()
return ident
def getnsident(self):
ns = ""
ident = self.getident()
if self.curch() == ":":
self.nextch()
ns = ident
ident = self.getident()
return (ns, ident)
def match(self, c):
self.skip_ws()
if self.curch() == c:
self.nextch()
return True
return False
def expect(self, c):
if not self.match(c):
raise XMLSyntaxError
def lex_attrs_till(self):
while self.isident():
attr = self.getnsident()
#yield (ATTR, attr)
self.expect("=")
self.expect('"')
val = ""
while self.curch() != '"':
val += self.getch()
#yield (ATTR_VAL, val)
self.expect('"')
yield (ATTR, attr, val)
def tokenize(self):
while not self.eof():
if self.match("<"):
if self.match("/"):
yield (END_TAG, self.getnsident())
self.expect(">")
elif self.match("?"):
yield (PI, self.getident())
for tok in self.lex_attrs_till():
yield tok
self.expect("?")
self.expect(">")
elif self.match("!"):
self.expect("-")
self.expect("-")
last3 = ''
while True:
last3 = last3[-2:] + self.getch()
if last3 == "-->":
break
else:
tag = self.getnsident()
yield (START_TAG, tag)
for tok in self.lex_attrs_till():
yield tok
if self.match("/"):
yield (END_TAG, tag)
self.expect(">")
else:
text = ""
while self.curch() != "<":
text += self.getch()
if text:
yield (TEXT, text)
def gfind(gen, pred):
for i in gen:
if pred(i):
return i
def text_of(gen, tag):
# Return text content of a leaf tag
def match_tag(t):
if t[0] != START_TAG:
return False
if isinstance(tag, ()):
return t[1] == tag
return t[1][1] == tag
gfind(gen, match_tag)
# Assumes no attributes
t, val = next(gen)
assert t == TEXT
return val
def tokenize(file):
return XMLTokenizer(file).tokenize()