#xml #go #unmarshalling
# #xml #Вперед #отмена сопоставления
Вопрос:
Я пытаюсь преобразовать XML-тег в логическое значение, если он существует. Теги внутри <status>
могут быть <active />
, <available />
или <invalid />
и только один из этих тегов существует внутри <status>
.
Вот моя текущая попытка:
package main
import (
"encoding/xml"
"fmt"
)
type Response struct {
XMLName xml.Name `xml:"domain"`
Authority string `xml:"authority,attr"`
RegistryType string `xml:"registryType,attr"`
EntityClass string `xml:"entityClass,attr"`
EntityName string `xml:"entityName,attr"`
DomainName string `xml:"domainName"`
Status Status `xml:"status"`
}
type Status struct {
Active bool `xml:"active,omitempty"`
Available bool `xml:"available,omitempty"`
Invalid bool `xml:"invalid,omitempty"`
}
func main() {
str := `
<domain authority="domain.fi" registryType="dchk1" entityClass="domain-name" entityName="esimerkki.fi">
<domainName>esimerkki.fi</domainName>
<status>
<active />
</status>
</domain>
`
var ans Response
err := xml.Unmarshal([]byte(str), amp;ans)
if err != nil {
panic(err)
}
fmt.Printf(`%#v`, ans.Status)
}
Это возвращает все Status.*
как false
, а не Status.Active = true
как ожидалось. Как вы можете получить ожидаемый результат?
Вторая попытка с указателями:
type Status struct {
Active *bool `xml:"active,omitempty"`
Available *bool `xml:"available,omitempty"`
Invalid *bool `xml:"invalid,omitempty"`
}
*ans.Status.Active
тем не менее false
.
Комментарии:
1. Вы пытались установить для активного свойства значение
*bool
? Если это работает, то вам нужно проверить указатель nil / non nil, а не логическое значение.2. @mh-cbon Теперь у меня есть и не работает. Также добавлено это к вопросу.
3. я думаю, мы неправильно поняли. В этом воспроизведении play.golang.org/p/9ARvyErrQ8A , когда тег присутствует, свойству будет присвоено нулевое значение (nil bool со значением false). Когда тег отсутствует, свойству присваивается значение nil, что означает, что тег отсутствует. Я не думаю, что вы можете получить статус. Active = true, если только вы не внедрили специальный тип unmarshaler, но вы можете обнаружить присутствие / отсутствие с учетом свойств nil / not nil.
4. @mh-cbon понял это и ответил 🙂
Ответ №1:
Как предложил @mh-cbon, достаточно просто проверить, был ли указатель не nil
для *bool
, чтобы определить, существовал ли этот тег. Но я пошел и превратил структуру ответа XML в правильную Response
структуру, которая содержит только необходимую информацию, и Status
в константу.
Итак, теперь это:
// Raw XML DTO
type XmlResponse struct {
XMLName xml.Name `xml:"domain"`
Authority string `xml:"authority,attr"`
RegistryType string `xml:"registryType,attr"`
EntityClass string `xml:"entityClass,attr"`
EntityName string `xml:"entityName,attr"`
DomainName string `xml:"domainName"`
Status XmlStatus `xml:"status"`
}
// Raw XML DTO
type XmlStatus struct {
Active *bool `xml:"active,omitempty"`
Available *bool `xml:"available,omitempty"`
Invalid *bool `xml:"invalid,omitempty"`
}
// Return Response struct which doesn't have the unnecessary XML
func (x XmlResponse) GetResponse() Response {
st := Invalid // Default to invalid
if x.Status.Active != nil {
st = Active
} else if x.Status.Available != nil {
st = Available
} else if x.Status.Invalid != nil {
st = Invalid
}
return Response{
Domain: x.DomainName,
Status: st,
}
}
// Proper response parsed from XML
type Response struct {
Domain string
Status Status
}
type Status uint8
const (
Invalid Status = iota
Active
Available
)
И синтаксический анализ происходит следующим образом:
var xmlresp XmlResponse
err := xml.Unmarshal([]byte(str), amp;xmlresp)
if err != nil {
panic(err)
}
ans := xmlresp.GetResponse()
fmt.Printf(`%#v`, ans)