首页 > 解决方案 > 是否可以在不解析其子元素的情况下流式解析 XML 父元素?

问题描述

给定以下 XML:

<Report name="scan_against_stuff">
    <ReportHost>
        ....
    </ReportHost>
    <ReportHost>
        ....
    </ReportHost>
    <ReportHost>
        ....
    </ReportHost>
    <ReportHost>
        ....
    </ReportHost>
    <ReportHost>
        ....
    </ReportHost>
</Report>

我想在 Go 中流式解析这个 XML。特别是,我想流式解析<ReportHost>元素,而不是一次将它们全部加载到内存中。问题是我还想检索元素的name属性。<Report>为什么这是个问题?好吧,我熟悉的流解析方法需要我解析整个<Report>元素,这将包括所有<ReportHost>元素,因为它们是元素的子<Report>元素。有什么方法可以让我在<Report>不解析子元素的情况下解析父<ReportHost>元素?

编辑

根据 Volker 的评论,我正在编辑此内容以进行澄清。使用下面的代码,块永远不会else if ty.Local.Name == "ReportHost"触发,而如果块被删除(并更改为),它会触发。我认为这是因为一旦元素被丢弃,作为其子元素的元素就不再可用于处理。"ty.Local.Name == "Report"else ififReportReportHost

parsexml.go

type ReportName struct {
    Name string `xml:"name,attr"`
}

type ReportHost struct{
   ....
}

d := xml.NewDecoder(f)
    for {
        tok, err := d.Token()
        if tok == nil || err == io.EOF {
            // EOF means we're done.
            break
        } else if err != nil {
            log.Fatalf("Error decoding token: %s", err)
        }
        //
        switch element := tok.(type) {
        case xml.StartElement:
            if element.Name.Local == "Report" {
                if err = d.DecodeElement(&reportName, &element); err != nil {
                    log.Fatalf("Error decoding item: %s", err)
                }
            else if element.Name.Local == "ReportHost" {
                if err = d.DecodeElement(&reportHost, &element); err != nil {
                    log.Fatalf("Error decoding item: %s", err)
                }
            }
                

标签: xmlgo

解决方案


decode 方法会吞噬元素的所有子元素。要通过元素的子元素进行流式传输,请直接访问元素的属性,而不是使用 decode。

    switch element := tok.(type) {
    case xml.StartElement:
        if element.Name.Local == "Report" {

            // Look for report name in attributes.
            for _, attr := range element.Attr {
                if attr.Name.Local == "name" {
                    fmt.Println("name =", attr.Value)
                }
            }

        } else if element.Name.Local == "ReportHost" {
            var reportHost ReportHost
            if err = d.DecodeElement(&reportHost, &element); err != nil {
                log.Fatalf("Error decoding item: %s", err)
            }
            fmt.Println("host =", reportHost.Data)
        }
    }

在操场上运行它


推荐阅读