首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何用片格式解析XML

如何用片格式解析XML
EN

Stack Overflow用户
提问于 2020-01-06 16:14:53
回答 1查看 226关注 0票数 0

我有一个XML:

代码语言:javascript
运行
复制
   <?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}],并得到单个的值,如heightweight等。最后得到641, 82, 971088

我根据我发现的指南试了一下:

代码语言:javascript
运行
复制
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)

我得到了空的切片/列表

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-01-06 16:59:53

问题

有两个问题:

  1. 错误xml.Unmarshal返回被忽略,但函数在指定的输入数据流上失败,因为所谓的XML声明(即<?xml ... ?>位)声明数据流使用与UTF-8不同的编码,而UTF-8是标准指定的唯一有效编码,因此解码器拒绝继续。
  2. 要接收解码后的数据位的struct类型字段被标注为标记,提示它必须在数据流中找到的XML节点的所有小写名称都是假的。 因为解码器被明确地告知,例如,查找一个名为"FreeText“的节点,所以它忽略了名为"freetext”的节点,等等。

解决方案

XML节点和struct标记的名称

检测感兴趣节点的问题是要解决的简单问题:只要去掉xml:标签,解码器就能找到正确的节点。

另一种解决方案是利用解码器在字段标记中理解“嵌套”名称的能力:您可以使用

代码语言:javascript
运行
复制
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很简单:

代码语言:javascript
运行
复制
dec := xml.NewDecoder(bytes.NewReader(data))
if err := dec.Decode(&t); err != nil {
    // handle the error
}
// handle the result

Decoder感兴趣的领域是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,这样我们就可以找到以下解决方案:

代码语言:javascript
运行
复制
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)
    }
}

一个示例解

代码语言:javascript
运行
复制
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‘上事实上的标准。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59615418

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档