我有一个XML:
<?xml version="1.0" encoding="ASCII"?><QuestionFormAnswers xmlns="http://mechanicalturk.amazonaws.com/AWSMechanicalTurkDataSchemas/2005-10-01/QuestionFormAnswers.xsd"><Answer><QuestionIdentifier>annotatedResult.boundingBoxes</QuestionIdentifier><FreeText>[{"height":641,"label":"F-22 Raptor","left":82,"top":97,"width":1088}]</FreeText></Answer><Answer><QuestionIdentifier>annotatedResult.inputImageProperties.height</QuestionIdentifier><FreeText>839</FreeText></Answer><Answer><QuestionIdentifier>annotatedResult.inputImageProperties.width</QuestionIdentifier><FreeText>1260</FreeText></Answer></QuestionFormAnswers>我不知道如何解析得到[{"height":641,"label":"F-22 Raptor","left":82,"top":97,"width":1088}],并得到单个的值,如height、weight等。最后得到641, 82, 97和1088
我根据我发现的指南试了一下:
type DimensionInfo struct {
Answer struct {
FreeText []string `xml:"freetext"`
} `xml:"answer"`
}
var data = []byte(`<?xml version="1.0" encoding="ASCII"?><QuestionFormAnswers xmlns="http://mechanicalturk.amazonaws.com/AWSMechanicalTurkDataSchemas/2005-10-01/QuestionFormAnswers.xsd"><Answer><QuestionIdentifier>annotatedResult.boundingBoxes</QuestionIdentifier><FreeText>[{"height":641,"label":"F-22 Raptor","left":82,"top":97,"width":1088}]</FreeText></Answer><Answer><QuestionIdentifier>annotatedResult.inputImageProperties.height</QuestionIdentifier><FreeText>839</FreeText></Answer><Answer><QuestionIdentifier>annotatedResult.inputImageProperties.width</QuestionIdentifier><FreeText>1260</FreeText></Answer></QuestionFormAnswers>`)
var t DimensionInfo
xml.Unmarshal(data, &t)
fmt.Println(t.Answer.FreeText)我得到了空的切片/列表
发布于 2020-01-06 16:59:53
问题
有两个问题:
xml.Unmarshal返回被忽略,但函数在指定的输入数据流上失败,因为所谓的XML声明(即<?xml ... ?>位)声明数据流使用与UTF-8不同的编码,而UTF-8是标准指定的唯一有效编码,因此解码器拒绝继续。struct类型字段被标注为标记,提示它必须在数据流中找到的XML节点的所有小写名称都是假的。
因为解码器被明确地告知,例如,查找一个名为"FreeText“的节点,所以它忽略了名为"freetext”的节点,等等。解决方案
XML节点和struct标记的名称
检测感兴趣节点的问题是要解决的简单问题:只要去掉xml:标签,解码器就能找到正确的节点。
另一种解决方案是利用解码器在字段标记中理解“嵌套”名称的能力:您可以使用
type DimensionInfo struct {
FreeText []string `xml:"Answer>FreeText"`
}此标记告诉解码器使用任何名为FreeText的节点的内容填充FreeText字段,该节点直接位于名为Answer的任何节点下。
源数据的编码
编码的问题更麻烦--在一般情况下。
由于表示XML文档的唯一有效编码是UTF-8 (没有BOM),因此解码器期望其源数据为UTF-8编码。
为了处理不同编码的数据流,解码器为程序员提供了一种指定“适配器”的方法,该适配器将透明地将输入数据流重新编码为UTF-8编码的数据流,然后解码器将使用该数据流。
为了做到这一点,您必须构造(并调整) xml.Decoder的实例,而不是直接运行xml.Unmarshal (后者在内部构建一个丢弃的Decoder本身)。
在您的示例中,将对xml.Unmarshal(data, &t)的调用转换为使用显式创建的xml.Decoder很简单:
dec := xml.NewDecoder(bytes.NewReader(data))
if err := dec.Decode(&t); err != nil {
// handle the error
}
// handle the resultDecoder感兴趣的领域是CharsetReader,它是一个函数,如果指定了该函数,则调用它来获取在构造Decoder时指定的源io.Reader和源数据流的字符集(编码),并返回另一个io.Reader,该io.Reader从源读取器中提取数据,将其从源编码重新编码到UTF-8,并将其交给Decoder。
在一般情况下,您可能会使用来自golang.org/x/text/encoding层次结构的几个包,这些包能够理解大量过时的非Unicode和Unicode编码,并从它们向UTF-8提供透明的重新编码。
不过,在您的简单示例中,可能最简单的方法是依赖于ASCII字符的编码方式与它们各自的Unicode代码点使用UTF-8进行编码的方式完全相同;2)假设输入数据流实际上是ASCII (并且不包含代码点在128.255范围内的奇怪字符。在这种情况下,我们可以不用任何重新编码就可以使用源io.Reader,这样我们就可以找到以下解决方案:
var dec = xml.NewDecoder(bytes.NewReader(data))
dec.CharsetReader = func(charset string, input io.Reader) (io.Reader, error) {
switch strings.ToLower(charset) {
case "ascii", "utf-8":
return input, nil
default:
return nil, fmt.Errorf("cannot handle XML encoding: %s", charset)
}
}一个示例解
package main
import (
"bytes"
"encoding/xml"
"fmt"
"io"
"log"
"strings"
)
const data = `<?xml version="1.0" encoding="ASCII"?>
<QuestionFormAnswers xmlns="http://mechanicalturk.amazonaws.com/AWSMechanicalTurkDataSchemas/2005-10-01/QuestionFormAnswers.xsd">
<Answer>
<QuestionIdentifier>annotatedResult.boundingBoxes</QuestionIdentifier>
<FreeText>[{"height":641,"label":"F-22 Raptor","left":82,"top":97,"width":1088}]</FreeText>
</Answer>
<Answer>
<QuestionIdentifier>annotatedResult.inputImageProperties.height</QuestionIdentifier>
<FreeText>839</FreeText>
</Answer>
<Answer>
<QuestionIdentifier>annotatedResult.inputImageProperties.width</QuestionIdentifier>
<FreeText>1260</FreeText>
</Answer>
</QuestionFormAnswers>`
func main() {
type DimensionInfo struct {
FreeText []string `xml:"Answer>FreeText"`
}
var dec = xml.NewDecoder(strings.NewReader(data))
dec.CharsetReader = func(charset string, input io.Reader) (io.Reader, error) {
switch strings.ToLower(charset) {
case "ascii", "utf-8":
return input, nil
default:
return nil, fmt.Errorf("cannot handle XML encoding: %s", charset)
}
}
var t DimensionInfo
err := dec.Decode(&t)
if err != nil {
log.Fatal(err)
}
fmt.Println(t.FreeText)
}严格地说,这不是真的: XML处理器必须理解UTF-8和UTF-16,但是UTF-8是'net‘上事实上的标准。
https://stackoverflow.com/questions/59615418
复制相似问题