WSDL/SOAP支持在运行中?

WSDL/SOAP支持在运行中?,soap,go,soap-client,Soap,Go,Soap Client,是否有支持SOAP/WSDL的软件包 没有 SOAP很糟糕,但我必须实现一个使用SOAP的已定义协议的服务器,因此我使用net/http收听,并使用encoding/xml解码/编码信封。几分钟后,我已经用Go提供了我的第一个信封。Go中不支持WSDL。其他语言中的支持可以是静态的,也可以是动态的:结构是从WSDL预先生成的,或者是通过哈希表动态生成的 但是,您可以手动对SOAP请求进行编码和解码。我发现标准的编码/xml包对于SOAP来说是不够的。在不同的服务器中有如此多的怪癖,而且编码/xm

是否有支持SOAP/WSDL的软件包

没有


SOAP很糟糕,但我必须实现一个使用SOAP的已定义协议的服务器,因此我使用
net/http
收听,并使用
encoding/xml
解码/编码信封。几分钟后,我已经用Go提供了我的第一个信封。

Go中不支持WSDL。其他语言中的支持可以是静态的,也可以是动态的:结构是从WSDL预先生成的,或者是通过哈希表动态生成的

但是,您可以手动对SOAP请求进行编码和解码。我发现标准的
编码/xml
包对于SOAP来说是不够的。在不同的服务器中有如此多的怪癖,而且
编码/xml
中的限制使得生成这些服务器满意的请求变得非常困难

例如,有些服务器需要在每个字符串标记上使用
xsi:type=“xsd:string”
。为了正确地执行此操作,对于
编码/xml
,您的结构需要如下所示:

type MethodCall struct {
    One XSI
    Two XSI
}

type XSI struct {
    Type string `xml:"xsi:type,attr"`
    Vaue string `xml:",chardata"`
}
你这样构造它:

MethodCall{
    XSI{"xsd:string", "One"},
    XSI{"xsd:string", "Two"},
}
x.RegisterType(MethodCallResponse{})
...
// Decode response
dec := x.NewDecoder(bytes.NewBufferString(`<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope>
    <soap:Body>
        <MethodCallResponse>
            <Three>three</Three>
        </MethodCallResponse>
    </soap:Body>
</soap:Envelope>`))
var start *xml.StartElement
var resp Envelope
if err := dec.DecodeElement(&resp, start); err != nil {
    log.Fatal(err)
}
fmt.Printf("%#v\n\n", resp)
<soap:Envelope>
  <soap:Body>
    <MethodResponse>
      <MethodResult>
        <diffgr:diffgram>
          <NewDataSet>
            <Table1 diffgr:id="Table1" msdata:rowOrder="0" diffgr:hasChanges="inserted">
              <Three>three</Three>
            </Table1>
          </NewDataSet>
        </diffgr:diffgram>
      </MethodResult>
    </MethodResponse>
  </soap:Body>
</soap:Envelope>
这给了你:

<MethodCall>
    <One xsi:type="xsd:string">One</One>
    <Two xsi:type="xsd:string">Two</Two>
</MethodCall>
然后对
编码/xml
:“此服务器需要xsi类型”

为了解决这个问题,我创造了。这是一项正在进行的工作。它不具备
编码/xml
编码器/解码器的所有功能,但它具备SOAP所需的功能

下面是一个工作示例:

package main

import (
    "bytes"
    "encoding/xml"
    "fmt"
    "github.com/webconnex/xmlutil"
    "log"
    //"net/http"
)

type Envelope struct {
    Body `xml:"soap:"`
}

type Body struct {
    Msg interface{}
}

type MethodCall struct {
    One string
    Two string
}

type MethodCallResponse struct {
    Three string
}

func main() {
    x := xmlutil.NewXmlUtil()
    x.RegisterNamespace("http://www.w3.org/2001/XMLSchema-instance", "xsi")
    x.RegisterNamespace("http://www.w3.org/2001/XMLSchema", "xsd")
    x.RegisterNamespace("http://www.w3.org/2003/05/soap-envelope", "soap")
    x.RegisterTypeMore(Envelope{}, xml.Name{"http://www.w3.org/2003/05/soap-envelope", ""},
        []xml.Attr{
            xml.Attr{xml.Name{"xmlns", "xsi"}, "http://www.w3.org/2001/XMLSchema-instance"},
            xml.Attr{xml.Name{"xmlns", "xsd"}, "http://www.w3.org/2001/XMLSchema"},
            xml.Attr{xml.Name{"xmlns", "soap"}, "http://www.w3.org/2003/05/soap-envelope"},
        })
    x.RegisterTypeMore("", xml.Name{}, []xml.Attr{
        xml.Attr{xml.Name{"http://www.w3.org/2001/XMLSchema-instance", "type"}, "xsd:string"},
    })

    buf := new(bytes.Buffer)
    buf.WriteString(`<?xml version="1.0" encoding="utf-8"?>`)
    buf.WriteByte('\n')
    enc := x.NewEncoder(buf)
    env := &Envelope{Body{MethodCall{
        One: "one",
        Two: "two",
    }}}
    if err := enc.Encode(env); err != nil {
        log.Fatal(err)
    }
    // Print request
    bs := buf.Bytes()
    bs = bytes.Replace(bs, []byte{'>', '<'}, []byte{'>', '\n', '<'}, -1)
    fmt.Printf("%s\n\n", bs)

    /*
        // Send response, SOAP 1.2, fill in url, namespace, and action
        var r *http.Response
        if r, err = http.Post(url, "application/soap+xml; charset=utf-8; action="+namespace+"/"+action, buf); err != nil {
            return
        }
        dec := x.NewDecoder(r.Body)
    */
    // Decode response
    dec := x.NewDecoder(bytes.NewBufferString(`<?xml version="1.0" encoding="utf-8"?>
    <soap:Envelope>
        <soap:Body>
            <MethodCallResponse>
                <Three>three</Three>
            </MethodCallResponse>
        </soap:Body>
    </soap:Envelope>`))
    find := []xml.Name{
        xml.Name{"", "MethodCallResponse"},
        xml.Name{"http://www.w3.org/2003/05/soap-envelope", "Fault"},
    }
    var start *xml.StartElement
    var err error
    if start, err = dec.Find(find); err != nil {
        log.Fatal(err)
    }
    if start.Name.Local == "Fault" {
        log.Fatal("Fault!") // Here you can decode a Soap Fault
    }
    var resp MethodCallResponse
    if err := dec.DecodeElement(&resp, start); err != nil {
        log.Fatal(err)
    }
    fmt.Printf("%#v\n\n", resp)
}
当您的数据如下所示时,您会发现
find
方法很有用:

