Go でSOAP/WSDLをサポートするパッケージはありますか?
5 に答える
Go では WSDL はサポートされていません。他の言語でのサポートは、静的または動的のいずれかです。構造体は WSDL から事前に生成されるか、ハッシュ テーブルを使用してオンザフライで行われます。
ただし、SOAP リクエストを手動でエンコードおよびデコードすることはできます。encoding/xml
標準パッケージでは SOAP には不十分であることがわかりました。さまざまなサーバーには非常に多くの癖があり、制限encoding/xml
により、これらのサーバーが満足するリクエストを生成することは困難です.
たとえば、一部のサーバーxsi:type="xsd:string"
ではすべての文字列タグが必要です。これを適切に行うには、構造体を次のようにする必要がありますencoding/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"},
}
これにより、次のことが得られます。
<MethodCall>
<One xsi:type="xsd:string">One</One>
<Two xsi:type="xsd:string">Two</Two>
</MethodCall>
これで大丈夫かもしれません。それは確かに仕事を成し遂げます。しかし、単なる 以外のものが必要な場合はどうstring
でしょうか? encoding/xml
は現在サポートしていませんinterface{}
。
ご覧のとおり、これは複雑になります。統合する SOAP API が 1 つある場合、これはおそらくそれほど悪くはありません。それぞれが独自の癖を持ついくつかのものがあった場合はどうなりますか?
これだけできたらいいじゃないですか。
type MethodCall struct {
One string
Two string
}
次に、encoding/xml
「このサーバーは xsi タイプが必要です」と言います。
この問題を解決するために、私はgithub.com/webconnex/xmlutilを作成しました。進行中の作業です。のエンコーダー/デコーダーのすべての機能を備えているわけではありませんがencoding/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
メソッドを使用して応答オブジェクトまたは Fault を取得しています。これは厳密には必要ありません。次のようにすることもできます。
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)
このFind
メソッドは、データが次のようになっている場合に役立ちます。
<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>
これは、Microsoft .NET の一部である DiffGram です。Find
メソッドを使用して にアクセスできますTable1
。Decode
andメソッドはDecodeElement
スライスでも機能します。そのため、たまたま複数の結果が含まれる[]MethodCallResponse
場合に渡すことができます。NewDataSet
私は、SOAP が最悪であるという Zippower に同意します。しかし残念なことに、多くの企業が SOAP を使用しており、これらの API の使用を余儀なくされることがあります。xmlutil パッケージを使用すると、作業が少し楽になると思います。
いいえ。
SOAPは最悪ですが、SOAPを使用する定義済みのプロトコルのサーバーを実装する必要があったため、でnet/http
エンベロープをリッスンし、デコード/エンコードしましencoding/xml
た。数分で、私はすでにGoで最初の封筒を提供しました。
wsdl-goもあります。
でも使ったことがないので何とも言えません。