C #의 SOAP wsdl에서 작업에 대한 중첩 된 complexType 매개 변수를 가져 오는 방법

Nov 19 2020

WSDL이 있고 하나의 오퍼레이션이 제공되면이를 구문 분석하고 해당 오퍼레이션에 대한 입력 매개 변수를 가져오고 싶습니다.이 예제는 중첩 된 복합 유형이없는 경우에만 작동합니다.

중첩 된 요소 (complexType 및 simpleType 요소 및 속성)가있는 xsd 파일을 구문 분석하는 방법은 무엇입니까?

이를 위해 작동합니다.

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

즉, 4 개 작업 모두에 대해 올바른 매개 변수를 반환합니다 (Add에는 intA 및 intB와 함께 AddSoapIn이 있습니다 ...).

그러나 이것은 그렇지 않습니다.

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

SayHello에 대한 HelloRequest 만 가져오고 HelloRequest에서 요소 Name을 가져 오지 않습니다.

이것은 특정 SOAP WSDL이 아닌 모든 SOAP WSDL에서 작동해야합니다. 내 말은 일반 구문 분석입니다.

다음은 코드의 관련 부분입니다.

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];
        }
    foreach (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)
                {
                    foreach (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>>();

    foreach (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)
    {
        for (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");
        for (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)
    {
        for (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;
}

SayHello에 대해 getParams를 호출하면 명령 줄에 표시됩니다.

첫 번째 디버그는 49 행 (이전 주석 코드에서;)), 70 행에서 두 번째, OutputElements 함수의 138 행에서 마지막 디버그입니다.

또한 139 행에 null (childElement)이없고 param으로 추가 될 때 complexType (이 경우 HelloRequest)을 가져 오려고했습니다.

복잡한 유형으로 변환하십시오.

XmlSchemaComplexType complexTypeChild = sequence.Items[i] as XmlSchemaComplexType;

SayHello와 유사하게 HelloRequest의 부모가 처리되고이를 다시 호출하는 동일한 함수 OutputElements with complexTypeChild, recursive

그래서 다른 아이가 있으면

그러나 complexTypeChild는 null입니다.

다음과 같은 OutputElements를 얻었습니다.

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)
    {
        for (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 has 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");
        for (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)
    {
        for (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;
}

이후 5 줄 참조

// if it has children

그래서 발견되면 자식이 있는지 확인하고 해당 작업을 호출하는 봉투를 만들 때 사용할 수 있도록 매개 변수에 부모 매개 변수 / 요소를 추가했습니다.

답변

jdweng Nov 19 2020 at 18:39

WSDL을 가져 와서 스키마 섹션을 제거했습니다. 그런 다음 섹션에서 xsd.exe를 실행하고 다음 C # 클래스로 이동하십시오.

//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//     Runtime Version:4.0.30319.42000
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

using System.Xml.Serialization;

// 
// This source code was auto-generated by xsd, Version=4.0.30319.33440.
// 


/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.33440")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://learnwebservices.com/services/hello")]
[System.Xml.Serialization.XmlRootAttribute(Namespace="http://learnwebservices.com/services/hello", IsNullable=false)]
public partial class SayHello {
    
    private helloRequest helloRequestField;
    
    /// <remarks/>
    public helloRequest HelloRequest {
        get {
            return this.helloRequestField;
        }
        set {
            this.helloRequestField = value;
        }
    }
}

/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.33440")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://learnwebservices.com/services/hello")]
public partial class helloRequest {
    
    private string nameField;
    
    /// <remarks/>
    public string Name {
        get {
            return this.nameField;
        }
        set {
            this.nameField = value;
        }
    }
}

/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.33440")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://learnwebservices.com/services/hello")]
public partial class helloResponse {
    
    private string messageField;
    
    /// <remarks/>
    public string Message {
        get {
            return this.messageField;
        }
        set {
            this.messageField = value;
        }
    }
}

/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.33440")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://learnwebservices.com/services/hello")]
[System.Xml.Serialization.XmlRootAttribute(Namespace="http://learnwebservices.com/services/hello", IsNullable=false)]
public partial class SayHelloResponse {
    
    private helloResponse helloResponseField;
    
    /// <remarks/>
    public helloResponse HelloResponse {
        get {
            return this.helloResponseField;
        }
        set {
            this.helloResponseField = value;
        }
    }
}
whiteadi Nov 24 2020 at 15:20

이제 작동합니다. 문제는 처음에 코드를 사용한 솔루션이었습니다. 여기

실제로 복잡한 유형의 하나의 깊은 수준을 사용하여 wsdl 유형에 대해 사용자 정의되었으며 모든 wsdl에서 작업해야했습니다. 이제 몇 가지 작업을 시도했지만 작동하지만 일부 예제를 찾을 수 있습니다. 작동하지 않는 복잡한 항목,이 경우 여기로 돌아와 고정 코드를 게시하겠습니다.

어쨌든 해결책은 적어도 지금은 문서 및 rpc 및 soap 1.1 및 soap 1.2 wsdls에서 작동하는 것처럼 보입니다.

private static List<Tuple<string, string, string>> getParams(string methodName, XmlSchema schemaXML)
{
    List<Tuple<string, string, string>> parameters = new List<Tuple<string, 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];
    }

    foreach (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)
                {
                    foreach (XmlSchemaElement childElement in sequence.Items)
                    {
                        parameters.Add(new Tuple<string, string, string>(childElement.Name, childElement.SchemaTypeName.Name, schemaElement.Name));
                    }
                }
            }
        }
        else if (complexType != null && complexType.Name == methodName)
        {
            Console.Out.WriteLine("Complex Type: {0}", complexType.Name);
            List<Tuple<string, string, string>> moreparams = OutputElements(complexType.Particle, complexType.Name);
            if(moreparams != null && moreparams.Count !=0)
            {
                parameters.AddRange(moreparams);
            }
        }
    }
    // Loop through all detected imports in the main schema
    List<Tuple<string, string, string>> importparameters = ImportIncludedSchemasRecursively(wsdlUrl, methodName, xmlSchema);
    if (importparameters != null && importparameters.Count != 0)
    {
        parameters.AddRange(importparameters);
    }
    return parameters;
}

private static List<Tuple<string, string, string>> ImportIncludedSchemasRecursively(string mainWsdlUrl, string methodName, XmlSchema currentWsdlSchema)
{
    List<Tuple<string, string, string>> parameters = new List<Tuple<string, string, string>>();

    foreach (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, string>> complexparams = getParams(methodName, schema);
            if (complexparams != null && complexparams.Count != 0)
            {
                parameters.AddRange(complexparams);
            }

            List<Tuple<string, 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, 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)
    {
        for (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 has 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");
        for (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)
    {
        for (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;
}

이것은 파싱 된 wsdl이 주어지면 초기 / 원본 게시물의 코드를 참조하여 작업에 매개 변수를 제공하여 각각의 부모와 함께 호출합니다.