1# This program is free software; you can redistribute it and/or modify 2# it under the terms of the (LGPL) GNU Lesser General Public License as 3# published by the Free Software Foundation; either version 3 of the 4# License, or (at your option) any later version. 5# 6# This program is distributed in the hope that it will be useful, 7# but WITHOUT ANY WARRANTY; without even the implied warranty of 8# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9# GNU Library Lesser General Public License for more details at 10# ( http://www.gnu.org/licenses/lgpl.html ). 11# 12# You should have received a copy of the GNU Lesser General Public License 13# along with this program; if not, write to the Free Software 14# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 15# written by: Jeff Ortel ( jortel@redhat.com ) 16 17""" 18Provides sx typing classes. 19""" 20 21from suds import * 22from suds.mx import * 23from suds.sax import Namespace as NS 24from suds.sax.text import Text 25 26 27class Typer: 28 """ 29 Provides XML node typing as either automatic or manual. 30 @cvar types: A dict of class to xs type mapping. 31 @type types: dict 32 """ 33 34 types = { 35 int : ('int', NS.xsdns), 36 long : ('long', NS.xsdns), 37 float : ('float', NS.xsdns), 38 str : ('string', NS.xsdns), 39 unicode : ('string', NS.xsdns), 40 Text : ('string', NS.xsdns), 41 bool : ('boolean', NS.xsdns), 42 } 43 44 @classmethod 45 def auto(cls, node, value=None): 46 """ 47 Automatically set the node's xsi:type attribute based on either I{value}'s 48 class or the class of the node's text. When I{value} is an unmapped class, 49 the default type (xs:any) is set. 50 @param node: An XML node 51 @type node: L{sax.element.Element} 52 @param value: An object that is or would be the node's text. 53 @type value: I{any} 54 @return: The specified node. 55 @rtype: L{sax.element.Element} 56 """ 57 if value is None: 58 value = node.getText() 59 if isinstance(value, Object): 60 known = cls.known(value) 61 if known.name is None: 62 return node 63 tm = (known.name, known.namespace()) 64 else: 65 tm = cls.types.get(value.__class__, cls.types.get(str)) 66 cls.manual(node, *tm) 67 return node 68 69 @classmethod 70 def manual(cls, node, tval, ns=None): 71 """ 72 Set the node's xsi:type attribute based on either I{value}'s 73 class or the class of the node's text. Then adds the referenced 74 prefix(s) to the node's prefix mapping. 75 @param node: An XML node 76 @type node: L{sax.element.Element} 77 @param tval: The name of the schema type. 78 @type tval: str 79 @param ns: The XML namespace of I{tval}. 80 @type ns: (prefix, uri) 81 @return: The specified node. 82 @rtype: L{sax.element.Element} 83 """ 84 xta = ':'.join((NS.xsins[0], 'type')) 85 node.addPrefix(NS.xsins[0], NS.xsins[1]) 86 if ns is None: 87 node.set(xta, tval) 88 else: 89 ns = cls.genprefix(node, ns) 90 qname = ':'.join((ns[0], tval)) 91 node.set(xta, qname) 92 node.addPrefix(ns[0], ns[1]) 93 return node 94 95 @classmethod 96 def genprefix(cls, node, ns): 97 """ 98 Generate a prefix. 99 @param node: An XML node on which the prefix will be used. 100 @type node: L{sax.element.Element} 101 @param ns: A namespace needing an unique prefix. 102 @type ns: (prefix, uri) 103 @return: The I{ns} with a new prefix. 104 """ 105 for n in range(1, 1024): 106 p = 'ns%d' % n 107 u = node.resolvePrefix(p, default=None) 108 if u is None or u == ns[1]: 109 return (p, ns[1]) 110 raise Exception('auto prefix, exhausted') 111 112 @classmethod 113 def known(cls, object): 114 try: 115 md = object.__metadata__ 116 known = md.sxtype 117 return known 118 except: 119 pass 120