为了账号安全,请及时绑定邮箱和手机立即绑定

获取原始元素表示,包括开始和结束标签

获取原始元素表示,包括开始和结束标签

Go
至尊宝的传说 2023-07-31 17:34:39
我知道 golang xml,innerxml标签,它允许将元素内部内容作为原始 xml 获取。但我需要的是获取整个元素(开放标签、内部内容、关闭标签)作为原始数据。这是一个我想以这种方式解析的示例。我想获得整体<Useful>及其所有可能的属性元素,并避免获得无用的元素。package mainimport (    "encoding/xml"    "fmt")const data = `<Document>    <Useless1>        blah-blah    </Useless1>    <Useless2>        blah-blah    </Useless2>    <Useful someAttr="someVal">        <InnerField1>Inner field 1 value</InnerField1>        <InnerField2>Inner field 2 value</InnerField2>        <InnerField3>Inner field 3 value</InnerField3>    </Useful>    <Useless3>        blah-blah    </Useless3></Document>`func main() {    doc := Document{}    err := xml.Unmarshal([]byte(data), &doc)    if err != nil {        panic(err)    }    fmt.Println(doc.Useful.Data)}type Document struct {    XMLName xml.Name `xml:"Document"`    Useful  struct {        Data string `xml:",innerxml"`    } `xml:"Useful"`}游乐场中代码的链接位于: https: //goplay.space/#0KDXiRKDwlY这就是我得到的:    <InnerField1>Inner field 1 value</InnerField1>     <InnerField2>Inner field 2 value</InnerField2>     <InnerField3>Inner field 3 value</InnerField3>这就是我想要得到的:<Useful someAttr="someVal">     <InnerField1>Inner field 1 value</InnerField1>     <InnerField2>Inner field 2 value</InnerField2>     <InnerField3>Inner field 3 value</InnerField3></Useful>请注意,我正在使用的实际结构要复杂得多。我不想将整个<Document>内部内容作为原始 xml 获取,然后对其进行解析,尝试手动删除无用的元素。该<Useful>部分各不相同,因此我无法对例如属性进行硬编码,因为它们可能因一个文档而异。
查看完整描述

1 回答

?
料青山看我应如是

TA贡献1772条经验 获得超7个赞

也捕获属性

您可以在结构中使用附加字段Useful来捕获(类型切片的xml.Attr)所有属性,如下所示:

Useful  struct {

    Attrs []xml.Attr `xml:",any,attr"`

    Data  string     `xml:",innerxml"`

} `xml:"Useful"`

添加另一个属性时<Useful>:


<Useful someAttr="someVal" someAttr2="someVal2">

    ...

<Useful>

并使用 输出结果fmt.Printf("%+v", doc.Useful),输出将是(在Go Playground上尝试一下):

{Attrs:[{Name:{Space: Local:someAttr} Value:someVal} {Name:{Space: Local:someAttr2} Value:someVal2}] Data:
        <InnerField1>Inner field 1 value</InnerField1>
        <InnerField2>Inner field 2 value</InnerField2>
        <InnerField3>Inner field 3 value</InnerField3>
    }

真正获得完整的原始 XML

另一种更复杂的方法是使用xml.Decoder标记读取输入,并标记 的开始和结束位置<Useful>。然后你就可以获得完整的原始XML <Useful>

它可能是这样的:

dec := xml.NewDecoder(strings.NewReader(data))


var start, end int64

foundStart := false

for {

    if !foundStart {

        start = dec.InputOffset()

    }

    t, err := dec.Token()

    if err != nil {

        if err != io.EOF {

            fmt.Println(err)

        }

        break

    }

    if se, ok := t.(xml.StartElement); ok {

        if se.Name.Local == "Useful" {

            foundStart = true

        }

    }

    if se, ok := t.(xml.EndElement); ok {

        if se.Name.Local == "Useful" {

            end = dec.InputOffset()

            // We may break here, we got what we wanted

            break

        }

    }

}


fmt.Println(data[start:end])

它输出(在Go Playground上尝试):


<Useful someAttr="someVal" someAttr2="someVal2">

        <InnerField1>Inner field 1 value</InnerField1>

        <InnerField2>Inner field 2 value</InnerField2>

        <InnerField3>Inner field 3 value</InnerField3>

    </Useful>

由于我们不处理 的内容,因此我们可以通过如下<Useful>使用来加快速度:Decoder.Skip()

dec := xml.NewDecoder(strings.NewReader(data))


var start, end int64

for {

    start = dec.InputOffset()

    t, err := dec.Token()

    if err != nil {

        if err != io.EOF {

            fmt.Println(err)

        }

        break

    }

    if se, ok := t.(xml.StartElement); ok {

        if se.Name.Local != "Useful" {

            continue

        }

        if err := dec.Skip(); err != nil {

            fmt.Println(err)

            break

        }

        end = dec.InputOffset()

        break

    }

}


fmt.Println(data[start:end])

输出是一样的。在Go Playground上试试这个。




查看完整回答
反对 回复 2023-07-31
  • 1 回答
  • 0 关注
  • 78 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信