You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

336 lines
11 KiB

  1. # Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
  2. #
  3. # This software is subject to the provisions of the Zope Public License,
  4. # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
  5. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
  6. # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  7. # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
  8. # FOR A PARTICULAR PURPOSE.
  9. ident = "$Id$"
  10. import string, types, base64, re
  11. from Utility import DOM, Collection
  12. from StringIO import StringIO
  13. class SchemaReader:
  14. """A SchemaReader creates XMLSchema objects from urls and xml data."""
  15. def loadFromStream(self, file):
  16. """Return an XMLSchema instance loaded from a file object."""
  17. document = DOM.loadDocument(file)
  18. schema = XMLSchema()
  19. schema.load(document)
  20. return schema
  21. def loadFromString(self, data):
  22. """Return an XMLSchema instance loaded from an xml string."""
  23. return self.loadFromStream(StringIO(data))
  24. def loadFromURL(self, url):
  25. """Return an XMLSchema instance loaded from the given url."""
  26. document = DOM.loadFromURL(url)
  27. schema = XMLSchema()
  28. schema.location = url
  29. schema.load(document)
  30. return schema
  31. def loadFromFile(self, filename):
  32. """Return an XMLSchema instance loaded from the given file."""
  33. file = open(filename, 'rb')
  34. try: schema = self.loadFromStream(file)
  35. finally: file.close()
  36. return schema
  37. class SchemaError(Exception):
  38. pass
  39. class XMLSchema:
  40. # This is temporary, for the benefit of WSDL until the real thing works.
  41. def __init__(self, element):
  42. self.targetNamespace = DOM.getAttr(element, 'targetNamespace')
  43. self.element = element
  44. class realXMLSchema:
  45. """A schema is a collection of schema components derived from one
  46. or more schema documents, that is, one or more <schema> element
  47. information items. It represents the abstract notion of a schema
  48. rather than a single schema document (or other representation)."""
  49. def __init__(self):
  50. self.simpleTypes = Collection(self)
  51. self.complexTypes = Collection(self)
  52. self.attributes = Collection(self)
  53. self.elements = Collection(self)
  54. self.attrGroups = Collection(self)
  55. self.idConstraints=None
  56. self.modelGroups = None
  57. self.notations = None
  58. self.extensions = []
  59. targetNamespace = None
  60. attributeFormDefault = 'unqualified'
  61. elementFormDefault = 'unqualified'
  62. blockDefault = None
  63. finalDefault = None
  64. location = None
  65. version = None
  66. id = None
  67. def load(self, document):
  68. if document.nodeType == document.DOCUMENT_NODE:
  69. schema = DOM.getElement(document, 'schema', None, None)
  70. else:
  71. schema = document
  72. if schema is None:
  73. raise SchemaError('Missing <schema> element.')
  74. self.namespace = namespace = schema.namespaceURI
  75. if not namespace in DOM.NS_XSD_ALL:
  76. raise SchemaError(
  77. 'Unknown XML schema namespace: %s.' % self.namespace
  78. )
  79. for attrname in (
  80. 'targetNamespace', 'attributeFormDefault', 'elementFormDefault',
  81. 'blockDefault', 'finalDefault', 'version', 'id'
  82. ):
  83. value = DOM.getAttr(schema, attrname, None, None)
  84. if value is not None:
  85. setattr(self, attrname, value)
  86. # Resolve imports and includes here?
  87. ## imported = {}
  88. ## while 1:
  89. ## imports = []
  90. ## for element in DOM.getElements(definitions, 'import', NS_WSDL):
  91. ## location = DOM.getAttr(element, 'location')
  92. ## if not imported.has_key(location):
  93. ## imports.append(element)
  94. ## if not imports:
  95. ## break
  96. ## for element in imports:
  97. ## self._import(document, element)
  98. ## imported[location] = 1
  99. for element in DOM.getElements(schema, None, None):
  100. localName = element.localName
  101. if not DOM.nsUriMatch(element.namespaceURI, namespace):
  102. self.extensions.append(element)
  103. continue
  104. elif localName == 'message':
  105. name = DOM.getAttr(element, 'name')
  106. docs = GetDocumentation(element)
  107. message = self.addMessage(name, docs)
  108. parts = DOM.getElements(element, 'part', NS_WSDL)
  109. message.load(parts)
  110. continue
  111. def _import(self, document, element):
  112. namespace = DOM.getAttr(element, 'namespace', default=None)
  113. location = DOM.getAttr(element, 'location', default=None)
  114. if namespace is None or location is None:
  115. raise WSDLError(
  116. 'Invalid import element (missing namespace or location).'
  117. )
  118. # Sort-of support relative locations to simplify unit testing. The
  119. # WSDL specification actually doesn't allow relative URLs, so its
  120. # ok that this only works with urls relative to the initial document.
  121. location = urllib.basejoin(self.location, location)
  122. obimport = self.addImport(namespace, location)
  123. obimport._loaded = 1
  124. importdoc = DOM.loadFromURL(location)
  125. try:
  126. if location.find('#') > -1:
  127. idref = location.split('#')[-1]
  128. imported = DOM.getElementById(importdoc, idref)
  129. else:
  130. imported = importdoc.documentElement
  131. if imported is None:
  132. raise WSDLError(
  133. 'Import target element not found for: %s' % location
  134. )
  135. imported_tns = DOM.getAttr(imported, 'targetNamespace')
  136. importer_tns = namespace
  137. if imported_tns != importer_tns:
  138. return
  139. if imported.localName == 'definitions':
  140. imported_nodes = imported.childNodes
  141. else:
  142. imported_nodes = [imported]
  143. parent = element.parentNode
  144. for node in imported_nodes:
  145. if node.nodeType != node.ELEMENT_NODE:
  146. continue
  147. child = DOM.importNode(document, node, 1)
  148. parent.appendChild(child)
  149. child.setAttribute('targetNamespace', importer_tns)
  150. attrsNS = imported._attrsNS
  151. for attrkey in attrsNS.keys():
  152. if attrkey[0] == DOM.NS_XMLNS:
  153. attr = attrsNS[attrkey].cloneNode(1)
  154. child.setAttributeNode(attr)
  155. finally:
  156. importdoc.unlink()
  157. class Element:
  158. """Common base class for element representation classes."""
  159. def __init__(self, name=None, documentation=''):
  160. self.name = name
  161. self.documentation = documentation
  162. self.extensions = []
  163. def addExtension(self, item):
  164. self.extensions.append(item)
  165. class SimpleTypeDefinition:
  166. """Represents an xml schema simple type definition."""
  167. class ComplexTypeDefinition:
  168. """Represents an xml schema complex type definition."""
  169. class AttributeDeclaration:
  170. """Represents an xml schema attribute declaration."""
  171. class ElementDeclaration:
  172. """Represents an xml schema element declaration."""
  173. def __init__(self, name, type=None, targetNamespace=None):
  174. self.name = name
  175. targetNamespace = None
  176. annotation = None
  177. nillable = 0
  178. abstract = 0
  179. default = None
  180. fixed = None
  181. scope = 'global'
  182. type = None
  183. form = 0
  184. # Things we will not worry about for now.
  185. id_constraint_defs = None
  186. sub_group_exclude = None
  187. sub_group_affils = None
  188. disallowed_subs = None
  189. class AttributeGroupDefinition:
  190. """Represents an xml schema attribute group definition."""
  191. class IdentityConstraintDefinition:
  192. """Represents an xml schema identity constraint definition."""
  193. class ModelGroupDefinition:
  194. """Represents an xml schema model group definition."""
  195. class NotationDeclaration:
  196. """Represents an xml schema notation declaration."""
  197. class Annotation:
  198. """Represents an xml schema annotation."""
  199. class ModelGroup:
  200. """Represents an xml schema model group."""
  201. class Particle:
  202. """Represents an xml schema particle."""
  203. class WildCard:
  204. """Represents an xml schema wildcard."""
  205. class AttributeUse:
  206. """Represents an xml schema attribute use."""
  207. class ElementComponent:
  208. namespace = ''
  209. name = ''
  210. type = None
  211. form = 'qualified | unqualified'
  212. scope = 'global or complex def'
  213. constraint = ('value', 'default | fixed')
  214. nillable = 0
  215. id_constraint_defs = None
  216. sub_group_affil = None
  217. sub_group_exclusions = None
  218. disallowed_subs = 'substitution, extension, restriction'
  219. abstract = 0
  220. minOccurs = 1
  221. maxOccurs = 1
  222. ref = ''
  223. class AttributeThing:
  224. name = ''
  225. namespace = ''
  226. typeName = ''
  227. typeUri = ''
  228. scope = 'global | local to complex def'
  229. constraint = ('value:default', 'value:fixed')
  230. use = 'optional | prohibited | required'
  231. class ElementDataType:
  232. namespace = ''
  233. name = ''
  234. element_form = 'qualified | unqualified'
  235. attr_form = None
  236. type_name = ''
  237. type_uri = ''
  238. def __init__(self, name, namespace, type_name, type_uri):
  239. self.namespace = namespace
  240. self.name = name
  241. # type may be anonymous...
  242. self.type_name = type_name
  243. self.type_uri = type_uri
  244. def checkValue(self, value, context):
  245. # Delegate value checking to the type of the element.
  246. typeref = (self.type_uri, self.type_name)
  247. handler = context.serializer.getType(typeref)
  248. return handler.checkValue(value, context)
  249. def serialize(self, name, namespace, value, context, **kwargs):
  250. if context.check_values:
  251. self.checkValue(value, context)
  252. # Delegate serialization to the type of the element.
  253. typeref = (self.type_uri, self.type_name)
  254. handler = context.serializer.getType(typeref)
  255. return handler.serialize(self.name, self.namespace, value, context)
  256. def deserialize(self, element, context):
  257. if element_is_null(element, context):
  258. return None
  259. # Delegate deserialization to the type of the element.
  260. typeref = (self.type_uri, self.type_name)
  261. handler = context.serializer.getType(typeref)
  262. return handler.deserialize(element, context)
  263. def parse_schema(data):
  264. targetNS = ''
  265. attributeFormDefault = 0
  266. elementFormDefault = 0
  267. blockDefault = ''
  268. finalDefault = ''
  269. language = None
  270. version = None
  271. id = ''