Package library :: Package pyjamas :: Package builder :: Module XMLFile
[hide private]
[frames] | no frames]

Source Code for Module library.pyjamas.builder.XMLFile

  1  # 
  2  # Copyright 2010 ZX www.zx.nl 
  3  # 
  4  # Licensed under the Apache License, Version 2.0 (the "License"); 
  5  # you may not use this file except in compliance with the License. 
  6  # You may obtain a copy of the License at 
  7  # 
  8  #     http://www.apache.org/licenses/LICENSE-2.0 
  9  # 
 10  # Unless required by applicable law or agreed to in writing, software 
 11  # distributed under the License is distributed on an "AS IS" BASIS, 
 12  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 13  # See the License for the specific language governing permissions and 
 14  # limitations under the License. 
 15  # 
 16   
 17  import re 
 18   
19 -class XMLFileError(RuntimeError):
20 pass
21
22 -class XMLFile(object):
23 re_xml = re.compile('''<[?]xml([^?]*)[?]>''') 24 re_comment = re.compile('''<!--(-*)''') 25 re_tag = re.compile('''<\s*([^/]\S*)(.*)>''') 26 re_tag_close = re.compile('''</\s*(\S+)\s*>''') 27 #re_attr = re.compile('''(\S+)="([^"]*)"''') # Bug in pyjamas re module 28 re_attr = re.compile('''\S+="[^"]*"''') 29
30 - def __init__(self, lines):
31 if isinstance(lines, basestring): 32 lines = lines.split("\n") 33 self.lines = lines 34 self.lineno = 0 35 self.xmlAttrs = None
36
37 - def error(self, msg):
38 raise XMLFileError("Line %s: %s" % (self.lineno, msg))
39
40 - def parseValue(self, v, unpackStr=False):
41 if v == "": 42 # Quick return 43 return v 44 vlower = v.lower() 45 if vlower in ["null", "none"]: 46 return None 47 if vlower == "true": 48 return True 49 if vlower == "false": 50 return False 51 try: 52 v = int(v) 53 return v 54 except: 55 pass 56 try: 57 v = float(v) 58 return v 59 except: 60 pass 61 if len(v) > 1: 62 if v[0] == v[-1]: 63 if unpackStr and v[0] in ["'", '"']: 64 return v[1:-1] 65 elif v[0] == '(' and v[-1] == ')': 66 values = [] 67 try: 68 for value in v[1:-1].split(','): 69 value = self.parseValue(value.strip(), True) 70 values.append(value) 71 return tuple(values) 72 except: 73 pass 74 if len(v) > 2: 75 if v[:2] == "u'" and v[-1] == "'": 76 return v[2:-1] 77 if v[:2] == 'u"' and v[-1] == '"': 78 return v[2:-1] 79 return v
80
81 - def getAttrs(self, line):
82 attrs = {} 83 #for k, v in self.re_attr.findall(line): 84 # attrs[k] = self.parseValue(v) 85 for kv in self.re_attr.findall(line): 86 k, v = kv.split("=", 1) 87 k = k.strip() 88 v = v.replace("%22;", '"') 89 v = v.replace("%0A;", "\n") 90 v = v.strip()[1:-1] 91 attrs[k] = self.parseValue(v) 92 return attrs
93
94 - def getTag(self, line, requiredTags=None):
95 mTag = self.re_tag.match(line) 96 if ( not mTag 97 or ( requiredTags is not None 98 and mTag.group(1) not in requiredTags 99 ) 100 ): 101 if requiredTags is not None: 102 self.error("Expected tag %s" % ",".join(requiredTags)) 103 else: 104 self.error("Expected a tag") 105 tagName = mTag.group(1) 106 tagAttrs = mTag.group(2) 107 if tagAttrs and tagAttrs[-1] == "/": 108 tagAttrs = tagAttrs[:-1] 109 tagClose = True 110 else: 111 tagClose = False 112 return (tagName, tagClose, self.getAttrs(tagAttrs))
113
114 - def getTagClose(self, line, tag=None):
115 mTag = self.re_tag_close.match(line) 116 if not mTag or (tag is not None and mTag.group(1) != tag): 117 if tag is not None: 118 self.error("Expected closing tag '%s'" % tag) 119 else: 120 self.error("Expected a closing tag") 121 return ( 122 mTag.group(1), 123 )
124
125 - def currentLine(self):
126 if self.lineno > len(self.lines): 127 return None 128 line = self.lines[self.lineno].strip() 129 startlineno = self.lineno 130 mComment = self.re_comment.search(line) 131 while mComment: 132 start = '<!--%s' % mComment.group(1) 133 end = '%s-->' % mComment.group(1) 134 left = line.find(start) + len(start) 135 right = line.find(end, left) 136 if right >= left: 137 right += len(end) 138 line = line[:left - len(start)] + line[right + len(end):] 139 mComment = self.re_comment.search(line) 140 elif self.lineno == len(self.lines): 141 self.error( 142 "Unterminated comment starting at line %s" % startlineno, 143 ) 144 else: 145 self.lineno += 1 146 line = line[:left] + self.lines[self.lineno].strip() 147 return line
148
149 - def nextLine(self):
150 if self.lineno > len(self.lines): 151 return None 152 line = self.currentLine() 153 self.lineno += 1 154 return line
155
156 - def isTagClose(self, tagName):
157 line = self.currentLine() 158 mTag = self.re_tag_close.match(line) 159 if mTag and mTag.group(1) == tagName: 160 return True 161 return False
162
163 - def nextTag(self, requiredTags):
164 line = self.nextLine() 165 tag = self.getTag(line, requiredTags) 166 if self.isTagClose(tag[0]): 167 line = self.nextLine() 168 tag = (tag[0], True) + tag[2:] 169 tagFunc = "tag_%s" % tag[0] 170 if hasattr(self, tagFunc): 171 return getattr(self, tagFunc)(tag) 172 self.error("Unknown tag '%s'" % tag[0])
173
174 - def parse(self):
175 line = self.currentLine() 176 mXML = self.re_xml.match(line) 177 if mXML: 178 xmlAttrs = mXML.group(1) 179 self.xmlAttrs = self.getAttrs(xmlAttrs) 180 line = self.nextLine() 181 rootTag = None 182 properties = self.nextTag(["pyjsglade", "properties", "components"]) 183 if properties[0] == 'pyjsglade': 184 rootTag = properties[0] 185 properties = self.nextTag(["properties", "components"]) 186 if properties[0] == 'properties': 187 properties = properties[2] 188 components = self.nextTag(["components"])[1] 189 else: 190 components = properties[1] 191 properties = {} 192 if rootTag is not None: 193 line = self.nextLine() 194 self.getTagClose(line, rootTag) 195 return properties, components
196
197 - def tag_pyjsglade(self, tag):
198 return tag
199
200 - def tag_components(self, tag):
201 tags = [] 202 tagName, tagClosed, tagAttrs = tag 203 if not tagClosed: 204 while not self.isTagClose(tagName): 205 tags.append(self.nextTag(["component"])) 206 line = self.nextLine() 207 self.getTagClose(line, tagName) 208 components = [] 209 for tag in tags: 210 components.append((tag[1]["index"], tag[1:])) 211 components.sort() 212 return tagName, [c[1] for c in components]
213
214 - def tag_component(self, tag):
215 tags = [] 216 tagName, tagClosed, tagAttrs = tag 217 if not tagClosed: 218 while not self.isTagClose(tagName): 219 tags.append(self.nextTag(["properties", "components"])) 220 line = self.nextLine() 221 self.getTagClose(line, tagName) 222 props = {} 223 childs = [] 224 for tag in tags: 225 if tag[0] == 'properties': 226 name = tag[1]["name"] 227 if not name in props: 228 props[name] = {} 229 props[name].update(tag[2]) 230 elif tag[0] == 'components': 231 childs += tag[1] 232 else: 233 assert("Unknown tag found: %s" % repr(tag[0])) 234 return tagName, tagAttrs, props, childs
235
236 - def tag_properties(self, tag):
237 tags = [] 238 tagName, tagClosed, tagAttrs = tag 239 if not tagClosed: 240 while not self.isTagClose(tagName): 241 tags.append(self.nextTag(["properties", "property"])) 242 line = self.nextLine() 243 self.getTagClose(line, tagName) 244 245 props = {} 246 for tag in tags: 247 if tag[0] == "properties": 248 props[tag[1]["name"]] = tag[2] 249 else: 250 props.update(tag[1]) 251 return tagName, tagAttrs, props
252
253 - def tag_property(self, tag):
254 tags = [] 255 tagName, tagClosed, tagAttrs = tag 256 if not tagClosed: 257 line = self.nextLine() 258 self.getTagClose(line, tagName) 259 return tagName, {tag[2]["name"]: tag[2]["value"]}
260 261 262 if __name__ == '__main__': 263 import sys 264 lines = open(sys.argv[1]).read() 265 xmlFile = XMLFile(lines) 266 tagName, components = xmlFile.parse() 267
268 - def dump(component):
269 print "component:", component[0], component[1] 270 for c in component[2]: 271 dump(c)
272 for component in components: 273 print "Frame:", component[0], component[1] 274 for c in component[2]: 275 dump(c) 276