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.
 
 
 

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