在XML中使用无包装节点的结构数组?

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

Array of struct in XML with no wrapping node?

问题

我有一个客户,他们的 XML 中似乎想要一个库存数组,但是每个项目都在另一个项目之后列出,没有包装节点。

这是我正在做的一个示例,但是每个项目都有一个包装节点。有没有办法让它们都在 "root" 下面直接列出来?

测试代码:

package main

import (
	"encoding/xml"
	"fmt"
	"os"
	"strconv"
)

func main() {
	type InventoryItem struct {
		XMLName         xml.Name
		ItemName        string `xml:"Name"`
		ItemDescription string `xml:"Description"`
	}

	type XMLEnvelop struct {
		XMLName   xml.Name        `xml:"root"`
		Inventory []InventoryItem `xml:",any"`
		Records   int             `xml:"records"`
	}

	var items []InventoryItem

	for i := 1; i < 6; i++ {
		items = append(items, InventoryItem{XMLName: xml.Name{Local: "item" + strconv.Itoa(i)}, ItemName: "Test " + strconv.Itoa(i), ItemDescription: "Description " + strconv.Itoa(i)})
	}

	v := &XMLEnvelop{Records: 1, Inventory: items}

	output, err := xml.MarshalIndent(v, "", "    ")
	if err != nil {
		fmt.Printf("error: %v\n", err)
	}

	// Write the output to check
	os.Stdout.Write(output)

	//Here is where I would make the request

}

测试输出:

<root>
    <item1>
        <Name>Test 1</Name>
        <Description>Description 1</Description>
    </item1>
    <item2>
        <Name>Test 2</Name>
        <Description>Description 2</Description>
    </item2>
    <item3>
        <Name>Test 3</Name>
        <Description>Description 3</Description>
    </item3>
    <item4>
        <Name>Test 4</Name>
        <Description>Description 4</Description>
    </item4>
    <item5>
        <Name>Test 5</Name>
        <Description>Description 5</Description>
    </item5>
    <records>1</records>
</root>

这是他们似乎在寻找的输出...不管出于什么原因。

<root>
    <Name>Test 1</Name>
    <Description>Description 1</Description>
    <Name>Test 2</Name>
    <Description>Description 2</Description>
    <Name>Test 3</Name>
    <Description>Description 3</Description>
    <Name>Test 4</Name>
    <Description>Description 4</Description>
    <Name>Test 5</Name>
    <Description>Description 5</Description>
    <records>1</records>
</root>

Go Playground: https://play.golang.org/p/3DRUaBFEQvC

英文:

I have a customer who has XML where they seem to want an array of inventory, but with each item listed after the other with no wrapping node.

Here is an example of what I'm doing, but with a wrapping node for each item. Is there a way to do it so that they are just all listed one after the other under "root"?

Test code:

package main

import (
	&quot;encoding/xml&quot;
	&quot;fmt&quot;
	&quot;os&quot;
	&quot;strconv&quot;
)

func main() {
	type InventoryItem struct {
		XMLName  xml.Name
		ItemName string `xml:&quot;Name&quot;`
		ItemDescription string `xml:&quot;Description&quot;`
	}

	type XMLEnvelop struct {
		XMLName   xml.Name        `xml:&quot;root&quot;`
		Inventory []InventoryItem `xml:&quot;item&quot;`
		Records   int             `xml:&quot;records&quot;`
	}

	var items []InventoryItem

	for i := 1; i &lt; 6; i++ {
		items = append(items, InventoryItem{XMLName: xml.Name{Local: &quot;item&quot; + strconv.Itoa(i)}, ItemName: &quot;Test &quot; + strconv.Itoa(i), ItemDescription: &quot;Description &quot; + strconv.Itoa(i)})
	}

	v := &amp;XMLEnvelop{Records: 1, Inventory: items}

	output, err := xml.MarshalIndent(v, &quot;&quot;, &quot;    &quot;)
	if err != nil {
		fmt.Printf(&quot;error: %v\n&quot;, err)
	}

	// Write the output to check
	os.Stdout.Write(output)

	//Here is where I would make the request

}

