如何绕过深层次的 XML,而不使用嵌套循环?

huangapple go评论2191阅读模式
英文:

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 (
&quot;encoding/xml&quot;
&quot;fmt&quot;
)
type Obj struct {
Scripts []*Script `xml:&quot;scripts&gt;script&quot;`
}
type Script struct {
ID     string   `xml:&quot;id&quot;`
Tables []*Table `xml:&quot;tables&gt;table&quot;`
}
type Table struct {
Elements []*Element `xml:&quot;elements&gt;element&quot;`
Tables   []*Table   `xml:&quot;tables&gt;table&quot;`
}
type Element struct {
Key string `xml:&quot;key&quot;`
Val string `xml:&quot;val&quot;`
}
func main() {
// Example XML data
xmlData := `
&lt;obj&gt;
&lt;scripts&gt;
&lt;script&gt;
&lt;id&gt;requireID&lt;/id&gt;
&lt;tables&gt;
&lt;table&gt;
&lt;elements&gt;
&lt;element&gt;
&lt;key&gt;requireKey&lt;/key&gt;
&lt;val&gt;value1&lt;/val&gt;
&lt;/element&gt;
&lt;/elements&gt;
&lt;tables&gt;
&lt;table&gt;
&lt;elements&gt;
&lt;element&gt;
&lt;key&gt;requireKey&lt;/key&gt;
&lt;val&gt;value2&lt;/val&gt;
&lt;/element&gt;
&lt;/elements&gt;
&lt;/table&gt;
&lt;/tables&gt;
&lt;/table&gt;
&lt;/tables&gt;
&lt;/script&gt;
&lt;/scripts&gt;
&lt;/obj&gt;
`
var obj Obj
err := xml.Unmarshal([]byte(xmlData), &amp;obj)
if err != nil {
fmt.Println(&quot;Error:&quot;, err)
return
}
// Call the iterative function to find elements with specific ID and Key
elements := findElements(&quot;requireID&quot;, &quot;requireKey&quot;, &amp;obj)
for _, el := range elements {
fmt.Println(&quot;Element Key:&quot;, el.Key, &quot;Value:&quot;, 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) &gt; 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
}

huangapple
  • 本文由 发表于 2023年7月30日 18:30:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/76797339.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定