def parse_imports(self, doc): """Import other WSDL definitions in this document. Note that imports are non-transitive, so only import definitions which are defined in the imported document and ignore definitions imported in that document. This should handle recursive imports though: A -> B -> A A -> B -> C -> A :param doc: The source document :type doc: lxml.etree._Element """ for import_node in doc.findall("wsdl:import", namespaces=NSMAP): location = import_node.get('location') namespace = import_node.get('namespace') if namespace in self.wsdl._definitions: self.imports[namespace] = self.wsdl._definitions[namespace] else: document = self.wsdl._load_content(location) location = absolute_location(location, self.location) if etree.QName(document.tag).localname == 'schema': self.types.add_documents([document], location) else: wsdl = Definition(self.wsdl, document, location) self.imports[namespace] = wsdl
def visit_import(self, node, parent): """ <import id = ID namespace = anyURI schemaLocation = anyURI {any attributes with non-schema Namespace}...> Content: (annotation?) </import> """ if not node.get('schemaLocation'): raise NotImplementedError("schemaLocation is required") namespace = node.get('namespace') location = node.get('schemaLocation') # Resolve import if it is a file location = absolute_location(location, self.schema._location) schema = self.parser_context.schema_objects.get(location) if schema: logger.debug("Returning existing schema: %r", location) self.schema._imports[namespace] = schema return schema schema_node = load_external( location, self.schema._transport, self.parser_context) schema = self.schema.__class__( schema_node, self.schema._transport, location, self.parser_context) self.schema._imports[namespace] = schema return schema
def visit_import(self, node, parent): """ <import id = ID namespace = anyURI schemaLocation = anyURI {any attributes with non-schema Namespace}...> Content: (annotation?) </import> """ if not node.get('schemaLocation'): raise NotImplementedError("schemaLocation is required") namespace = node.get('namespace') location = node.get('schemaLocation') # Resolve import if it is a file location = absolute_location(location, self.schema._location) schema = self.parser_context.schema_objects.get(location) if schema: logger.debug("Returning existing schema: %r", location) self.schema._imports[namespace] = schema return schema schema_node = load_external(location, self.schema._transport, self.parser_context) schema = self.schema.__class__(schema_node, self.schema._transport, location, self.parser_context) self.schema._imports[namespace] = schema return schema
def load_external(url, transport, parser_context=None, base_url=None): if url.startswith('intschema'): assert parser_context return parser_context.schema_nodes.get(url) if base_url: url = absolute_location(url, base_url) response = transport.load(url) return parse_xml(response, transport, parser_context, base_url)
def visit_import(self, node, parent): """ <import id = ID namespace = anyURI schemaLocation = anyURI {any attributes with non-schema Namespace}...> Content: (annotation?) </import> """ namespace = node.get('namespace') location = node.get('schemaLocation') schema_node = None # Check if a schemaLocation is defined, if it isn't perhaps the # namespaces references to an internal xml schema. Otherwise we just # raise an error for now. if not location: if namespace: location = namespace try: schema_node = self.parser_context.schema_nodes.get(namespace) except KeyError: raise ValueError("No schema for namespace=%s" % namespace) if not schema_node: raise ValueError("schemaLocation is required") # If a schemaLocation is defined then make the location absolute based # on the base url and see if the schema is already processed (for # cyclic schema references). Otherwise load the data. else: location = absolute_location(location, self.schema._base_url) schema = self.parser_context.schema_objects.get(location) if schema: logger.debug("Returning existing schema: %r", location) self.schema._imports[namespace] = schema return schema schema_node = load_external( location, self.schema._transport, self.parser_context) # If this schema location is 'internal' then retrieve the original # location since that is used as base url for sub include/imports if location in self.parser_context.schema_locations: base_url = self.parser_context.schema_locations[location] else: base_url = location schema = self.schema.__class__( schema_node, self.schema._transport, location, self.parser_context, base_url) self.schema._imports[namespace] = schema return schema
def visit_import(self, node, parent): """ <import id = ID namespace = anyURI schemaLocation = anyURI {any attributes with non-schema Namespace}...> Content: (annotation?) </import> """ namespace = node.get('namespace') location = node.get('schemaLocation') # Use namespace as location if the schemaLocation is missing if not location: if namespace: location = namespace else: raise NotImplementedError("schemaLocation is required") # Resolve import if it is a file location = absolute_location(location, self.schema._base_url) schema = self.parser_context.schema_objects.get(location) if schema: logger.debug("Returning existing schema: %r", location) self.schema._imports[namespace] = schema return schema schema_node = load_external( location, self.schema._transport, self.parser_context) # If this schema location is 'internal' then retrieve the original # location since that is used as base url for sub include/imports if location in self.parser_context.schema_locations: base_url = self.parser_context.schema_locations[location] else: base_url = location schema = self.schema.__class__( schema_node, self.schema._transport, location, self.parser_context, base_url) self.schema._imports[namespace] = schema return schema
def visit_import(self, node, parent): """ <import id = ID namespace = anyURI schemaLocation = anyURI {any attributes with non-schema Namespace}...> Content: (annotation?) </import> """ schema_node = None namespace = node.get('namespace') location = node.get('schemaLocation') if location: location = absolute_location(location, self.document._base_url) if not namespace and not self.document._target_namespace: raise XMLParseError( "The attribute 'namespace' must be existent if the " "importing schema has no target namespace.") # Check if the schema is already imported before based on the # namespace. Schema's without namespace are registered as 'None' schema = self.parser_context.schema_objects.get(namespace) if schema: if location and schema._location != location: # Use same warning message as libxml2 message = ( "Skipping import of schema located at %r " + "for the namespace %r, since the namespace was " + "already imported with the schema located at %r" ) % (location, namespace or '(null)', schema._location) warnings.warn(message, ZeepWarning, stacklevel=6) return logger.debug("Returning existing schema: %r", location) self.document._imports[namespace] = schema return schema # Hardcode the mapping between the xml namespace and the xsd for now. # This seems to fix issues with exchange wsdl's, see #220 if not location and namespace == 'http://www.w3.org/XML/1998/namespace': location = 'https://www.w3.org/2001/xml.xsd' # Silently ignore import statements which we can't resolve via the # namespace and doesn't have a schemaLocation attribute. if not location: logger.debug( "Ignoring import statement for namespace %r " + "(missing schemaLocation)", namespace) return # Load the XML schema_node = load_external( location, self.document._transport, self.parser_context) # Check if the xsd:import namespace matches the targetNamespace. If # the xsd:import statement didn't specify a namespace then make sure # that the targetNamespace wasn't declared by another schema yet. schema_tns = schema_node.get('targetNamespace') if namespace and schema_tns and namespace != schema_tns: raise XMLParseError(( "The namespace defined on the xsd:import doesn't match the " "imported targetNamespace located at %r " ) % (location)) elif schema_tns in self.parser_context.schema_objects: schema = self.parser_context.schema_objects.get(schema_tns) message = ( "Skipping import of schema located at %r " + "for the namespace %r, since the namespace was " + "already imported with the schema located at %r" ) % (location, namespace or '(null)', schema._location) warnings.warn(message, ZeepWarning, stacklevel=6) # If this schema location is 'internal' then retrieve the original # location since that is used as base url for sub include/imports if location in self.parser_context.schema_locations: base_url = self.parser_context.schema_locations[location] else: base_url = location schema = self.document.__class__( schema_node, self.document._transport, self.schema, location, self.parser_context, base_url) self.document._imports[namespace] = schema return schema
def visit_import(self, node, parent): """ <import id = ID namespace = anyURI schemaLocation = anyURI {any attributes with non-schema Namespace}...> Content: (annotation?) </import> """ schema_node = None namespace = node.get('namespace') location = node.get('schemaLocation') if location: location = absolute_location(location, self.document._base_url) if not namespace and not self.document._target_namespace: raise XMLParseError( "The attribute 'namespace' must be existent if the " "importing schema has no target namespace.", filename=self._document.location, sourceline=node.sourceline) # Check if the schema is already imported before based on the # namespace. Schema's without namespace are registered as 'None' document = self.schema._get_schema_document(namespace, location) if document: logger.debug("Returning existing schema: %r", location) self.document.register_import(namespace, document) return document # Hardcode the mapping between the xml namespace and the xsd for now. # This seems to fix issues with exchange wsdl's, see #220 if not location and namespace == 'http://www.w3.org/XML/1998/namespace': location = 'https://www.w3.org/2001/xml.xsd' # Silently ignore import statements which we can't resolve via the # namespace and doesn't have a schemaLocation attribute. if not location: logger.debug( "Ignoring import statement for namespace %r " + "(missing schemaLocation)", namespace) return # Load the XML schema_node = load_external(location, self.schema._transport) # Check if the xsd:import namespace matches the targetNamespace. If # the xsd:import statement didn't specify a namespace then make sure # that the targetNamespace wasn't declared by another schema yet. schema_tns = schema_node.get('targetNamespace') if namespace and schema_tns and namespace != schema_tns: raise XMLParseError( ("The namespace defined on the xsd:import doesn't match the " "imported targetNamespace located at %r ") % (location), filename=self.document._location, sourceline=node.sourceline) schema = self.schema.create_new_document(schema_node, location) self.document.register_import(namespace, schema) return schema
def load_external(url, transport, base_url=None): if base_url: url = absolute_location(url, base_url) response = transport.load(url) return parse_xml(response, transport, base_url)
def visit_import(self, node, parent): """ <import id = ID namespace = anyURI schemaLocation = anyURI {any attributes with non-schema Namespace}...> Content: (annotation?) </import> """ schema_node = None namespace = node.get('namespace') location = node.get('schemaLocation') if location: location = absolute_location(location, self.schema._base_url) if not namespace and not self.schema._target_namespace: raise XMLParseError( "The attribute 'namespace' must be existent if the " "importing schema has no target namespace.") # Check if the schema is already imported before based on the # namespace. Schema's without namespace are registered as 'None' schema = self.parser_context.schema_objects.get(namespace) if schema: if location and schema._location != location: # Use same warning message as libxml2 message = ("Skipping import of schema located at %r " + "for the namespace %r, since the namespace was " + "already imported with the schema located at %r" ) % (location, namespace or '(null)', schema._location) warnings.warn(message, ZeepWarning, stacklevel=6) return logger.debug("Returning existing schema: %r", location) self.schema._imports[namespace] = schema return schema # Silently ignore import statements which we can't resolve via the # namespace and doesn't have a schemaLocation attribute. if not location: logger.debug( "Ignoring import statement for namespace %r " + "(missing schemaLocation)", namespace) return # Load the XML schema_node = load_external(location, self.schema._transport, self.parser_context) # Check if the xsd:import namespace matches the targetNamespace. If # the xsd:import statement didn't specify a namespace then make sure # that the targetNamespace wasn't declared by another schema yet. schema_tns = schema_node.get('targetNamespace') if namespace and schema_tns and namespace != schema_tns: raise XMLParseError( ("The namespace defined on the xsd:import doesn't match the " "imported targetNamespace located at %r ") % (location)) elif schema_tns in self.parser_context.schema_objects: schema = self.parser_context.schema_objects.get(schema_tns) message = ("Skipping import of schema located at %r " + "for the namespace %r, since the namespace was " + "already imported with the schema located at %r") % ( location, namespace or '(null)', schema._location) warnings.warn(message, ZeepWarning, stacklevel=6) # If this schema location is 'internal' then retrieve the original # location since that is used as base url for sub include/imports if location in self.parser_context.schema_locations: base_url = self.parser_context.schema_locations[location] else: base_url = location schema = self.schema.__class__(schema_node, self.schema._transport, location, self.parser_context, base_url) self.schema._imports[namespace] = schema return schema
def visit_import(self, node, parent): """ <import id = ID namespace = anyURI schemaLocation = anyURI {any attributes with non-schema Namespace}...> Content: (annotation?) </import> """ schema_node = None namespace = node.get('namespace') location = node.get('schemaLocation') if location: location = absolute_location(location, self.schema._base_url) if not namespace and not self.schema._target_namespace: raise XMLParseError( "The attribute 'namespace' must be existent if the " "importing schema has no target namespace.") # Check if the schema is already imported before based on the # namespace. Schema's without namespace are registered as 'None' schema = self.parser_context.schema_objects.get(namespace) if schema: if location and schema._location != location: # Raise same error message as libxml2 raise XMLParseError(( "Conflicting import of schema located at %r " + "for the namespace %r, since the namespace was " + "already imported with the schema located at %r" ) % (location, namespace or '(null)', schema._location)) return logger.debug("Returning existing schema: %r", location) self.schema._imports[namespace] = schema return schema # Check if if the namespace references an internal schema. Internal # schema's are created for multiple xsd:schema definitions in a wsdl try: schema_node = self.parser_context.schema_nodes.get(namespace) except KeyError: pass # Silently ignore import statements which we can't resolve via the # namespace and doesn't have a schemaLocation attribute. if not location: logger.debug( "Ignoring import statement for namespace %r " + "(missing schemaLocation)", namespace) return # Load the XML schema_node = load_external( location, self.schema._transport, self.parser_context) # Check if the xsd:import namespace matches the targetNamespace. If # the xsd:import statement didn't specify a namespace then make sure # that the targetNamespace wasn't declared by another schema yet. schema_tns = schema_node.get('targetNamespace') if namespace and schema_tns and namespace != schema_tns: raise XMLParseError(( "The namespace defined on the xsd:import doesn't match the " "imported targetNamespace located at %r " ) % (location)) elif schema_tns in self.parser_context.schema_objects: schema = self.parser_context.schema_objects.get(schema_tns) raise XMLParseError(( "Conflicting import of schema located at %r " + "for the namespace %r, since the namespace was " + "already imported with the schema located at %r" ) % (location, namespace or '(null)', schema._location)) # If this schema location is 'internal' then retrieve the original # location since that is used as base url for sub include/imports if location in self.parser_context.schema_locations: base_url = self.parser_context.schema_locations[location] else: base_url = location schema = self.schema.__class__( schema_node, self.schema._transport, location, self.parser_context, base_url) self.schema._imports[namespace] = schema return schema