Libraries for Subliminal
This commit is contained in:
@@ -0,0 +1,216 @@
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the (LGPL) GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 3 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 Library Lesser General Public License for more details at
|
||||
# ( http://www.gnu.org/licenses/lgpl.html ).
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
# written by: Jeff Ortel ( jortel@redhat.com )
|
||||
|
||||
"""
|
||||
Provides base classes for XML->object I{unmarshalling}.
|
||||
"""
|
||||
|
||||
from logging import getLogger
|
||||
from suds import *
|
||||
from suds.umx import *
|
||||
from suds.umx.attrlist import AttrList
|
||||
from suds.sax.text import Text
|
||||
from suds.sudsobject import Factory, merge
|
||||
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
reserved = { 'class':'cls', 'def':'dfn', }
|
||||
|
||||
class Core:
|
||||
"""
|
||||
The abstract XML I{node} unmarshaller. This class provides the
|
||||
I{core} unmarshalling functionality.
|
||||
"""
|
||||
|
||||
def process(self, content):
|
||||
"""
|
||||
Process an object graph representation of the xml I{node}.
|
||||
@param content: The current content being unmarshalled.
|
||||
@type content: L{Content}
|
||||
@return: A suds object.
|
||||
@rtype: L{Object}
|
||||
"""
|
||||
self.reset()
|
||||
return self.append(content)
|
||||
|
||||
def append(self, content):
|
||||
"""
|
||||
Process the specified node and convert the XML document into
|
||||
a I{suds} L{object}.
|
||||
@param content: The current content being unmarshalled.
|
||||
@type content: L{Content}
|
||||
@return: A I{append-result} tuple as: (L{Object}, I{value})
|
||||
@rtype: I{append-result}
|
||||
@note: This is not the proper entry point.
|
||||
@see: L{process()}
|
||||
"""
|
||||
self.start(content)
|
||||
self.append_attributes(content)
|
||||
self.append_children(content)
|
||||
self.append_text(content)
|
||||
self.end(content)
|
||||
return self.postprocess(content)
|
||||
|
||||
def postprocess(self, content):
|
||||
"""
|
||||
Perform final processing of the resulting data structure as follows:
|
||||
- Mixed values (children and text) will have a result of the I{content.node}.
|
||||
- Simi-simple values (attributes, no-children and text) will have a result of a
|
||||
property object.
|
||||
- Simple values (no-attributes, no-children with text nodes) will have a string
|
||||
result equal to the value of the content.node.getText().
|
||||
@param content: The current content being unmarshalled.
|
||||
@type content: L{Content}
|
||||
@return: The post-processed result.
|
||||
@rtype: I{any}
|
||||
"""
|
||||
node = content.node
|
||||
if len(node.children) and node.hasText():
|
||||
return node
|
||||
attributes = AttrList(node.attributes)
|
||||
if attributes.rlen() and \
|
||||
not len(node.children) and \
|
||||
node.hasText():
|
||||
p = Factory.property(node.name, node.getText())
|
||||
return merge(content.data, p)
|
||||
if len(content.data):
|
||||
return content.data
|
||||
lang = attributes.lang()
|
||||
if content.node.isnil():
|
||||
return None
|
||||
if not len(node.children) and content.text is None:
|
||||
if self.nillable(content):
|
||||
return None
|
||||
else:
|
||||
return Text('', lang=lang)
|
||||
if isinstance(content.text, basestring):
|
||||
return Text(content.text, lang=lang)
|
||||
else:
|
||||
return content.text
|
||||
|
||||
def append_attributes(self, content):
|
||||
"""
|
||||
Append attribute nodes into L{Content.data}.
|
||||
Attributes in the I{schema} or I{xml} namespaces are skipped.
|
||||
@param content: The current content being unmarshalled.
|
||||
@type content: L{Content}
|
||||
"""
|
||||
attributes = AttrList(content.node.attributes)
|
||||
for attr in attributes.real():
|
||||
name = attr.name
|
||||
value = attr.value
|
||||
self.append_attribute(name, value, content)
|
||||
|
||||
def append_attribute(self, name, value, content):
|
||||
"""
|
||||
Append an attribute name/value into L{Content.data}.
|
||||
@param name: The attribute name
|
||||
@type name: basestring
|
||||
@param value: The attribute's value
|
||||
@type value: basestring
|
||||
@param content: The current content being unmarshalled.
|
||||
@type content: L{Content}
|
||||
"""
|
||||
key = name
|
||||
key = '_%s' % reserved.get(key, key)
|
||||
setattr(content.data, key, value)
|
||||
|
||||
def append_children(self, content):
|
||||
"""
|
||||
Append child nodes into L{Content.data}
|
||||
@param content: The current content being unmarshalled.
|
||||
@type content: L{Content}
|
||||
"""
|
||||
for child in content.node:
|
||||
cont = Content(child)
|
||||
cval = self.append(cont)
|
||||
key = reserved.get(child.name, child.name)
|
||||
if key in content.data:
|
||||
v = getattr(content.data, key)
|
||||
if isinstance(v, list):
|
||||
v.append(cval)
|
||||
else:
|
||||
setattr(content.data, key, [v, cval])
|
||||
continue
|
||||
if self.unbounded(cont):
|
||||
if cval is None:
|
||||
setattr(content.data, key, [])
|
||||
else:
|
||||
setattr(content.data, key, [cval,])
|
||||
else:
|
||||
setattr(content.data, key, cval)
|
||||
|
||||
def append_text(self, content):
|
||||
"""
|
||||
Append text nodes into L{Content.data}
|
||||
@param content: The current content being unmarshalled.
|
||||
@type content: L{Content}
|
||||
"""
|
||||
if content.node.hasText():
|
||||
content.text = content.node.getText()
|
||||
|
||||
def reset(self):
|
||||
pass
|
||||
|
||||
def start(self, content):
|
||||
"""
|
||||
Processing on I{node} has started. Build and return
|
||||
the proper object.
|
||||
@param content: The current content being unmarshalled.
|
||||
@type content: L{Content}
|
||||
@return: A subclass of Object.
|
||||
@rtype: L{Object}
|
||||
"""
|
||||
content.data = Factory.object(content.node.name)
|
||||
|
||||
def end(self, content):
|
||||
"""
|
||||
Processing on I{node} has ended.
|
||||
@param content: The current content being unmarshalled.
|
||||
@type content: L{Content}
|
||||
"""
|
||||
pass
|
||||
|
||||
def bounded(self, content):
|
||||
"""
|
||||
Get whether the content is bounded (not a list).
|
||||
@param content: The current content being unmarshalled.
|
||||
@type content: L{Content}
|
||||
@return: True if bounded, else False
|
||||
@rtype: boolean
|
||||
'"""
|
||||
return ( not self.unbounded(content) )
|
||||
|
||||
def unbounded(self, content):
|
||||
"""
|
||||
Get whether the object is unbounded (a list).
|
||||
@param content: The current content being unmarshalled.
|
||||
@type content: L{Content}
|
||||
@return: True if unbounded, else False
|
||||
@rtype: boolean
|
||||
'"""
|
||||
return False
|
||||
|
||||
def nillable(self, content):
|
||||
"""
|
||||
Get whether the object is nillable.
|
||||
@param content: The current content being unmarshalled.
|
||||
@type content: L{Content}
|
||||
@return: True if nillable, else False
|
||||
@rtype: boolean
|
||||
'"""
|
||||
return False
|
||||
Reference in New Issue
Block a user