Преобразуйте XML-тег в логическое значение, если он существует при отмене сопоставления

#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)