英文:
How to bypass deep xml, no nested loops?
问题
我有一个深层嵌套的 XML 对象:
type Obj struct{
Scripts []*Script `xml:"scripts"`
}
type Script struct{
ID string `xml:"id"`
Tables []*Table `xml:"tables"`
}
type Table struct{
Elements []*Element `xml:"elements"`
Tables []*Table `xml:"tables"`
}
type Element struct{
Key string `xml:"key"`
Val string `xml:"val"`
}
我需要从对象中获取具有正确键的 Element 列表。如何在没有嵌套循环的情况下完成这个任务:
for _, s := range obj {
if s.ID == "requireID" {
for _, table := range s.Tables {
for _, t := range table.Tables {
for _, el := range t.Elements {
if el.Key == "requireKey" {
elements = append(elements, el)
}
}
}
}
}
}
英文:
I have deep nested xml object:
type Obj struct{
Scripts []*Script `xml:"scripts"`
}
type Script struct{
ID string `xml:"id"`
Tables []*Table `xml:"tables"`
}
type Table struct{
Elements []*Element `xml:"elements"`
Tables []*Table `xml:"tables"`
}
type Element struct{
Key string `xml:"key"`
Val string `xml:"val"`
}
I need to get a list of Element from Object with the right keys.How can this be done without a nested loop:
for _, s:= range obj{
if s.ID == "requireID"{
for _, table:= range s.Tables{
for _, t:= range table.Tables{
for _, el:= range t.Elements{
if el.Key == "requireKey"{
elements = elements.append(elements, el)
}
}
}
}
}
}
}
答案1
得分: 2
这是一个使用堆栈的完整工作解决方案。它比使用嵌套循环更复杂:
package main
import (
"encoding/xml"
"fmt"
)
type Obj struct {
Scripts []*Script `xml:"scripts>script"`
}
type Script struct {
ID string `xml:"id"`
Tables []*Table `xml:"tables>table"`
}
type Table struct {
Elements []*Element `xml:"elements>element"`
Tables []*Table `xml:"tables>table"`
}
type Element struct {
Key string `xml:"key"`
Val string `xml:"val"`
}
func main() {
// 示例 XML 数据
xmlData := `
<obj>
<scripts>
<script>
<id>requireID</id>
<tables>
<table>
<elements>
<element>
<key>requireKey</key>
<val>value1</val>
</element>
</elements>
<tables>
<table>
<elements>
<element>
<key>requireKey</key>
<val>value2</val>
</element>
</elements>
</table>
</tables>
</table>
</tables>
</script>
</scripts>
</obj>
`
var obj Obj
err := xml.Unmarshal([]byte(xmlData), &obj)
if err != nil {
fmt.Println("Error:", err)
return
}
// 调用迭代函数查找具有特定 ID 和 Key 的元素
elements := findElements("requireID", "requireKey", &obj)
for _, el := range elements {
fmt.Println("Element Key:", el.Key, "Value:", el.Val)
}
}
// 辅助函数,将切片转换为 []interface{} 切片
func toInterfaceSlice(slice interface{}) []interface{} {
s := make([]interface{}, 0)
switch slice.(type) {
case []*Script:
for _, v := range slice.([]*Script) {
s = append(s, v)
}
case []*Table:
for _, v := range slice.([]*Table) {
s = append(s, v)
}
case []*Element:
for _, v := range slice.([]*Element) {
s = append(s, v)
}
}
return s
}
func findElements(requiredID, requiredKey string, rootObj interface{}) []*Element {
var elements []*Element
stack := []interface{}{rootObj}
for len(stack) > 0 {
// 从堆栈中弹出顶部元素
obj := stack[len(stack)-1]
stack = stack[:len(stack)-1]
switch v := obj.(type) {
case *Obj:
for _, script := range v.Scripts {
if script.ID == requiredID {
stack = append(stack, script)
}
}
case *Script:
stack = append(stack, toInterfaceSlice(v.Tables)...)
case *Table:
for _, el := range v.Elements {
if el.Key == requiredKey {
elements = append(elements, el)
}
}
stack = append(stack, toInterfaceSlice(v.Tables)...)
}
}
return elements
}
希望对你有帮助!
英文:
This is a complete working solution using stack. It is more complex than using nested loops:
package main
import (
"encoding/xml"
"fmt"
)
type Obj struct {
Scripts []*Script `xml:"scripts>script"`
}
type Script struct {
ID string `xml:"id"`
Tables []*Table `xml:"tables>table"`
}
type Table struct {
Elements []*Element `xml:"elements>element"`
Tables []*Table `xml:"tables>table"`
}
type Element struct {
Key string `xml:"key"`
Val string `xml:"val"`
}
func main() {
// Example XML data
xmlData := `
<obj>
<scripts>
<script>
<id>requireID</id>
<tables>
<table>
<elements>
<element>
<key>requireKey</key>
<val>value1</val>
</element>
</elements>
<tables>
<table>
<elements>
<element>
<key>requireKey</key>
<val>value2</val>
</element>
</elements>
</table>
</tables>
</table>
</tables>
</script>
</scripts>
</obj>
`
var obj Obj
err := xml.Unmarshal([]byte(xmlData), &obj)
if err != nil {
fmt.Println("Error:", err)
return
}
// Call the iterative function to find elements with specific ID and Key
elements := findElements("requireID", "requireKey", &obj)
for _, el := range elements {
fmt.Println("Element Key:", el.Key, "Value:", el.Val)
}
}
// Helper function to convert slice to []interface{} slice
func toInterfaceSlice(slice interface{}) []interface{} {
s := make([]interface{}, 0)
switch slice.(type) {
case []*Script:
for _, v := range slice.([]*Script) {
s = append(s, v)
}
case []*Table:
for _, v := range slice.([]*Table) {
s = append(s, v)
}
case []*Element:
for _, v := range slice.([]*Element) {
s = append(s, v)
}
}
return s
}
func findElements(requiredID, requiredKey string, rootObj interface{}) []*Element {
var elements []*Element
stack := []interface{}{rootObj}
for len(stack) > 0 {
// Pop the top element from the stack
obj := stack[len(stack)-1]
stack = stack[:len(stack)-1]
switch v := obj.(type) {
case *Obj:
for _, script := range v.Scripts {
if script.ID == requiredID {
stack = append(stack, script)
}
}
case *Script:
stack = append(stack, toInterfaceSlice(v.Tables)...)
case *Table:
for _, el := range v.Elements {
if el.Key == requiredKey {
elements = append(elements, el)
}
}
stack = append(stack, toInterfaceSlice(v.Tables)...)
}
}
return elements
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论