########################################################################
# $Header: /var/local/cvsroot/4Suite/Ft/Xml/XPath/Conversions.py,v 1.16 2005/08/09 15:24:01 uogbuji Exp $
"""
The implementation of the XPath object type conversions.
Copyright 2000-2005 Fourthought, Inc. (USA).
Detailed license and copyright information: http://4suite.org/COPYRIGHT
Project home, documentation, distributions: http://4suite.org/
"""
import types
from xml.dom import Node
from Ft.Lib import number,boolean
StringValue = lambda obj: _strConversions.get(type(obj), _strUnknown)(obj)
NumberValue = lambda obj: _numConversions.get(type(obj), _numUnknown)(obj)
BooleanValue = lambda obj: _boolConversions.get(type(obj), _boolUnknown)(obj)
# -- String Conversions ----------------------------------------------
def _strUnknown(obj):
# Allow for non-instance DOM node objects
if hasattr(obj, 'nodeType'):
# Add this type to the mapping for next time through
_strConversions[type(obj)] = _strInstance
return _strInstance(obj)
return u''
def _strInstance(obj):
if hasattr(obj, 'stringValue'):
return obj.stringValue
elif hasattr(obj, 'nodeType'):
node_type = obj.nodeType
if node_type in [Node.ELEMENT_NODE, Node.DOCUMENT_NODE]:
# The concatenation of all text descendants
text_elem_children = filter(lambda x:
x.nodeType in [Node.TEXT_NODE, Node.ELEMENT_NODE],
obj.childNodes)
return reduce(lambda x, y: StringValue(x) + StringValue(y),
text_elem_children,
'')
if node_type in [Node.ATTRIBUTE_NODE, NAMESPACE_NODE]:
return obj.value
if node_type in [Node.PROCESSING_INSTRUCTION_NODE, Node.COMMENT_NODE, Node.TEXT_NODE]:
return obj.data
return u''
def _strFloat(float):
if number.finite(float):
if float == round(float):
return unicode(str(long(float)))
else:
# 12 digits is how many Python uses for str()
return u'%0.12g' % float
elif number.isnan(float):
return u'NaN'
elif float < 0:
return u'-Infinity'
else:
return u'Infinity'
_strConversions = {
str : unicode,
unicode : unicode,
int : lambda i: unicode(str(i)),
long : lambda l: unicode(str(l)),
float : _strFloat,
boolean.BooleanType : lambda b: unicode(str(b)),
types.InstanceType : _strInstance,
list : lambda x: x and _strConversions.get(type(x[0]), _strUnknown)(x[0]) or u'',
}
# -- Number Conversions ----------------------------------------------
def _numString(string):
try:
# From XPath 1.0, sect 4.4 - number():
# Any string that does not match "S? '-'? Number" is converted to NaN
# S ::= [\x20\x09\x0A\x0D]*
# Digits ::= [0-9]+
# Number ::= Digits ('.' Digits?)? | '.' Digits
return float(string)
except:
# Many platforms seem to have a problem with strtod('nan'),
# reported on Windows and FreeBSD
return number.nan
_numUnknown = lambda obj: _numString(StringValue(obj))
_numConversions = {
int : float,
long : float,
float : float,
boolean.BooleanType : float,
str : _numString,
unicode : _numString,
}
# -- Boolean Conversions ---------------------------------------------
_boolConversions = {
boolean.BooleanType : boolean.bool,
int : boolean.bool,
long : boolean.bool,
float : boolean.bool,
str : boolean.bool,
unicode : boolean.bool,
list : boolean.bool,
}
_boolUnknown = lambda obj: boolean.bool(StringValue(obj))
try:
# Use C optimized functions, if available
from _conversions import *
except:
from Ft.Xml.XPath import NAMESPACE_NODE
|