如何从SOAP wsdl获取嵌套的complexType参数以进行操作?

Whiteadi

会员
已加入
2020年11月19日
留言内容
9
编程经验
10+
有了WSDL并提供了一个操作,我想解析它并获取该操作的输入参数,该示例仅在没有嵌套的复杂类型时才对我有用:

如何解析具有嵌套元素(complexType和simpleType元素及属性)的xsd文件?

为此,它起作用:

http://www.dneonline.com/calculator.asmx?wsdl

这意味着它将为所有4个操作返回正确的参数(拥有 加SoapIn 诠释 整数...)

但这不是:

http://www.learnwebservices.com/services/hello?WSDL

它只到达 HelloRequest 对于 问好 并且不获取元素 名称 HelloRequest.

这应该适用于任何而不是特定的SOAP WSDL,我的意思是通用解析。
 

跳伞

工作人员
已加入
2019年4月6日
留言内容
2,497
地点
弗吉尼亚州切萨皮克
编程经验
10+
向我们展示您用于解析WSDL的代码。
 

Whiteadi

会员
已加入
2020年11月19日
留言内容
9
编程经验
10+
向我们展示您用于解析WSDL的代码。
C#:
public TheClient(string url) {
        wsdlUrl = url;
        ReadServiceDescription();
        ServiceName = theService.Name;
    }

...
    
void ReadServiceDescription()
    {
        try
        {               
            XmlTextReader reader=new XmlTextReader (wsdlUrl);   
            ServiceDescription service=
                ServiceDescription.Read(reader);
            theService = service;
            _services.Add(service);
        }
        catch (Exception e)
        {                                                       
            throw e;
        }
    }

