Hello to everybody, This is XMLToolkit 0,7,BETA.2. I simplified most of the code. There are a few new features added as well. Now you can use the Binding tool to Bind XML documents to python objects.
doc = Binding.fromfile('GoogleService.wsdl') doc.definitions.message doc.definitions.message[0] doc.definitions.message[1] doc.definitions.message.name doc.definitions.message.name = 'bla bla' doc.definitions.message = '<h1>Hei I can assign XML to elements that will be parsed on the fly.</h1> Good!' doc.definitions.message[1] = OtherBinding doc.definitions.message[2] = OtherElement doc.definitions.message[0] = doc.definitions.message[2] for m in doc.definitions.message: print m print m.name doc.xml doc.xml(encoding = 'utf-8') doc.xml(encoding = 'utf-8', stream = mystream) doc.xml(encoding = 'utf-8', file = 'myGoogle.wsdl') str(doc.xml) doc.xml.composestream(stream) As you can see the syntax is similar to Amara XMLToolkit. I am still stuck with PEXComposer. If anyone is willing to help me out with simplifying the code and writing proper Composer to assemble PEX Objects back to XML, feel free to let me know. It shouldn't take that long. I need your help more than ever. I believe that XT (XML Toolkit) is coming nicely and I want to complete it as soon as possible because I want to move forward and start doing something else. :) So, can you have a look on the code and suggest any corrections or recommendations? Or even help me out rewriting some of it. I believe that the current design is not bad at all, however, somebody may suggest a different approach to solve a problem. Thanks.
# XML Toolkit # Copyright (C) 2005 Petko Petkov (GNUCITIZEN) [EMAIL PROTECTED] # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA __version__ = 0,7,'BETA.2' __author__ = 'Petko Petkov' __doc__ = """ XML Toolkit XML Toolkit provides an easy to use, very pythonic approach to xml processing. Why hard when it can be as simple as Python. """ import cStringIO # XML PARSER class Parser(object): """ Parser is responsible for parsing xml content. All methods are classmethods by design. This means that there is not need to instantiate the class. """ # ESCAPE FUNCTIONS @classmethod def escape(self, string, entities = {}): """ escape(string, entities = {}) -> escaped_string Replace special strings with their xml represenation. The optional entity dictionary is there if additional string substitutions are required. """ string = string.replace('&', '&') string = string.replace('<', '<') string = string.replace('>', '>') for entity, value in entities.iteritems(): string = string.replace(entity, value) return string @classmethod def unescape(self, string, entities = {}): """ unescape(string, entities = {}) -> unescaped_string Replace xml entities with their string representation. This method is a reverse of the escape method. """ string = string.replace('>', '>') string = string.replace('<', '<') string = string.replace('&', '&') for entity, value in entities.iteritems(): string = string.replace(value, entity) return string @classmethod def quote(self, string, entities = {}): """ quote(string, entities) -> quoted_string Replace special strings with their xml representation and quote. This function is useful when dealing with attributes. The optional entity dictionary is there if additional string substitutions are required. """ _entities = {} _entities.update(entities) _entities['"'] = '"e;' _entities["'"] = ''' return '"%s"' % self.escape(string, _entities) @classmethod def unquote(self, string, entities = {}): """ unquote(string, entities) -> unquoted_string Replace xml entities with their string representation. This method is a reverse of the unquote method. """ _entities = {} _entities.update(entities) _entities['"'] = '"e;' _entities["'"] = ''' string = string.strip() if string.startswith('"'): string = string.strip('"') else: string = string.strip("'") return self.unescape(string, _entities) # SPLIT FUNCTIONS @classmethod def splitdtd(self, dtdstring): """ splitdtd(dtdstring) -> dtdstring TODO: to be implemented """ return dtdstring @classmethod def splitcdata(self, cdatastring): """ splitcdata(cdatastring) -> string Remove the XML CDATA encapsulation. """ return cdatastring.lstrip('<![CDATA[').rstrip(']]>') @classmethod def splitcomment(self, commentstring): """ splitcomment(commentstring) -> string Remove the XML Comment encapsulation. """ return commentstring.lstrip('<!--').rstrip('-->').strip() @classmethod def splitpi(self, pistring): """ splitpi(pistring) -> target, content Remove the XML PI encapsulation. """ pistring = pistring.lstrip('<?').rstrip('?>').strip() try: space = pistring.index(' ') except: space = 0 return pistring[:space], pistring[space:].strip() @classmethod def splitattributes(self, attributestring): """ splitattributes(attributestring) -> dict Remove the XML Attribute encapsulation and return a dictionary that maps attribute names to their coresponding values. """ string = attributestring.strip() if not string: return {} attributedict = {} while True: index = string.index('=') name = string[:index].strip() rest = string[index + 1:].strip() if rest.startswith('"'): end = rest[1:].index('"') else: end = rest[1:].index("'") value = self.unquote(rest[:end + 2]) attributedict[name] = value string = rest[end + 2:].strip() if not string: break return attributedict @classmethod def splitelement(self, elementstring): """ splitelement(elementstring) -> qname, attributestring Remove the XML Element encapsulation and split to a tuple that contains the element name and the attributestring. """ element = elementstring.lstrip('<').rstrip('>') try: space = element.index(' ') except: space = len(element) qname = element[:space].strip('/').strip() attributestring = element[space:].rstrip('/').strip() return qname, attributestring @classmethod def splitstring(self, string): """ splitstring(string) -> generator Split string to XML Nodes. """ if not string: raise StopIteration while True: try: index = string.index('<') except: index = len(string) if string[:index]: end = index elif string.startswith('<![CDATA['): end = string.index(']]>') + 3 elif string.startswith('<?'): end = string.index('?>') + 2 elif string.startswith('<!DOCTYPE'): end = string.index(']>') + 2 elif string.startswith('<!--'): end = string.index('-->') + 3 else: end = string.index('>') + 1 yield string[:end] string = string[end:] if not string: break @classmethod def splitstream(self, stream): """ splitstream(stream) -> generator Split stream to XML Nodes. TODO: implement stream parser instead of calling splitstring method """ return self.splitstring(stream.read()) @classmethod def splitfile(self, filepath): """ splitfile(filepath) -> generator Split file to XML Nodes. """ file = open(filepath) generator = self.splitstream(file) file.close() return generator @classmethod def parsenodes(self, nodes, handler): """ parsenodes(nodes, handler) -> None Dispatch XML Nodes to their coresponding event handler. """ for node in nodes: if node.startswith('<![CDATA['): handler.cdata(self.splitcdata(node)) elif node.startswith('<?'): handler.pi(*self.splitpi(node)) elif node.startswith('<!DOCTYPE'): handler.dtd(*self.splitdtd(node)) elif node.startswith('<!--'): handler.comment(self.splitcomment(node)) elif node.startswith('</'): qname, attributes = self.splitelement(node) handler.endelement(qname) elif node.endswith('/>'): qname, attributes = self.splitelement(node) handler.beginelement(qname, self.splitattributes(attributes)) handler.endelement(qname) elif node.startswith('<'): qname, attributes = self.splitelement(node) handler.beginelement(qname, self.splitattributes(attributes)) else: handler.text(node) @classmethod def parsestream(self, stream, handler): """ parsestream(stream, handler) -> None Dispatch XML Nodes from stream to their coresponding event handler. """ self.parsenodes(self.splitstream(stream), handler) @classmethod def parsefile(self, filepath, handler): """ parsefile(filepath, handler) -> None Dispatch XML Nodes from file to their coresponding event handler. """ self.parsenodes(self.splitfile(filepath), handler) @classmethod def parsestring(self, string, handler): """ parsestring(string, handler) -> None Dispatch XML Nodes from string to their coresponding event handler. """ self.parsenodes(self.splitstring(string), handler) # XML PARSER WITH NAMESPACE SUPPORT class ParserNS(Parser): """ ParserNS extends Parser by adding namespace support. """ @classmethod def splitqname(self, qname): """ splitqname(qname) -> prefix, localName Split qualified name to prefix, localName tuple. """ try: index = qname.index(':') except: return '', qname return qname[:index], qname[index + 1:] @classmethod def splituname(self, uname): """ splituname(uname) -> namespace, localName Split universal name to namespace, localName tuple. """ try: index = uname.index('}') if not uname.startswith('{'): raise except: return '', uname return uname[1:index], uname[index + 1:] @classmethod def splitnamespaces(self, attributes): """ splitnamespaces(attributes) -> namespaces, attributes Separate namespace declarations from the attribute dictionary. """ namespacedict = {} attributedict = {} for name, value in attributes.iteritems(): prefix, _name = self.splitqname(name) if prefix == 'xmlns': namespacedict[_name] = value elif prefix == '' and _name == 'xmlns': namespacedict[''] = value else: attributedict[name] = value return namespacedict, attributedict @classmethod def findnamespace(self, prefix, nslevels): """ findnamespace(prefix, nslevels) -> namespace Find namespace by prefix. This functions is a bit misleading. The nslevels dictionary contains level to namespaces dictionary mappings. The level represents the level at which a namespace declration is found. """ for index in reversed(nslevels.keys()): try: return nslevels[index][prefix] except: pass return '' @classmethod def rebuildattributes(self, attributes, nslevels): """ rebuildattributes(attributes, nslevels) -> qualified_attributes Rebuild attributes according to nslevels. The nslevels dictionary is used by the findnamespace method to find the coresponding namespace for each attribute. """ _attributes = {} for name, value in attributes.iteritems(): prefix, name = self.splitqname(name) namespace = self.findnamespace(prefix, nslevels) _attributes[namespace, prefix, name] = value return _attributes @classmethod def parsenodes(self, nodes, handler): """ parsenodes(nodes, handler) -> None Dispatch XML Nodes to their coresponding event handler. """ namespaces = {} count = 0 for node in nodes: if node.startswith('<![CDATA['): handler.cdata(self.splitcdata(node)) elif node.startswith('<?'): handler.pi(*self.splitpi(node)) elif node.startswith('<!DOCTYPE'): handler.dtd(self.splitdtd(node)) elif node.startswith('<!--'): handler.comment(self.splitcomment(node)) elif node.startswith('</'): count -= 1 qname, attributes = self.splitelement(node) prefix, name = self.splitqname(qname) namespace = self.findnamespace(prefix, namespaces) if namespaces.has_key(count): del namespaces[count] handler.endelement((name, prefix, namespace)) elif node.endswith('/>'): qname, attributes = self.splitelement(node) prefix, name = self.splitqname(qname) attributes = self.splitattributes(attributes) nsattributes, attributes = self.splitnamespaces(attributes) attributes = self.rebuildattributes(attributes, namespaces) if nsattributes: namespaces[count] = nsattributes namespace = self.findnamespace(prefix, namespaces) if namespaces.has_key(count): del namespaces[count] handler.beginelement((name, prefix, namespace), attributes) handler.endelement((name, prefix, namespace)) elif node.startswith('<'): qname, attributes = self.splitelement(node) prefix, name = self.splitqname(qname) attributes = self.splitattributes(attributes) nsattributes, attributes = self.splitnamespaces(attributes) attributes = self.rebuildattributes(attributes, namespaces) if nsattributes: namespaces[count] = nsattributes namespace = self.findnamespace(prefix, namespaces) handler.beginelement((name, prefix, namespace), attributes) count += 1 else: handler.text(node) # CONTENT HANDLER class Handler(object): """ Handle XML Events. """ def beginelement(self, qname, attributes): pass def endelement(self, qname): pass def dtd(self, content): pass def text(self, content): pass def cdata(self, content): pass def comment(self, content): pass def pi(self, target, content): pass # PEX HANDLER, PARSER AND COMPOSER class PEXHandler(Handler): """ Build PEX from ParserNS. """ def __init__(self, normalize = True): self.nodes = [] self.prefixes = {} self.normalize = normalize self.elementque = [self] def beginelement(self, qname, attributes): name, prefix, namespace = qname self.prefixes[prefix] = namespace element = Element(name, namespace, prefix) for (namespace, prefix, name), value in attributes.iteritems(): element.attributes.append(Attribute( name, value, namespace, prefix)) self.elementque[-1].nodes.append(element) self.elementque.append(element) def endelement(self, qname): name, prefix, namespace = qname self.prefixes[prefix] = namespace self.elementque.pop() def dtd(self, content): self.elementque[-1].nodes.append(DTD(content)) def cdata(self, content): self.elementque[-1].nodes.append(CDATA(content)) def comment(self, content): self.elementque[-1].nodes.append(Comment(content)) def pi(self, target, content): self.elementque[-1].nodes.append(PI(target, content)) def text(self, content): if self.normalize: content = content.strip() if content: self.elementque[-1].nodes.append(Text(content)) else: self.elementque[-1].nodes.append(Text(content)) class PEXParser(object): """ Build PEX from PEXHandler and ParserNS. """ @classmethod def parsestring(self, string, normalize = True): """ parsestring(string, normalize = True) -> [] Parse string and return nodes as list. """ handler = PEXHandler(normalize) ParserNS.parsestring(string, handler) return handler.nodes @classmethod def parsestream(self, stream, normalize = True): """ parsestream(stream, normalize = True) -> [] Parse stream and return nodes as list. """ handler = PEXHandler(normalize) ParserNS.parsestream(stream, handler) return handler.nodes @classmethod def parsefile(self, filepath, normalize = True): """ parsefile(filepath, normalize = True) -> [] Parse file and return nodes as list. """ handler = PEXHandler(normalize) ParserNS.parsefile(filepath, handler) return handler.nodes class PEXComposer(object): """ Compose XML from PEX. """ @classmethod def findprefix(self, namespace, namespaces): """ findprefix(namespace, namespaces) -> prefix Find prefix from namespace in namespaces. Otherwise, return None. """ for key, value in namespaces.iteritems(): if value == namespace: return key @classmethod def findnamespace(self, prefix, namespaces): """ findnamespace(prefix, namespaces) -> namespace Find namespace from prefix in namespaces. Otherwise, return None. """ try: return namespaces[prefix] except: pass @classmethod def addnamespace(self, namespace, prefix, namespaces): """ addnamespace(namespace, prefix, namespaces) -> None Add prefix to namespace mapping in namespaces as such all prefix names are resolved automatically. """ if namespaces.has_key(prefix): if namespaces[prefix] != namespace: index = 0 prefix = 'ns0' while namespaces.has_key(prefix): index = index + 1 prefix = 'ns' + str(index) namespaces[prefix] = namespace else: _prefix = self.findprefix(namespace, namespaces) if _prefix is None: namespaces[prefix] = namespace @classmethod def extractnamespaces(self, list, namespaces = {}): """ extractnamespaces(list) -> {} Extract namespaces from nodes and return prefix to namespaces mappins in a dictionary. list must contain Element and Attributes only. The optional namespaces parameter supplies base namespaces. """ _namespaces = {} _namespaces.update(namespaces) for item in list: if not item.namespace: continue prefix = item.prefix or 'ns0' self.addnamespace(item.namespace, prefix, _namespaces) return _namespaces @classmethod def exportnode(self, node, stream, namespaces = {}): """ exportnode(node, stream, namespaces = {}) -> None Export node into stream. The namespaces parameter will be modified. Exported elements does not contain xml declrations. """ if isinstance(node, PI): stream.write('<?%s %s ?>' % (node.target or '', node.content)) elif isinstance(node, DTD): stream.write(node.content) elif isinstance(node, CDATA): stream.write('<![CDATA['+ node +']>') elif isinstance(node, Comment): stream.write('<!-- ' + node + ' -->') elif isinstance(node, (Text, str, unicode)): stream.write(node) elif isinstance(node, Element): pass else: raise ValueError, 'TODO: add message here' @classmethod def exportnodens(self, node, stream, namespaces = {}): """ exportnodens(node, stream, namespaces = {} -> None Export node into stream. The namespaces parameter will be modified. Exported element contain namespace declarations. """ if not isinstance(node, Element): self.exportnode(node, stream, namespaces) else: namespaces = self.extractnamespaces( [node] + node.attributes, namespaces) buff = cStringIO.StringIO() for _node in node.nodes: self.exportnode(_node, buff, namespaces) attributes = '' for attribute in node.attributes: attributes = '%s %s=%s' % ( attributes, attribute.name, ParserNS.quote(attribute.value)) for prefix, namespace in namespaces.iteritems(): attributes = '%s %s=%s' % ( attributes, 'xmlns:' + prefix, namespace) prefix = self.findprefix(node.namespace, namespaces) name = '%s:%s' % (prefix, node.name) if not node.nodes: stream.write('<%s%s/>' % (name, attributes)) else: stream.write('<%s%s>' % (name, attributes)) stream.write(buff.getvalue()) stream.write('<%s>' % name) @classmethod def composestream(self, pex, stream, encoding = 'utf-8', namespaces = {}): """ composestream(pex, stream, encoding = 'utf-8', namespaces = {}) -> None Compose XML document from pex and write to stream. pex is either Element or list. """ class encapsulate(object): def __init__(self, stream): self.stream = stream def write(self, string): self.stream.write(string.encode(encoding)) stream = encapsulate(stream) stream.write('<?xml version="1.0" encoding="%s"?>\n' % encoding) if isinstance(pex, list): for node in pex: if isinstance(node, PI) and node.target == 'xml': continue self.exportnodens(node, stream, namespaces) else: self.exportnodens(pex, stream, namespaces) @classmethod def composestring(self, pex, encoding = 'utf-8', namespaces = {}): """ composestring(pex, encoding = 'utf-8', namespaces = {}) -> string Compose XML document from pex and return string. pex is either Element or list. """ stream = cStringIO.StringIO() self.composestream(pex, stream, encoding, namespaces) return stream.getvalue() @classmethod def composefile(self, pex, filepath, encoding = 'utf-8', namespaces = {}): """ composefile(pex, filepath, encoding = 'utf-8', namespaces = {}) -> None Compose XML document from pex and write to file. pex is either Element or list. """ file = open(filepath, 'w') self.composestream(pex, file, encoding, namespaces) file.close() # PEX TYPES class Text(unicode): """ XML Text node """ class CDATA(unicode): """ XML CDATA node """ class Comment(unicode): """ XML Comment node """ class PI(object): """ XML ProcessInstruction node """ def __init__(self, target = '', content = ''): self.target = target self.content = content class DTD(object): """ XML DTD node NOTE: not implemented """ def __init__(self, content): self.content = content class Attribute(object): """ XML Attribute """ def __init__(self, name, value = '', namespace = '', prefix = ''): self.name = name self.value = value self.namespace = namespace self.prefix = prefix class Element(object): """ XML Element """ def __init__(self, name, namespace = '', prefix = ''): self.name = name self.namespace = namespace self.prefix = prefix self.nodes = [] self.attributes = [] # PEX HELPERS class Composer(PEXComposer): """ Compose XML from Binding """ def __init__(self, binding, encoding = 'utf-8', namespaces = {}): self.encoding = encoding self.namespaces = namespaces if isinstance(binding, Binding): if binding.xml_name == '__binding__': self.element = binding.xml_nodes else: self.element = binding.xml_element else: self.element = binding def __call__(self, encoding = None, namespaces = None, stream = None, file = None): if encoding is None: encoding = self.encoding if namespaces is None: namespaces = self.namespaces if stream is not None: self.composestream(self.element, stream, encoding, namespaces) elif file is not None: self.composefile(self.element, file, encoding, namespaces) else: return self.composestring(self.element, encoding, namespaces) def __str__(self): return self.composestring(self.element, self.encoding, self.namespaces) class Binding(object): """ XML to Python object Binding """ def __init__(self, element, origin = None): self.xml_element = element self.xml_origin = origin self.xml = Composer(element) def __getattr__(self, name): if not name.startswith('xml'): for attribute in self.xml_element.attributes: if attribute.name == name: return attribute.value for node in self.xml_element.nodes: if isinstance(node, Element) and node.name == name: return Binding(node, self.xml_element) else: if name not in ('xml_element', 'xml_origin'): return getattr(self.xml_element, name[4:]) raise AttributeError, 'TODO: add message here' def __setattr__(self, name, value): if not name.startswith('xml'): for attribute in self.xml_element.attributes: if attribute.name == name: attribute.value = value return for node in self.xml_element.nodes: if isinstance(node, Element) and node.name == name: return self.__setelement_(node, value) self.xml_element.attributes.append(Attribute( name = name, value = value)) return object.__setattr__(self, name, value) def __delattr__(self, name): if not name.startswith('xml'): for index, attribute in enumerate(self.xml_element.attributes): if attribute.name == name: del self.xml_element.attributes[index] return for index, node in enumerate(self.xml_element.nodes): if isinstance(node, Element) and node.name == name: del self.xml_elements.nodes[index] return raise AttributeError, 'TODO: add message here' def __getitem__(self, key): if isinstance(key, slice): # TODO: support for slices pass elif isinstance(key, int): if self.xml_origin is None: raise RuntimeError, 'TODO: add message here' if key >= 0: nodes = lambda: self.xml_origin.nodes else: nodes = lambda: reversed(self.xml_origin.nodes) key = key * -1 - 1 for node in nodes(): if isinstance(node, Element) \ and node.name == self.xml_element.name: if key == 0: return Binding(node) key = key - 1 raise IndexError, 'TODO: add message here' elif isinstance(key, (str, unicode)): matches = self.__makematch_(key) if key.startswith('@'): for attribute in self.xml_element.attributes: if matches(attribute): return attribute.value else: for node in self.xml_element.nodes: if matches(node): return Binding(node, self.xml_element) raise KeyError, 'TODO: add message here' def __setitem__(self, key, value): if isinstance(key, slice): # TODO: support for slices pass elif isinstance(key, int): if self.xml_origin is None: raise RuntimeError, 'TODO: add message here' if key >= 0: nodes = lambda: self.xml_origin.nodes else: nodes = lambda: reversed(self.xml_origin.nodes) key = key * -1 - 1 for node in nodes(): if isinstance(node, Element) \ and node.name == self.xml_element.name: if key == 0: return self.__setelement_(node, value) key = key - 1 raise IndexError, 'TODO: add message here' elif isinstance(key, (str, unicode)): matches = self.__makematch_(key) if key.startswith('@'): for attribute in self.xml_element.attributes: if matches(attribute): attribute.value = value return else: for node in self.xml_element.nodes: if matches(node): return self.__setelement_(node, value) raise KeyError, 'TODO: add message here' def __delitem__(self, key): if isinstance(key, slice): # TODO: support for slices pass elif isinstance(key, int): if self.xml_origin is None: raise RuntimeError, 'TODO: add message here' if key >= 0: nodes = lambda: self.xml_origin.nodes else: nodes = lambda: reversed(self.xml_origin.nodes) key = key * -1 - 1 for index, node in enumerate(nodes()): if isinstance(node, Element) \ and node.name == self.xml_element.name: if key == 0: del self.xml_origin.nodes[index] return key = key - 1 raise IndexError, 'TODO: add message here' elif isinstance(key, (str, unicode)): matches = self.__makematch_(key) if key.startswith('@'): for index, attribute in enumerate(self.xml_element.attributes): if matches(attribute): del self.xml_element.attributes[index] return else: for index, node in enumerate(self.xml_element.nodes): if matches(node): del self.xml_element.nodes[index] return raise KeyError, 'TODO: add message here' def __len__(self): if self.xml_origin is None: raise RuntimeError, 'TODO: add message here' len = 0 for node in self.xml_origin.nodes: if isinstance(node, Element) \ and node.name == self.xml_element.name: len = len + 1 return len def __iter__(self): if self.xml_origin is None: raise RuntimeError, 'TODO: add message here' def iterator(): for node in self.xml_origin.nodes: if isinstance(node, Element) \ and node.name == self.xml_element.name: yield Binding(node) return iterator() def __repr__(self): return PEXComposer.composestring(self.xml_element.nodes) def __setelement_(self, element, value): """ __setelement_(element, value) -> None Set element content to value. value is string, Binding or another Element. """ if isinstance(value, (str, unicode)): element.nodes = PEXParser.parsestring(value) elif isinstance(value, Binding): node.name = value.xml_name node.namespace = value.xml_namespace node.prefix = value.xml_prefix node.attributes = value.xml_attributes node.nodes = value.xml_nodes elif isinstance(value, Element): node.name = value.name node.namespace = value.namespace node.prefix = value.prefix node.attributes = value.attributes node.nodes = value.nodes else: raise ValueError, 'TODO: add message here' @classmethod def fromstring(self, string, normalize = True): """ fromstring(string, normalize = True) -> Binding Parse string and return Binding. """ element = Element('__binding__') element.nodes = PEXParser.parsestring(string, normalize) return Binding(element) @classmethod def fromstream(self, stream, normalize = True): """ fromstream(stream, normalize = True) -> Binding Parse stream and return Binding. """ element = Element('__binding__') element.nodes = PEXParser.parsestream(stream, normalize) return Binding(element) @classmethod def fromfile(self, filepath, normalize = True): """ fromfile(filepath, normalize = True) -> Binding Parse file and return Binding. """ element = Element('__binding__') element.nodes = PEXParser.parsefile(filepath, normalize) return Binding(element)
_______________________________________________ XML-SIG maillist - XML-SIG@python.org http://mail.python.org/mailman/listinfo/xml-sig