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 - [email protected]
http://mail.python.org/mailman/listinfo/xml-sig