private static List<Tuple<string, string>> getParams(string methodName, XmlSchema schemaXML)
    {
        List<Tuple<string, string>> parameters = new List<Tuple<string, string>>();
        ServiceDescription serviceDescription = theService;
        XmlSchema xmlSchema;
        WebClient client = new WebClient(); ;
        //Drill down into the WSDL's complex types to list out the individual schema elements
        //and their data types
        Types types = serviceDescription.Types;
        if (schemaXML != null)
        {
            xmlSchema = schemaXML;
        } else
        {
            xmlSchema = types.Schemas[0];
        }

        对于each (object item in xmlSchema.Items)
        {
            XmlSchemaElement schemaElement = item as XmlSchemaElement;
            XmlSchemaComplexType complexType = item as XmlSchemaComplexType;

            if (schemaElement != null && methodName == schemaElement.Name)
            {
                Console.Out.WriteLine("Schema Element: {0}", schemaElement.Name);

                XmlSchemaType schemaType = schemaElement.SchemaType;
                XmlSchemaComplexType schemaComplexType = schemaType as XmlSchemaComplexType;

                if (schemaComplexType != null)
                {
                    XmlSchemaParticle particle = schemaComplexType.Particle;
                    XmlSchemaSequence sequence = particle as XmlSchemaSequence;
                    if (sequence != null)
                    {
                        对于each (XmlSchemaElement childElement in sequence.Items)
                        {
                            Console.Out.WriteLine("    Element/Type: {0}:{1}", childElement.Name, childElement.SchemaTypeName.Name);
                            parameters.Add(new Tuple<string, string>(childElement.Name, childElement.SchemaTypeName.Name));
                        }
                    }
                }
            }
            else if (complexType != null && complexType.Name == methodName)
            {
                Console.Out.WriteLine("Complex Type: {0}", complexType.Name);
                List<Tuple<string, string>> moreparams = OutputElements(complexType.Particle);
                if(moreparams != null && moreparams.Count !=0)
                {
                    parameters.AddRange(moreparams);
                }
            }
            //Console.Out.WriteLine();
        }
        // Loop through all detected imports in the main schema
        List<Tuple<string, string>> importparameters = ImportIncludedSchemasRecursively(wsdlUrl, methodName, xmlSchema);
        if (importparameters != null && importparameters.Count != 0)
        {
            parameters.AddRange(importparameters);
        }
        return parameters;
    }
    
    private static List<Tuple<string, string>> ImportIncludedSchemasRecursively(string mainWsdlUrl, string methodName, XmlSchema currentWsdlSchema)
    {
        List<Tuple<string, string>> parameters = new List<Tuple<string, string>>();

        对于each (XmlSchemaObject externalSchema in currentWsdlSchema.Includes)
        {
            // Read each external schema into a schema object
            if (externalSchema is XmlSchemaImport)
            {
                Uri baseUri = new Uri(mainWsdlUrl);
                Uri schemaUri = new Uri(baseUri, ((XmlSchemaExternal)externalSchema).SchemaLocation);

                WebClient http = new WebClient();
                Stream schemaStream = http.OpenRead(schemaUri);

                System.Xml.Schema.XmlSchema schema = XmlSchema.Read(schemaStream, null);
                List<Tuple<string, string>> complexparams = getParams(methodName, schema);
                if (complexparams != null && complexparams.Count != 0)
                {
                    parameters.AddRange(complexparams);
                }

                List<Tuple<string, string>> morecomplexparams = ImportIncludedSchemasRecursively(mainWsdlUrl.ToString(), methodName, schema);
                if (morecomplexparams != null && morecomplexparams.Count != 0)
                {
                    parameters.AddRange(morecomplexparams);
                }

            }
        }

        return parameters.Distinct().ToList();
    }

    private static List<Tuple<string, string>> OutputElements(XmlSchemaParticle particle)
    {
        List<Tuple<string, string>> parameters = new List<Tuple<string, string>>();

        XmlSchemaSequence sequence = particle as XmlSchemaSequence;
        XmlSchemaChoice choice = particle as XmlSchemaChoice;
        XmlSchemaAll all = particle as XmlSchemaAll;

        if (sequence != null)
        {
            对于 (int i = 0; i < sequence.Items.Count; i++)
            {
                XmlSchemaElement childElement = sequence.Items[i] as XmlSchemaElement;
                XmlSchemaSequence innerSequence = sequence.Items[i] as XmlSchemaSequence;
                XmlSchemaChoice innerChoice = sequence.Items[i] as XmlSchemaChoice;
                XmlSchemaAll innerAll = sequence.Items[i] as XmlSchemaAll;
                Console.Out.WriteLine("111 child: {0}", childElement.Name);
                if (childElement != null)
                {
                    parameters.Add(new Tuple<string, string>(childElement.Name, childElement.SchemaTypeName.Name));
                }
                else {
                    List<Tuple<string, string>> moreparams = OutputElements(sequence.Items[i] as XmlSchemaParticle);
                    if (moreparams != null && moreparams.Count != 0)
                    {
                        parameters.AddRange(moreparams);
                    }
                }
            }

            return parameters;
        }
        else if (choice != null)
        {
            Console.Out.WriteLine("  Choice");
            对于 (int i = 0; i < choice.Items.Count; i++)
            {
                XmlSchemaElement childElement = choice.Items[i] as XmlSchemaElement;
                XmlSchemaSequence innerSequence = choice.Items[i] as XmlSchemaSequence;
                XmlSchemaChoice innerChoice = choice.Items[i] as XmlSchemaChoice;
                XmlSchemaAll innerAll = choice.Items[i] as XmlSchemaAll;
                Console.Out.WriteLine("222 child: {0}", childElement.Name);
                if (childElement != null)
                {
                    parameters.Add(new Tuple<string, string>(childElement.Name, childElement.SchemaTypeName.Name));
                }
                else
                {                       
                    List<Tuple<string, string>> moreparams = OutputElements(choice.Items[i] as XmlSchemaParticle);
                    if (moreparams != null && moreparams.Count != 0)
                    {
                        parameters.AddRange(moreparams);
                    }
                }

            }
            return parameters;
        }
        else if (all != null)
        {
            对于 (int i = 0; i < all.Items.Count; i++)
            {
                XmlSchemaElement childElement = all.Items[i] as XmlSchemaElement;
                XmlSchemaSequence innerSequence = all.Items[i] as XmlSchemaSequence;
                XmlSchemaChoice innerChoice = all.Items[i] as XmlSchemaChoice;
                XmlSchemaAll innerAll = all.Items[i] as XmlSchemaAll;
                Console.Out.WriteLine("333 child: {0}", childElement.Name);
                if (childElement != null)
                {
                    parameters.Add(new Tuple<string, string>(childElement.Name, childElement.SchemaTypeName.Name));
                }
                else
                {
                    List<Tuple<string, string>> moreparams = OutputElements(all.Items[i] as XmlSchemaParticle);
                    if (moreparams != null && moreparams.Count != 0)
                    {
                        parameters.AddRange(moreparams);
                    }
                }
            }
            return parameters;
        }
        return parameters;
    }
 

