重构Golang XML解析结构体

重构Golang XML解析结构体 我有一个如下所示的结构体

// ReportsImport 原始数据源,用于报告列表。仅使用 SysrptID、Name、FileName。
// 这很混乱,但拆分它似乎会影响反序列化
type ReportsImport struct {
	XMLName xml.Name `xml:"ReportsImport"`
	//Text    string   `xml:",chardata"`
	//Xsi     string   `xml:"xsi,attr"`
	//Xsd     string   `xml:"xsd,attr"`
	Reports struct {
		//	Text         string `xml:",chardata"`
		ReportImport []struct {
			Text         string `xml:",chardata"`
			SysrptID     string `xml:"sysrptID"`
			SQLVersion   string `xml:"sqlVersion"`
			FileName     string `xml:"FileName"`
			Name         string `xml:"Name"`
			ReportImport []struct {
				Text         string `xml:",chardata"`
				SysrptID     string `xml:"sysrptID"`
				SQLVersion   string `xml:"sqlVersion"`
				FileName     string `xml:"FileName"`
				Name         string `xml:"Name"`
				ReportImport []struct {
					Text       string `xml:",chardata"`
					SysrptID   string `xml:"sysrptID"`
					SQLVersion string `xml:"sqlVersion"`
					FileName   string `xml:"FileName"`
					Name       string `xml:"Name"`
				} `xml:"ReportImport"`
			} `xml:"ReportImport"`
		} `xml:"ReportImport"`
	} `xml:"Reports"`
	//Path string `xml:"Path"`
}

用于解析如下所示的 XML 文件

    <?xml version="1.0" encoding="utf-8"?>
<ReportsImport xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Reports>
    <ReportImport>
      <sysrptID>1</sysrptID>
      <sqlVersion>8</sqlVersion>
      <FileName>MDR\Account Statistics.RPT</FileName>
      <Name>MDR - Account Statistics</Name>
    </ReportImport>
    <ReportImport>
      <sysrptID>2</sysrptID>
      <sqlVersion>8</sqlVersion>
      <FileName>CTE\Call Progress.RPT</FileName>
      <Name>CTE - Call Progress</Name>
    </ReportImport>
   
    <ReportImport>
      <sysrptID>295</sysrptID>
      <sqlVersion>9</sqlVersion>
      <FileName>IS\Genesis Account Statistics minutes.rpt</FileName>
      <Name>Genesis - Account Statistics Minutes</Name>
    </ReportImport>
  </Reports>
  <Path>E:\Reports\Version20\</Path>
</ReportsImport>

它能够工作,但我想清理这个结构体并将其拆分为一个列表和单个项目,类似于这样

type Import struct {
   XMLName xml.Name `xml:"ReportsImport"`
   Reports []ReportImport `xml:"Reports"`
}
type ReportImport struct {
	XMLName xml.Name `xml:"ReportImport"`
	Text       string `xml:",chardata"`
	SysrptID   string `xml:"sysrptID"`
	SQLVersion string `xml:"sqlVersion"`
	FileName   string `xml:"FileName"`
	Name       string `xml:"Name"`
}

但是当我这样做时,集合是 nil 或长度为零,不确定我遗漏了什么。

这个 XML 有点奇怪,但它是一个旧项目[为其生成的],我无法控制。


更多关于重构Golang XML解析结构体的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于重构Golang XML解析结构体的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


根据你的XML结构,问题在于XML中的Reports元素包含的是ReportImport子元素,但你的结构体定义中Reports字段的类型是[]ReportImport,而实际上它应该是一个包含ReportImport切片的结构体。

以下是正确的重构方案:

package main

import (
    "encoding/xml"
    "fmt"
)

type Import struct {
    XMLName xml.Name `xml:"ReportsImport"`
    Reports Reports  `xml:"Reports"`
}

type Reports struct {
    ReportImport []ReportImport `xml:"ReportImport"`
}

type ReportImport struct {
    SysrptID   string `xml:"sysrptID"`
    SQLVersion string `xml:"sqlVersion"`
    FileName   string `xml:"FileName"`
    Name       string `xml:"Name"`
}

func main() {
    xmlData := `<?xml version="1.0" encoding="utf-8"?>
<ReportsImport xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Reports>
    <ReportImport>
      <sysrptID>1</sysrptID>
      <sqlVersion>8</sqlVersion>
      <FileName>MDR\Account Statistics.RPT</FileName>
      <Name>MDR - Account Statistics</Name>
    </ReportImport>
    <ReportImport>
      <sysrptID>2</sysrptID>
      <sqlVersion>8</sqlVersion>
      <FileName>CTE\Call Progress.RPT</FileName>
      <Name>CTE - Call Progress</Name>
    </ReportImport>
    <ReportImport>
      <sysrptID>295</sysrptID>
      <sqlVersion>9</sqlVersion>
      <FileName>IS\Genesis Account Statistics minutes.rpt</FileName>
      <Name>Genesis - Account Statistics Minutes</Name>
    </ReportImport>
  </Reports>
  <Path>E:\Reports\Version20\</Path>
</ReportsImport>`

    var data Import
    err := xml.Unmarshal([]byte(xmlData), &data)
    if err != nil {
        fmt.Printf("Error: %v\n", err)
        return
    }

    fmt.Printf("Total reports: %d\n", len(data.Reports.ReportImport))
    for i, report := range data.Reports.ReportImport {
        fmt.Printf("Report %d: ID=%s, Name=%s\n", i+1, report.SysrptID, report.Name)
    }
}

如果你想要更简洁的结构,也可以使用嵌套切片:

type Import struct {
    XMLName xml.Name       `xml:"ReportsImport"`
    Reports []ReportImport `xml:"Reports>ReportImport"`
}

type ReportImport struct {
    SysrptID   string `xml:"sysrptID"`
    SQLVersion string `xml:"sqlVersion"`
    FileName   string `xml:"FileName"`
    Name       string `xml:"Name"`
}

func main() {
    xmlData := `<?xml version="1.0" encoding="utf-8"?>
<ReportsImport xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Reports>
    <ReportImport>
      <sysrptID>1</sysrptID>
      <sqlVersion>8</sqlVersion>
      <FileName>MDR\Account Statistics.RPT</FileName>
      <Name>MDR - Account Statistics</Name>
    </ReportImport>
  </Reports>
</ReportsImport>`

    var data Import
    err := xml.Unmarshal([]byte(xmlData), &data)
    if err != nil {
        fmt.Printf("Error: %v\n", err)
        return
    }

    fmt.Printf("Total reports: %d\n", len(data.Reports))
}

两种方案都能正确解析你的XML数据。第一种方案更符合XML的层次结构,第二种方案使用xml:"Reports>ReportImport"标签来直接映射嵌套元素。

回到顶部