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