savonrb / wasabi

A simple WSDL parser
MIT License
90 stars 84 forks source link

wasabi seems to ignore choices #104

Open hadmut opened 3 years ago

hadmut commented 3 years ago

Hi, I'm currenty trying to debug a soap error where the ruby lib savon uses the wrong namespace for soap request elements, if these elements are part of a choice in the wsdl. Actually, savon does not parse the wsdl by itself, but uses wasabi, and then does not find the element in wasabis list of type definitions and namespaces.

Example:

wsdl = Wasabi::Document.new('https://tom.vgwort.de/services/1.0/authorMessageService.wsdl')

then most elements defined in this wsdl can be found in wsdl.type_definitions or wsdl.type_namespaces

except for those within choices, i.e. the elements pdf, plainText, and epub in the given example. Since savon can't find them in the list, it uses the wrong namespaces.

wasabi doesn't seem to cope at all with choice elements, although it is a valid xml schema element: https://www.w3schools.com/xml/el_choice.asp

regards Hadmut

hadmut commented 3 years ago

Just as a workaround hack:

Manually adding the types like

wsdl.instance_eval do @type_namespaces += [ [["Text","epub"], "http://vgwort.de/1.0/AuthorMessageService/xsd"] ] end

makes savon work correctly and use the right namespace. So it is in fact the problem that wasabi does not recognize elements within a choice data type.

olleolleolle commented 3 years ago

Question: to diagnose, could you attempt to pin to an earlier version of Wasabi? Or, latest in its GitHub repo?

markstanley-nps commented 2 years ago

I have had this problem as well, and it has been a long standing issue. We have worked around it by hardcoding the prefix within Savon.

I have done a bit more digging and the problem is in the process_type method within the Parser.

In two places this extracts the elements using xpath but ignores the fact that choices can be present

type.xpath('./xs:sequence/xs:element', 'xs' => XSD).each do |inner|
...
type.xpath('./xs:complexContent/xs:extension/xs:sequence/xs:element', 'xs' => XSD).each do |inner_element|

Changing these to allow for choices resolves the issue, at least in my test case

type.xpath('(./xs:sequence/xs:element|./xs:sequence/xs:choice/xs:element)', 'xs' => XSD).each do |inner|
...
type.xpath('(./xs:complexContent/xs:extension/xs:sequence/xs:element|./xs:complexContent/xs:extension/xs:sequence/xs:choice/xs:element)', 'xs' => XSD).each do |inner_element|

This doesn't appear to break any of the test cases