-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathxsdcc.py
More file actions
248 lines (220 loc) · 8.28 KB
/
xsdcc.py
File metadata and controls
248 lines (220 loc) · 8.28 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
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
#!/usr/bin/python
import libxml2, sys, os
import urlparse
sys.path.append(".")
sys.setrecursionlimit(10000)
from fsm import XMLFsm, State
class switch(object):
def __init__(self, value):
self.value = value
self.fall = False
def __iter__(self):
yield self.match
raise StopIteration
def match(self, *args):
if self.fall or not args:
return True
elif self.value in args:
self.fall = True
return True
else:
return False
class XSCompiler:
XSC_NS = "urn:application:xsc"
def __init__(self):
self.subgraphs = dict()
self.substs = dict()
self.Decls = {0: dict(), 1: dict(), 2: dict()}
self.declTypes = dict(attribute=0, element=1, complexType=2, attributeGroup=0, group=1, simpleType=2)
self.loadedSchemas = set()
self.definitions = dict()
self.Decls[2] = {
"{http://www.w3.org/2001/XMLSchema}string": None,
"{http://www.w3.org/2001/XMLSchema}double": None,
"{http://www.w3.org/2001/XMLSchema}boolean": None,
"{http://www.w3.org/2001/XMLSchema}integer": None,
"{http://www.w3.org/2001/XMLSchema}positiveInteger": None,
"{http://www.w3.org/2001/XMLSchema}nonNegativeInteger": None,
"{http://www.w3.org/2001/XMLSchema}decimal": None,
"{http://www.w3.org/2001/XMLSchema}dateTime": None,
"{http://www.w3.org/2001/XMLSchema}unsignedLong": None,
"{http://www.w3.org/2001/XMLSchema}token": None,
"{http://www.w3.org/2001/XMLSchema}normalizedString": None
}
def expandQName(self, node, qname):
prefix, localname = qname.split(":")
if localname is None:
prefix, localname = localname, prefix
return "{%s}%s" % (node.searchNs(node.get_doc(), prefix).content, localname)
def importDef(self, node, targetNamespace):
qname = "{%s}%s" % (targetNamespace, node.prop("name"))
self.Decls[self.declTypes[node.name]][qname] = node
# print "Registered type %s" % qname
subst = node.prop("substitutionGroup")
if bool(subst):
subst = self.expandQName(node, subst)
if not self.substs.has_key(subst): self.substs[subst] = set()
self.substs[subst].add(node)
# print " added %s as substitut for %s" % (qname, subst)
def loadSchema(self, uri, targetNamespace = None):
if uri in self.loadedSchemas: return
print "Loading schema file: %s" % uri
self.loadedSchemas.add(uri)
doc = libxml2.readFile(uri, None, options = libxml2.XML_PARSE_NOBLANKS)
root = doc.getRootElement()
xpath = doc.xpathNewContext()
result = xpath.xpathEval("/*[local-name()='schema']/*[local-name()='include' or local-name()='import']")
for node in result:
url = urlparse.urlparse(node.prop("schemaLocation"))
if bool(url.scheme): continue
loc = os.path.normpath(os.path.join(os.path.dirname(uri), url.path))
self.loadSchema(loc, targetNamespace if node.name == "include" else None)
if targetNamespace is None:
targetNamespace = root.prop("targetNamespace")
result = xpath.xpathEval("/*[local-name()='schema']/*")
for node in result:
if node.name not in self.declTypes: continue
self.importDef(node, targetNamespace)
def targetNamespace(self, node):
return node.get_doc().getRootElement().prop("targetNamespace")
@staticmethod
def getActions(s):
if s is None: return []
return [x for x in s.split(" ")]
def createContentModel(self, node, ea, la, _stack = list()):
name = node.prop("name")
minOccurs = node.prop("minOccurs")
minOccurs = 1 if minOccurs is None else int(minOccurs)
maxOccurs = node.prop("maxOccurs")
maxOccurs = 1 if maxOccurs is None else (maxOccurs if maxOccurs == "unbounded" else int(maxOccurs))
fsm = None
ea.extend(self.getActions(node.prop("enter")))
la[:0] = self.getActions(node.prop("leave"))
print "%s%s: '%s' (%s, %s) %s | %s" % (len(_stack)* " ", node.name, name, minOccurs, maxOccurs, ea, la)
if _stack.count(node) > 0:
print "*** recursion detected ***"
return XMLFsm().empty()
stack = list(_stack)
stack.append(node)
for case in switch(node.name):
if case("element"):
if node.prop("ref") is not None:
ref = self.Decls[1][self.expandQName(node, node.prop("ref"))]
if ref is None: raise BaseException("Referenced element not known: %s" % node.prop("ref"))
return self.createContentModel(ref, [], [], stack).apply(ea, la).particle(minOccurs, maxOccurs)
name = node.prop("name")
if name is None: raise BaseException("Element requires a name")
qname = "{%s}%s" % (self.targetNamespace(node), name)
if self.subgraphs.has_key(qname) > 0:
print "*** call to subgraph %s ***" % qname
fsm = XMLFsm()
fsm.entry = State()
leave = State()
fsm.entry.addTransition("%s%s" % ('!' if node.prop("abstract") == "true" else "", qname), leave)
fsm.accepts.add(leave)
return fsm.particle(minOccurs, maxOccurs)
if node.prop("abstract") == "true":
if self.substs.has_key(qname):
content = []
for child in self.substs[qname]:
content.append(self.createContentModel(child, [], [], stack))
if len(content) > 0:
return XMLFsm().choice(content).particle(minOccurs, maxOccurs)
return XMLFsm().empty()
content = None
if node.prop("type") is not None:
typename = self.expandQName(node, node.prop("type"))
if not self.Decls[2].has_key(typename):
raise BaseException("Unknown type %s" % typename)
if self.Decls[2][typename] is not None:
content = self.createContentModel(self.Decls[2][typename], ea, la, stack)
else:
child = node.children
while child is not None:
if child.name in ("simpleType", "complexType"):
content = self.createContentModel(child, ea, la, stack)
break
child = child.next
if content is None: content = XMLFsm().empty()
return XMLFsm().element(name, content).apply(ea, la).particle(minOccurs, maxOccurs)
break
if case("simpleType"):
return XMLFsm().empty()
break
if case("complexType"):
content = None
child = node.children
while child is not None:
if child.name in ("simpleContent", "complexContent", "group", "choice", "sequence", "all"):
content = self.createContentModel(child, [], [], stack)
break
child = child.next
content = XMLFsm().empty() if content is None else content
return content
break
if case("sequence", "choice"):
content = []
child = node.children
while child is not None:
if child.name in ("element", "group", "choice", "sequence", "any"):
content.append(self.createContentModel(child, [], [], stack))
child = child.next
if len(content) == 0:
content = XMLFsm().empty()
else:
content = XMLFsm().sequence(content) if node.name == "sequence" else XMLFsm().choice(content)
return content.apply(ea, la).particle(minOccurs, maxOccurs)
break
if case("complexContent"):
content = None
child = node.children
while child is not None:
if child.name in ("extension", "restriction"):
content = self.createContentModel(child, [], [], stack)
break
child = child.next
return XMLFsm().empty() if content is None else content
break
if case("extension", "restriction"):
if node.name == "extension":
qname = self.expandQName(node, node.prop("base"))
base = self.Decls[2][qname]
baseContent = XMLFsm().empty() if base is None else self.createContentModel(base, [], [], stack)
else:
baseContent = XMLFsm().empty()
content = None
child = node.children
while child is not None:
if child.name in ("group", "choice", "sequence"):
content = self.createContentModel(child, [], [], stack)
break
child = child.next
if content is None:
fsm = baseContent
else:
fsm = baseContent.concat(content)
# if node.prop("base") == "se:SymbolizerType":
# print "**********"
## baseContent.dump()
# content.dump()
# fsm.dump()
return fsm
break
if case("any"):
return XMLFsm().element("*", XMLFsm().empty()).particle(minOccurs, maxOccurs)
break
if case():
raise BaseException("Unknown schema object: %s" % node.name)
return fsm
cc = XSCompiler()
cc.loadSchema(os.path.normpath(sys.argv[1]))
cc.subgraphs.update({
"{http://www.opengis.net/ogc}expression": None,
"{http://www.opengis.net/se}Graphic": None,
"{http://www.opengis.net/gml}_Geometry": None
})
nfa = cc.createContentModel(cc.Decls[1]["{http://www.opengis.net/se}LineSymbolizer"], [], [])
#nfa.dump()
dfa = nfa.determinize().minimize()
dfa.dump()
dfa.dump2()