跳伞

工作人员
已加入
2019年4月6日
留言内容
2,497
地点
弗吉尼亚州切萨皮克
编程经验
10+
当您使用调试器逐步执行代码时,发现了"HelloRequest"?我对该代码转储的快速扫描是,它应该以递归方式尝试读取内容,但是理所当然的是,我只是在浏览其中而不是主动尝试调试它。
 

Whiteadi

会员
已加入
2020年11月19日
留言内容
9
编程经验
10+
当您使用调试器逐步执行代码时,发现了"HelloRequest"?我对该代码转储的快速扫描是,它应该以递归方式尝试读取内容,但是理所当然的是,我只是在浏览其中而不是主动尝试调试它。
当我为SayHello调用getParams时,它将显示在命令行上:
1605797660620.png

从第49行进行第一次调试(在先前注释的代码中) ;) ),
第70行第二
最后一个是OutputElements函数的第138行。

当第139行的值不为null(childElement)并添加为param时,我还尝试了一个complexType,在本例中为HelloRequest。

并将其转换为复杂类型:

C#:
XmlSchemaComplexType complexTypeChild = sequence.Items[i] as XmlSchemaComplexType;

与SayHello类似,处理HelloRequest的父级,然后再次调用它,带有complexTypeChild的相同函数OutputElements,递归

所以如果有其他孩子会工作

但complexTypeChild为null。
 

跳伞

工作人员
已加入
2019年4月6日
留言内容
2,497
地点
弗吉尼亚州切萨皮克
编程经验
10+
也许我不明白您的期望。"HelloRequest"已经是叶子节点(请参见第9行):
XML:
<wsdl:types>
  <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://learnwebservices.com/services/hello" elementFormDefault="qualified" targetNamespace="http://learnwebservices.com/services/hello" version="1.0">
    <xs:element name="SayHello" type="tns:SayHello"/>

    <xs:element name="SayHelloResponse" type="tns:SayHelloResponse"/>

    <xs:complexType name="SayHello">
      <xs:sequence>
        <xs:element name="HelloRequest" type="tns:helloRequest"/>
      </xs:sequence>
    </xs:complexType>
      
    <xs:complexType name="helloRequest">
      <xs:sequence>
        <xs:element name="Name" type="xs:string"/>
      </xs:sequence>
    </xs:complexType>
      
    <xs:complexType name="SayHelloResponse">
      <xs:sequence>
        <xs:element name="HelloResponse" type="tns:helloResponse"/>
      </xs:sequence>
    </xs:complexType>
      
    <xs:complexType name="helloResponse">
      <xs:sequence>
        <xs:element name="Message" type="xs:string"/>
      </xs:sequence>
    </xs:complexType>
  </xs:schema>
</wsdl:types>
 

Whiteadi