Test Output:

&lt;root&gt;
    &lt;item1&gt;
        &lt;Name&gt;Test 1&lt;/Name&gt;
        &lt;Description&gt;Description 1&lt;/Description&gt;
    &lt;/item1&gt;
    &lt;item2&gt;
        &lt;Name&gt;Test 2&lt;/Name&gt;
        &lt;Description&gt;Description 2&lt;/Description&gt;
    &lt;/item2&gt;
    &lt;item3&gt;
        &lt;Name&gt;Test 3&lt;/Name&gt;
        &lt;Description&gt;Description 3&lt;/Description&gt;
    &lt;/item3&gt;
    &lt;item4&gt;
        &lt;Name&gt;Test 4&lt;/Name&gt;
        &lt;Description&gt;Description 4&lt;/Description&gt;
    &lt;/item4&gt;
    &lt;item5&gt;
        &lt;Name&gt;Test 5&lt;/Name&gt;
        &lt;Description&gt;Description 5&lt;/Description&gt;
    &lt;/item5&gt;
    &lt;records&gt;1&lt;/records&gt;
&lt;/root&gt;

Go Playground: https://play.golang.org/p/3DRUaBFEQvC

This is the output that they seem to be looking for...for whatever reason.

&lt;root&gt;
    &lt;Name&gt;Test 1&lt;/Name&gt;
    &lt;Description&gt;Description 1&lt;/Description&gt;
    &lt;Name&gt;Test 2&lt;/Name&gt;
    &lt;Description&gt;Description 2&lt;/Description&gt;
    &lt;Name&gt;Test 3&lt;/Name&gt;
    &lt;Description&gt;Description 3&lt;/Description&gt;
    &lt;Name&gt;Test 4&lt;/Name&gt;
    &lt;Description&gt;Description 4&lt;/Description&gt;
    &lt;Name&gt;Test 5&lt;/Name&gt;
    &lt;Description&gt;Description 5&lt;/Description&gt;
    &lt;records&gt;1&lt;/records&gt;
&lt;/root&gt;

答案1

得分: 1

你可以实现一个自定义的编组器

type InventoryItem struct {
	XMLName         xml.Name
	ItemName        string `xml:"Name"`
	ItemDescription string `xml:"Description"`
}

func (i InventoryItem) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
    // 忽略传入的 `start` 参数,它表示 Name 和 Description 的父级 InventoryItem 元素。

    // 声明类型来表示要编码的元素,将它们初始化为项的字段值并进行编码。
    //
    // 使用 ",chardata" 选项告诉编码器直接编码字段的值,而不是作为子元素。
	type Name struct {
		Value string `xml:",chardata"`
	}
	if err := e.Encode(Name{i.ItemName}); err != nil {
		return err
	}
	type Description struct {
		Value string `xml:",chardata"`
	}
	return e.Encode(Description{i.ItemDescription})
}

https://play.golang.org/p/D4ZVr2sWZju

英文:

You can implement a custom marshaler.

type InventoryItem struct {
	XMLName         xml.Name
	ItemName        string `xml:&quot;Name&quot;`
	ItemDescription string `xml:&quot;Description&quot;`
}

func (i InventoryItem) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
    // Ignore the passed in `start` argument, it represents the
    // parent InventoryItem element of the Name and Description.

    // Declare types to represent the elements you want to encode,
    // initialize them to the item&#39;s field values and encode them.
    //
    // Use the &quot;,chardata&quot; option to tell the encoder to encode the
    // field&#39;s value directly rather than as a child element. 
	type Name struct {
		Value string `xml:&quot;,chardata&quot;`
	}
	if err := e.Encode(Name{i.ItemName}); err != nil {
		return err
	}
	type Description struct {
		Value string `xml:&quot;,chardata&quot;`
	}
	return e.Encode(Description{i.ItemDescription})
}

https://play.golang.org/p/D4ZVr2sWZju

huangapple
  • 本文由 发表于 2021年11月7日 02:00:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/69866547.html
匿名

发表评论

匿名网友

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

确定