Golang如何通过属性读取XML数据
Golang如何通过属性读取XML数据 尝试按照此处的解释,使用Golang连接MS SharePoint,因此我编写了以下代码,它返回了XML文本:
package main
import (
"bytes"
"encoding/xml"
"fmt"
"io/ioutil"
"log"
"net/http"
"strings"
)
func main() {
const myurl = "https://login.microsoftonline.com/extSTS.srf"
const username = "myuser@mydmain.com"
const password = "mypassword"
const endpoint = "https://mydomain.sharepoint.com/"
const xmlbody = `
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"
xmlns:a="http://www.w3.org/2005/08/addressing"
xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<s:Header>
<a:Action s:mustUnderstand="1">http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issue</a:Action>
<a:ReplyTo>
<a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
</a:ReplyTo>
<a:To s:mustUnderstand="1">https://login.microsoftonline.com/extSTS.srf</a:To>
<o:Security s:mustUnderstand="1"
xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<o:UsernameToken>
<o:Username>` + username + `</o:Username>
<o:Password>` + password + `</o:Password>
</o:UsernameToken>
</o:Security>
</s:Header>
<s:Body>
<t:RequestSecurityToken xmlns:t="http://schemas.xmlsoap.org/ws/2005/02/trust">
<wsp:AppliesTo xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">
<a:EndpointReference>
<a:Address>` + endpoint + `</a:Address>
</a:EndpointReference>
</wsp:AppliesTo>
<t:KeyType>http://schemas.xmlsoap.org/ws/2005/05/identity/NoProofKey</t:KeyType>
<t:RequestType>http://schemas.xmlsoap.org/ws/2005/02/trust/Issue</t:RequestType>
<t:TokenType>urn:oasis:names:tc:SAML:1.0:assertion</t:TokenType>
</t:RequestSecurityToken>
</s:Body>
</s:Envelope>`
resp, err := http.Post(myurl, "text/xml", strings.NewReader(xmlbody))
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
fmt.Println("response Body:", string(body))
}
上面的代码完美地完成了第一步,现在我想获取返回的字符串并读取具有 ID="Compact0" 属性的 xml 元素,所以我尝试了以下方法:
type Node struct {
XMLName xml.Name
Attrs []xml.Attr `xml:"-"`
Content []byte `xml:",innerxml"`
Nodes []Node `xml:",any"`
}
func walk(nodes []Node, f func(Node) bool) {
for _, n := range nodes {
if f(n) {
walk(n.Nodes, f)
}
}
}
func main() {
// My code above, followed by:
var n Node
var data = []byte(body)
buf := bytes.NewBuffer(data)
dec := xml.NewDecoder(buf)
err = dec.Decode(&n)
if err != nil {
panic(err)
}
walk([]Node{n}, func(n Node) bool {
if n.Attrs == "Compact0" {. // <= ERROR
fmt.Println(string(n.Content))
}
return true
})
}
但是我遇到了这个错误:
无法将“Compact0”(无类型字符串常量)转换为 xml.AttrcompilerInvalidUntypedConversion
错误位置:
if n.Attrs == “Compact0” {}
返回的 XML 响应是:
<?xml version="1.0" encoding="utf-8"?>
<S:Envelope xmlns:wsa="http://www.w3.org/2005/08/addressing"
xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
xmlns:wst="http://schemas.xmlsoap.org/ws/2005/02/trust"
xmlns:S="http://www.w3.org/2003/05/soap-envelope">
<S:Header>
<wsa:Action S:mustUnderstand="1" wsu:Id="Action">http://schemas.xmlsoap.org/ws/2005/02/trust/RSTR/Issue</wsa:Action>
<wsa:To S:mustUnderstand="1" wsu:Id="To">http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:To>
<wsse:Security S:mustUnderstand="1">
<wsu:Timestamp wsu:Id="TS" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsu:Created>2021-06-30T18:38:50.5911765Z</wsu:Created>
<wsu:Expires>2021-06-30T18:43:50.5911765Z</wsu:Expires>
</wsu:Timestamp>
</wsse:Security>
</S:Header>
<S:Body xmlns:S="http://www.w3.org/2003/05/soap-envelope">
<wst:RequestSecurityTokenResponse xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" x
mlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
xmlns:wst="http://schemas.xmlsoap.org/ws/2005/02/trust">
<wst:TokenType>urn:passport:compact</wst:TokenType>
<wsp:AppliesTo>
<wsa:EndpointReference xmlns:wsa="http://www.w3.org/2005/08/addressing">
<wsa:Address>https://mydomain.sharepoint.com/</wsa:Address>
</wsa:EndpointReference>
</wsp:AppliesTo>
<wst:Lifetime>
<wsu:Created>2021-06-30T18:38:49Z</wsu:Created>
<wsu:Expires>2021-07-01T18:38:49Z</wsu:Expires>
</wst:Lifetime>
<wst:RequestedSecurityToken>
<wsse:BinarySecurityToken Id="Compact0"
xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
t=blablabla==&p=
</wsse:BinarySecurityToken>
</wst:RequestedSecurityToken>
<wst:RequestedAttachedReference>
<wsse:SecurityTokenReference xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:Reference URI="VkETyJDRdMqocUhjsNftrfT9Z8U="></wsse:Reference>
</wsse:SecurityTokenReference>
</wst:RequestedAttachedReference>
<wst:RequestedUnattachedReference>
<wsse:SecurityTokenReference xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:Reference URI="VkETyJDRdMqocUhjsNftrfT9Z8U="></wsse:Reference>
</wsse:SecurityTokenReference>
</wst:RequestedUnattachedReference>
</wst:RequestSecurityTokenResponse>
</S:Body>
</S:Envelope>
我需要从中获取位于以下位置的 blablabla:
<wsse:BinarySecurityToken Id="Compact0"
xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
t=blablabla==&p=
</wsse:BinarySecurityToken>
更多关于Golang如何通过属性读取XML数据的实战教程也可以访问 https://www.itying.com/category-94-b0.html
2 回复
问题之一可能是你正在尝试将一个字符串与一个 xml.Attr 数组进行比较。
更多关于Golang如何通过属性读取XML数据的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
在Golang中通过属性读取XML数据,需要使用xml.Attr类型来访问属性。你的代码中n.Attrs是一个[]xml.Attr切片,不能直接与字符串比较。以下是修正后的代码:
package main
import (
"bytes"
"encoding/xml"
"fmt"
"io/ioutil"
"log"
"net/http"
"strings"
)
type Node struct {
XMLName xml.Name
Attrs []xml.Attr `xml:",any,attr"`
Content []byte `xml:",innerxml"`
Nodes []Node `xml:",any"`
}
func walk(nodes []Node, f func(Node) bool) {
for _, n := range nodes {
if f(n) {
walk(n.Nodes, f)
}
}
}
func main() {
const myurl = "https://login.microsoftonline.com/extSTS.srf"
const username = "myuser@mydmain.com"
const password = "mypassword"
const endpoint = "https://mydomain.sharepoint.com/"
const xmlbody = `
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"
xmlns:a="http://www.w3.org/2005/08/addressing"
xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<s:Header>
<a:Action s:mustUnderstand="1">http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issue</a:Action>
<a:ReplyTo>
<a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
</a:ReplyTo>
<a:To s:mustUnderstand="1">https://login.microsoftonline.com/extSTS.srf</a:To>
<o:Security s:mustUnderstand="1"
xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<o:UsernameToken>
<o:Username>` + username + `</o:Username>
<o:Password>` + password + `</o:Password>
</o:UsernameToken>
</o:Security>
</s:Header>
<s:Body>
<t:RequestSecurityToken xmlns:t="http://schemas.xmlsoap.org/ws/2005/02/trust">
<wsp:AppliesTo xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">
<a:EndpointReference>
<a:Address>` + endpoint + `</a:Address>
</a:EndpointReference>
</wsp:AppliesTo>
<t:KeyType>http://schemas.xmlsoap.org/ws/2005/05/identity/NoProofKey</t:KeyType>
<t:RequestType>http://schemas.xmlsoap.org/ws/2005/02/trust/Issue</t:RequestType>
<t:TokenType>urn:oasis:names:tc:SAML:1.0:assertion</t:TokenType>
</t:RequestSecurityToken>
</s:Body>
</s:Envelope>`
resp, err := http.Post(myurl, "text/xml", strings.NewReader(xmlbody))
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
fmt.Println("response Body:", string(body))
var n Node
var data = []byte(body)
buf := bytes.NewBuffer(data)
dec := xml.NewDecoder(buf)
err = dec.Decode(&n)
if err != nil {
panic(err)
}
walk([]Node{n}, func(n Node) bool {
for _, attr := range n.Attrs {
if attr.Name.Local == "Id" && attr.Value == "Compact0" {
fmt.Println("Found BinarySecurityToken with Id='Compact0':")
fmt.Println(string(n.Content))
return false
}
}
return true
})
}
关键修改:
- 将
Attrs字段的标签改为xml:",any,attr"以正确捕获所有属性 - 在
walk函数中遍历n.Attrs切片,检查每个属性的Name.Local和Value - 当找到
Id="Compact0"的属性时,打印节点的内容
另一种更直接的方法是使用结构体映射:
type BinarySecurityToken struct {
XMLName xml.Name `xml:"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd BinarySecurityToken"`
Id string `xml:"Id,attr"`
Content string `xml:",chardata"`
}
type RequestedSecurityToken struct {
BinarySecurityToken BinarySecurityToken `xml:"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd BinarySecurityToken"`
}
type RequestSecurityTokenResponse struct {
XMLName xml.Name `xml:"http://schemas.xmlsoap.org/ws/2005/02/trust RequestSecurityTokenResponse"`
RequestedSecurityToken RequestedSecurityToken `xml:"RequestedSecurityToken"`
}
type Body struct {
RequestSecurityTokenResponse RequestSecurityTokenResponse `xml:"http://schemas.xmlsoap.org/ws/2005/02/trust RequestSecurityTokenResponse"`
}
type Envelope struct {
XMLName xml.Name `xml:"http://www.w3.org/2003/05/soap-envelope Envelope"`
Body Body `xml:"Body"`
}
func main() {
// ... 前面的HTTP请求代码保持不变 ...
var envelope Envelope
err = xml.Unmarshal(body, &envelope)
if err != nil {
panic(err)
}
token := envelope.Body.RequestSecurityTokenResponse.RequestedSecurityToken.BinarySecurityToken
if token.Id == "Compact0" {
fmt.Println("BinarySecurityToken content:", token.Content)
}
}
这种方法通过定义精确的XML结构体映射,可以直接访问Id="Compact0"的BinarySecurityToken元素内容。