会员
已加入
2020年11月19日
留言内容
9
编程经验
10+
也许我不明白您的期望。"HelloRequest"已经是叶子节点(请参见第9行):
XML:
<wsdl:types>
  <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://learnwebservices.com/services/hello" elementFormDefault="qualified" targetNamespace="http://learnwebservices.com/services/hello" version="1.0">
    <xs:element name="SayHello" type="tns:SayHello"/>

    <xs:element name="SayHelloResponse" type="tns:SayHelloResponse"/>

    <xs:complexType name="SayHello">
      <xs:sequence>
        <xs:element name="HelloRequest" type="tns:helloRequest"/>
      </xs:sequence>
    </xs:complexType>
    
    <xs:complexType name="helloRequest">
      <xs:sequence>
        <xs:element name="Name" type="xs:string"/>
      </xs:sequence>
    </xs:complexType>
    
    <xs:complexType name="SayHelloResponse">
      <xs:sequence>
        <xs:element name="HelloResponse" type="tns:helloResponse"/>
      </xs:sequence>
    </xs:complexType>
    
    <xs:complexType name="helloResponse">
      <xs:sequence>
        <xs:element name="Message" type="xs:string"/>
      </xs:sequence>
    </xs:complexType>
  </xs:schema>
</wsdl:types>

HelloRequest还有一个名为Name的子元素,它不是一个复杂的元素,但是我确实需要进行请求的所有输入参数,因此

我可以使用将为该操作创建的子创建方法的值构成信封,例如:


XML:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
   <soapenv:Header/>
   <soapenv:Body>
      <SayHello xmlns="http://learnwebservices.com/services/hello">
         <HelloRequest>
            <Name>John Doe</Name>
         </HelloRequest>
      </SayHello>
   </soapenv:Body>
</soapenv:Envelope>

问好 -> HelloRequest -> 名称 (and I can get also type 对于 it)

现在可以正常工作,为所有wsdl提取所有输入参数,对于那些没有这些嵌套的complexTypes并带有提供的代码的输入参数,例如: http://www.dneonline.com/calculator.asmx?wsdl

我为每种方法都获得了正确的参数,为最终元素获得了正确的类型,因此我可以为ex构造正确的信封。用于添加操作:

XML:
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <Add xmlns="http://tempuri.org/">
      <intA>2</intA>
      <intB>3</intB>
    </Add>
  </soap:Body>
</soap:Envelope>

PS:我也有一个BuildEnvelope,如果我得到正确的参数,它将起作用 :)
 

跳伞

工作人员
已加入
2019年4月6日
留言内容
2,497
地点
弗吉尼亚州切萨皮克
编程经验
10+
您需要建立"object tree"。请注意"HelloRequest" is "helloRequest":
XML:
<xs:element name="HelloRequest" type="tns:helloRequest"/>
并注意如何"helloRequest" contains the "Name"您正在寻找:
XML:
<xs:complexType name="helloRequest">
  <xs:sequence>
    <xs:element name="Name" type="xs:string"/>
  </xs:sequence>
</xs:complexType>
 

Whiteadi

会员
已加入
2020年11月19日
留言内容
9
编程经验
10+
您需要建立"object tree"。请注意"HelloRequest" is "helloRequest":
XML:
<xs:element name="HelloRequest" type="tns:helloRequest"/>
并注意如何"helloRequest" contains the "Name"您正在寻找:
XML:
<xs:complexType name="helloRequest">
  <xs:sequence>
    <xs:element name="Name" type="xs:string"/>
  </xs:sequence>
</xs:complexType>
但这就是getParams代码应该做的。只是没有,这就是问题所在。
 

跳伞

工作人员
已加入
2019年4月6日
留言内容
2,497
地点
弗吉尼亚州切萨皮克
编程经验
10+
As I said in post #4: step through the code 与 the debugger. Don't just run it. I think that you'll find that when you call OutputElements() on line 71 (which produced the output 从 line 138), that the rest of the 对于each loop 对于 in getParams() 拥有 not yet seen the succeeding elements.
 

Whiteadi

会员
已加入
2020年11月19日
留言内容
9
编程经验
10+
As I said in post #4: step through the code 与 the debugger. Don't just run it. I think that you'll find that when you call OutputElements() on line 71 (which produced the output 从 line 138), that the rest of the 对于each loop 对于 in getParams() 拥有 not yet seen the succeeding elements.
我确实会检查星期一,有anice周结束!
 

