#xml #floating-point #go
#xml #значение с плавающей запятой #Вперед
Вопрос:
Внешний API, который использует мое приложение, иногда не возвращает значений для одного из полей float64. Когда это происходит, я не могу разархивировать остальную часть документа.
Вот пример кода в Go playground:
http://play.golang.org/p/Twv8b6KCtw
package main
import (
"encoding/xml"
"fmt"
)
func main() {
type Result struct {
XMLName xml.Name `xml:"Person"`
Grade float64 `xml:"grade"`
Name string `xml:"name"`
}
data := `
<Person>
<grade/>
<name>Jack</name>
</Person>
`
var v Result
err := xml.Unmarshal([]byte(data), amp;v)
if err != nil {
fmt.Printf("error: %v", err)
return
}
fmt.Printf("name: %sn", v.Name)
}
Если я изменю float64 в строке 12 на string, это сработает. Есть идеи, как я могу найти обходной путь для этого? Должен ли я просто определять каждое поле как строку и выполнять преобразование вручную?
Ответ №1:
Я полагаю, что вы обнаружили ошибку, вам следует сообщить об этом в системе отслеживания проблем, я отправил отчет об ошибке выпуска 8333.
Теперь для решения текущей проблемы у вас есть 2 варианта:
- Используйте
string
тип, который они ведут в вашем собственном диалоге, чтобы выводить по требованию. - Полностью удалите
<grade/>
тег и используйтеxml:"grade,omitempty"
в своей структуре.
Комментарии:
1. Выполнение преобразования моими силами сводит на нет весь смысл определения всех полей в структурах. На самом деле я не могу использовать опцию omitempty, поскольку внешний API, который я использую, возвращает <grade/>. Возможно, мне следует изменить Unmarshal(), чтобы игнорировать создание подобных пустых элементов.
2. Ну, вы могли бы определить свою функцию диалога в структуре или просто запустить свой xml через
strings.Replace(xml_string, "<grade/>", "", -1)
но это ошибка.3. Отлично. С нетерпением ждем его появления в следующем выпуске.
Ответ №2:
Чтобы добавить к решениям OneOfOne, вы также можете определить свой собственный UnmarshalXML
метод.
Пример (При воспроизведении):
type Grade float64
func (g *Grade) UnmarshalXML(d *xml.Decoder, s xml.StartElement) error {
for tok, err := d.Token(); err != io.EOF; tok, err = d.Token() {
if chrdata, ok := tok.(xml.CharData); ok {
f, err := strconv.ParseFloat(string(chrdata), 64)
if err != nil {
return err
}
*(*float64)(g) = f
}
}
return nil
}
type Result struct {
XMLName xml.Name `xml:"Person"`
Grade Grade `xml:"grade"`
Name string `xml:"name"`
}
Это анализирует <grade>
тег путем поиска CharData
промежуточных токенов и их разбора как float, оставляя оценку на уровне 0.0
, когда нет значения для анализа.