MethodCall{
    XSI{"xsd:string", "One"},
    XSI{"xsd:string", "Two"},
}
x.RegisterType(MethodCallResponse{})
...
// Decode response
dec := x.NewDecoder(bytes.NewBufferString(`<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope>
    <soap:Body>
        <MethodCallResponse>
            <Three>three</Three>
        </MethodCallResponse>
    </soap:Body>
</soap:Envelope>`))
var start *xml.StartElement
var resp Envelope
if err := dec.DecodeElement(&resp, start); err != nil {
    log.Fatal(err)
}
fmt.Printf("%#v\n\n", resp)
<soap:Envelope>
  <soap:Body>
    <MethodResponse>
      <MethodResult>
        <diffgr:diffgram>
          <NewDataSet>
            <Table1 diffgr:id="Table1" msdata:rowOrder="0" diffgr:hasChanges="inserted">
              <Three>three</Three>
            </Table1>
          </NewDataSet>
        </diffgr:diffgram>
      </MethodResult>
    </MethodResponse>
  </soap:Body>
</soap:Envelope>
这是一个DiffGram,是Microsoft.NET的一部分。您可以使用
Find
方法进入
Table1
Decode
decodelement
方法也适用于切片。因此,如果
NewDataSet
恰好包含多个结果,则可以传入
[]方法调用响应

我同意Zippower的说法,肥皂确实很烂。但不幸的是,很多企业都使用SOAP,有时您不得不使用这些API。有了xmlutil包,我希望使用它能减少一点痛苦。

一个选项是使用它生成一个C WSDL客户机
然后通过GO with使用该客户端,虽然GO本身仍然没有任何功能,但仍然有。到目前为止,它似乎工作得很好,足以让我与几个SOAP服务进行交互

我不使用它提供的SOAP代理,我认为它不支持auth,但会从WSDL生成我需要的结构和代码来封送请求和解组响应——这是一个巨大的胜利。

还有。

但我还没有使用过它,所以我真的不能说。

Go-tip现在支持和编码/xml-like-encoding/json,这项功能预计将出现在Go 1.2中。这可能有助于处理SOAP。Works great@luke,您的小型xml实用程序库…js需要一个入门文档,尽管只需几分钟的时间扫描上面的脚本,我就能够理解如何使用它。我编写了一个WSDL解析器,可以生成调用SOAP的go代码。关于标记,编码/xml有很多限制,我在自述文件中提供了一个链接。检查:感谢您提供的小型XML/SOAP包,工作做得很好。大家可以在这里找到lib——我经常不得不在遗留系统上使用SOAP,直到上周末我还在Go中通过硬编码结构来实现。黑客入侵了一个用于WSDL的parser+Go代码生成器,它可以生成可用的Go代码来调用SOAP。我使用的一些API非常广泛,生成的文件超过2k LOC。检查一下:当然可以,但是有无限多的企业系统只支持SOAP。对于这些情况,我们仍然需要一些有用的东西。我会重新考虑“最佳选择”!这是一个复杂而令人困惑的方法,可能是最稳定和完整的SOAP实现:如果你能解决使用C/C++从GO中产生的麻烦……那么它的方法是:)没有任何来自GC++的GSOAP的双关语,我强烈建议不要这样做。gSoap代码是我见过的最糟糕的代码之一(包括硬件供应商的代码!)。这太可怕了。不要使用它。当你面临一个选择,其中一个选项是gSoap时,选择另一个选项。即使那个选项是“写你自己的”。@eddyce我是认真的。我会告诉你去看看代码,但你看起来是个好人,所以不要这样对自己。gsoap问题的一个例子是它根本不分层代码。在soap库中,我希望看到一个http层,一个xml层和一个soap层(或处理此问题的外部库)。gsoap混合了所有这些。没有分层。@KristofProvost我从来没有这样做过(看看我指的代码)。wsdl客户机应该创建可以工作的代码,它不必是好的或可读的,因为我甚至不会打开它。我在回答中省略了“最佳选项”,因为你不是唯一这样想的人,另一方面,我看到gsoap在相当复杂的wsdl上提供了一个很好的接口,如果我愿意,我会再次使用它。这似乎不再存在。