Whiteadi

会员
已加入
2020年11月19日
留言内容
9
编程经验
10+
嗨,我向OutputElements添加了几行,请参见高亮行(21-26):

C#:
private static List<Tuple<string, string, string>> OutputElements(XmlSchemaParticle particle, string parentName)
    {
        List<Tuple<string, string, string>> parameters = new List<Tuple<string, string, string>>();

        XmlSchemaSequence sequence = particle as XmlSchemaSequence;
        XmlSchemaChoice choice = particle as XmlSchemaChoice;
        XmlSchemaAll all = particle as XmlSchemaAll;

        if (sequence != null)
        {
            对于 (int i = 0; i < sequence.Items.Count; i++)
            {
                XmlSchemaElement childElement = sequence.Items[i] as XmlSchemaElement;
                XmlSchemaSequence innerSequence = sequence.Items[i] as XmlSchemaSequence;
                XmlSchemaChoice innerChoice = sequence.Items[i] as XmlSchemaChoice;
                XmlSchemaAll innerAll = sequence.Items[i] as XmlSchemaAll;
                
                if (childElement != null)
                {
                    parameters.Add(new Tuple<string, string, string>(childElement.Name, childElement.SchemaTypeName.Name, parentName));
                    // if it 拥有 children
                    List<Tuple<string, string, string>> moreparams = getParams(childElement.SchemaTypeName.Name, null);
                    if (moreparams != null && moreparams.Count != 0)
                    {
                        parameters.AddRange(moreparams);
                    }
                }
                else {
                    List<Tuple<string, string, string>> moreparams = OutputElements(sequence.Items[i] as XmlSchemaParticle, parentName);
                    if (moreparams != null && moreparams.Count != 0)
                    {
                        parameters.AddRange(moreparams);
                    }
                }
            }

            return parameters;
        }
        else if (choice != null)
        {
            Console.Out.WriteLine("  Choice");
            对于 (int i = 0; i < choice.Items.Count; i++)
            {
                XmlSchemaElement childElement = choice.Items[i] as XmlSchemaElement;
                XmlSchemaSequence innerSequence = choice.Items[i] as XmlSchemaSequence;
                XmlSchemaChoice innerChoice = choice.Items[i] as XmlSchemaChoice;
                XmlSchemaAll innerAll = choice.Items[i] as XmlSchemaAll;

                if (childElement != null)
                {
                    parameters.Add(new Tuple<string, string, string>(childElement.Name, childElement.SchemaTypeName.Name, parentName));
                }
                else
                {                       
                    List<Tuple<string, string, string>> moreparams = OutputElements(choice.Items[i] as XmlSchemaParticle, parentName);
                    if (moreparams != null && moreparams.Count != 0)
                    {
                        parameters.AddRange(moreparams);
                    }
                }

            }
            return parameters;
        }
        else if (all != null)
        {
            对于 (int i = 0; i < all.Items.Count; i++)
            {
                XmlSchemaElement childElement = all.Items[i] as XmlSchemaElement;
                XmlSchemaSequence innerSequence = all.Items[i] as XmlSchemaSequence;
                XmlSchemaChoice innerChoice = all.Items[i] as XmlSchemaChoice;
                XmlSchemaAll innerAll = all.Items[i] as XmlSchemaAll;

                if (childElement != null)
                {
                    parameters.Add(new Tuple<string, string, string>(childElement.Name, childElement.SchemaTypeName.Name, parentName));
                }
                else
                {
                    List<Tuple<string, string, string>> moreparams = OutputElements(all.Items[i] as XmlSchemaParticle, parentName);
                    if (moreparams != null && moreparams.Count != 0)
                    {
                        parameters.AddRange(moreparams);
                    }
                }
            }
            return parameters;
        }
        return parameters;
    }

另外,我还将元素的父名称传递给参数,以了解稍后在创建用于调用方法的信封时将其附加到何处。
 
最佳 底部