C#将对象序列化为包含对象列表的XML

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

C# Serializing an object into XML that includes a list of objects

问题

我需要将XML序列化以附加到API PUT请求。

我正在使用System.Xml.Serialization。

最终结果需要类似于以下内容:

<?xml version="1.0" encoding="UTF-8"?>
<prestashop xmlns:xlink="http://www.w3.org/1999/xlink">
    <product>
        <id>
            <![CDATA[2678]]>
        </id>
        <cache_default_attribute>
            <![CDATA[0]]>
        </cache_default_attribute>
        <id_shop_default>
            <![CDATA[1]]>
        </id_shop_default>
        <reference>
            <![CDATA[2678]]>
        </reference>
        <supplier_reference>
            <![CDATA[]]>
        </supplier_reference>
        <location>
            <![CDATA[]]>
        </location>
        <width>
            <![CDATA[0.000000]]>
        </width>
        <height>
            <![CDATA[0.000000]]>
        </height>
        <depth>
            <![CDATA[0.000000]]>
        </depth>
        <weight>
            <![CDATA[0.000000]]>
        </weight>
        <quantity_discount>
            <![CDATA[0]]>
        </quantity_discount>
        <ean13>
            <![CDATA[]]>
        </ean13>
        <isbn>
            <![CDATA[]]>
        </isbn>
        <upc>
            <![CDATA[0]]>
        </upc>
        <mpn>
            <![CDATA[000.018]]>
        </mpn>
        <cache_is_pack>
            <![CDATA[0]]>
        </cache_is_pack>
        <cache_has_attachments>
            <![CDATA[0]]>
        </cache_has_attachments>
        <is_virtual>
            <![CDATA[0]]>
        </is_virtual>
        <state>
            <![CDATA[1]]>
        </state>
        <additional_delivery_times>
            <![CDATA[1]]>
        </additional_delivery_times>
        <delivery_in_stock>
            <language id="1">
                <![CDATA[]]>
            </language>
            <language id="2">
                <![CDATA[]]>
            </language>
        </delivery_in_stock>
        <delivery_out_stock>
            <language id="1">
                <![CDATA[]]>
            </language>
            <language id="2">
                <![CDATA[]]>
            </language>
        </delivery_out_stock>
        <product_type>
            <![CDATA[combinations]]>
        </product_type>
        <on_sale>
            <![CDATA[0]]>
        </on_sale>
        <online_only>
            <![CDATA[0]]>
        </online_only>
        <date_add>
            <![CDATA[2023-02-16 00:21:12]]>
        </date_add>
        <date_upd>
            <![CDATA[2023-02-22 17:22:23]]>
        </date_upd>
        <name>
            <language id="1">
                <![CDATA[ETNIES TRI LAM POLO (000.018)]]
            </language>
            <language id="2">
                <![CDATA[ETNIES TRI LAM POLO (000.018)]]
            </language>
        </name>
    </product>
</prestashop>

为此,我有一个类如下:

[XmlType("product")]
public class Product
{
    public Product()
    {
        id = "";
        active = "1";
        available_for_order = "1";
        indexed = "1";
        visibility = "both";
        delivery_in_stock = new List<PaLanguage>();
        delivery_out_stock = new List<PaLanguage>();
        name = new List<PaLanguage>();
    }

    [XmlElement("id")]
    public XmlCDataSection C_id
    {
        get { return new XmlDocument().CreateCDataSection(id); }
        set { id = value.Value; }
    }
    [XmlIgnore]
    public string id;
    [XmlElement("cache_default_attribute")]
    public XmlCDataSection C_cache_default_attribute
    {
        get { return new XmlDocument().CreateCDataSection(cache_default_attribute); }
        set { cache_default_attribute = value.Value; }
    }
    [XmlIgnore]
    public string cache_default_attribute;
    ...
    [XmlArray("delivery_in_stock")]
    public List<PaLanguage> delivery_in_stock;
    [XmlArray("delivery_out_stock")]
    public List<PaLanguage> delivery_out_stock;
    ...
}

PaLanguage类如下:

public class PaLanguage
{
    [XmlElement("language")]
    public XmlCDataSection C_language
    {
        get { return new XmlDocument().CreateCDataSection(language); }
        set { language = value.Value; }
    }
    [XmlIgnore]
    public string language { get; set; }
    [XmlAttribute("id")]
    public string id;
}

因为这是更新记录,我首先完成一个GET请求,然后匹配所有其值。我使用以下代码来完成这个任务:

XDocument getResponse = Helper.GetProductReference(get, Helper.GetValueByKey("ShopApi") + "products/");
var gotProduct = getResponse
    .Element("prestashop")
    .Element("products")
    .Elements("product")
    .Where(e => e.Element("reference").Value == mtrl)
    .Single();

我创建一个新的Product项目以附加到我的PUT请求,但我在序列化其XmlArrays方面遇到了问题。我最后尝试的是以下内容:

foreach (XElement x in gotProduct.Element("delivery_in_stock").Elements("language"))
{
    product.delivery_in_stock.Add(new PrestaLanguage { id = (string)x.Attribute("id"), language = (string)x.Element("language") });
}

这是完全错误的,因为它将其序列化为:

<product>
<id><![CDATA[2678]]></id>
... xml
<delivery_in_stock>
  <PaLanguage id="1">
    <language><![CDATA[]]></language>
  </PaLanguage>
  <PaLanguage id="2">
    <language><![CDATA[]]></language>
  </PaLanguage>
</delivery_in_stock>

感觉我已经尝试过网络上和官方文档中能找到的一切,每次尝试都离我预期的结果更远。

我应该指出,实际上该类还有几十个字段,它们要么是一个字符串,要么是id和语言值的组合。

非常感谢您的任何帮助。

英文:

I need to serialize an XML to attach for an API PUT request.

I am using System.Xml.Serialization.

The end result needs to resemble the following:

&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;prestashop xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot;&gt;
        &lt;product&gt;
            &lt;id&gt;
                &lt;![CDATA[2678]]&gt;
            &lt;/id&gt;
            &lt;cache_default_attribute&gt;
                &lt;![CDATA[0]]&gt;
            &lt;/cache_default_attribute&gt;
            &lt;id_shop_default&gt;
                &lt;![CDATA[1]]&gt;
            &lt;/id_shop_default&gt;
            &lt;reference&gt;
                &lt;![CDATA[2678]]&gt;
            &lt;/reference&gt;
            &lt;supplier_reference&gt;
                &lt;![CDATA[]]&gt;
            &lt;/supplier_reference&gt;
            &lt;location&gt;
                &lt;![CDATA[]]&gt;
            &lt;/location&gt;
            &lt;width&gt;
                &lt;![CDATA[0.000000]]&gt;
            &lt;/width&gt;
            &lt;height&gt;
                &lt;![CDATA[0.000000]]&gt;
            &lt;/height&gt;
            &lt;depth&gt;
                &lt;![CDATA[0.000000]]&gt;
            &lt;/depth&gt;
            &lt;weight&gt;
                &lt;![CDATA[0.000000]]&gt;
            &lt;/weight&gt;
            &lt;quantity_discount&gt;
                &lt;![CDATA[0]]&gt;
            &lt;/quantity_discount&gt;
            &lt;ean13&gt;
                &lt;![CDATA[]]&gt;
            &lt;/ean13&gt;
            &lt;isbn&gt;
                &lt;![CDATA[]]&gt;
            &lt;/isbn&gt;
            &lt;upc&gt;
                &lt;![CDATA[0]]&gt;
            &lt;/upc&gt;
            &lt;mpn&gt;
                &lt;![CDATA[000.018]]&gt;
            &lt;/mpn&gt;
            &lt;cache_is_pack&gt;
                &lt;![CDATA[0]]&gt;
            &lt;/cache_is_pack&gt;
            &lt;cache_has_attachments&gt;
                &lt;![CDATA[0]]&gt;
            &lt;/cache_has_attachments&gt;
            &lt;is_virtual&gt;
                &lt;![CDATA[0]]&gt;
            &lt;/is_virtual&gt;
            &lt;state&gt;
                &lt;![CDATA[1]]&gt;
            &lt;/state&gt;
            &lt;additional_delivery_times&gt;
                &lt;![CDATA[1]]&gt;
            &lt;/additional_delivery_times&gt;
            &lt;delivery_in_stock&gt;
                &lt;language id=&quot;1&quot;&gt;
                    &lt;![CDATA[]]&gt;
                &lt;/language&gt;
                &lt;language id=&quot;2&quot;&gt;
                    &lt;![CDATA[]]&gt;
                &lt;/language&gt;
            &lt;/delivery_in_stock&gt;
            &lt;delivery_out_stock&gt;
                &lt;language id=&quot;1&quot;&gt;
                    &lt;![CDATA[]]&gt;
                &lt;/language&gt;
                &lt;language id=&quot;2&quot;&gt;
                    &lt;![CDATA[]]&gt;
                &lt;/language&gt;
            &lt;/delivery_out_stock&gt;
            &lt;product_type&gt;
                &lt;![CDATA[combinations]]&gt;
            &lt;/product_type&gt;
            &lt;on_sale&gt;
                &lt;![CDATA[0]]&gt;
            &lt;/on_sale&gt;
            &lt;online_only&gt;
                &lt;![CDATA[0]]&gt;
            &lt;/online_only&gt;
            &lt;date_add&gt;
                &lt;![CDATA[2023-02-16 00:21:12]]&gt;
            &lt;/date_add&gt;
            &lt;date_upd&gt;
                &lt;![CDATA[2023-02-22 17:22:23]]&gt;
            &lt;/date_upd&gt;
            &lt;name&gt;
                &lt;language id=&quot;1&quot;&gt;
                    &lt;![CDATA[ETNIES TRI LAM POLO (000.018)]]&gt;
                &lt;/language&gt;
                &lt;language id=&quot;2&quot;&gt;
                    &lt;![CDATA[ETNIES TRI LAM POLO (000.018)]]&gt;
                &lt;/language&gt;
            &lt;/name&gt;
        &lt;/product&gt;
&lt;/prestashop&gt;

For this purpose I have a class like this:

[XmlType(&quot;product&quot;)]
public class Product
{
    public Product()
    {
        id = &quot;&quot;;
        active = &quot;1&quot;;
        available_for_order= &quot;1&quot;;
        indexed= &quot;1&quot;;
        visibility = &quot;both&quot;;
        delivery_in_stock = new List&lt;PaLanguage&gt;();
        delivery_out_stock = new List&lt;PaLanguage&gt;();
        name = new List&lt;PaLanguage&gt;();
    }

    [XmlElement(&quot;id&quot;)] public XmlCDataSection C_id { get { return new XmlDocument().CreateCDataSection(id); } set { id = value.Value; } }
    [XmlIgnore] public string id;
    [XmlElement(&quot;cache_default_attribute&quot;)] public XmlCDataSection C_cache_default_attribute { get { return new XmlDocument().CreateCDataSection(cache_default_attribute); } set {cache_default_attribute = value.Value; } }
    [XmlIgnore] public string cache_default_attribute;
    ...
    [XmlArray(&quot;delivery_in_stock&quot;)] public List&lt;PaLanguage&gt; delivery_in_stock;
    [XmlArray(&quot;delivery_out_stock&quot;)] public List&lt;PaLanguage&gt; delivery_out_stock;
    ...

With PaLanguage being:

public class PaLanguage
{
    [XmlElement(&quot;language&quot;)] public XmlCDataSection C_language { get { return new XmlDocument().CreateCDataSection(language); } set { language = value.Value; } }
    [XmlIgnore] public string language { get; set; }
    [XmlAttribute(&quot;id&quot;)] public string id;
}

Because this is updating a record I first complete a get request and then match all of its values.
I accomplish this with the following code:

XDocument getResponse = Helper.GetProductReference(get, Helper.GetValueByKey(&quot;ShopApi&quot;) + &quot;products/&quot;);
var gotProduct = getResponse
    .Element(&quot;prestashop&quot;)
    .Element(&quot;products&quot;)
    .Elements(&quot;product&quot;)
    .Where(e =&gt; e.Element(&quot;reference&quot;).Value == mtrl)
    .Single();  

I create a new Product item to attach to my put request but I have trouble serializing its XmlArrays.

The last thing I tried was the following:

foreach (XElement x in gotProduct.Element(&quot;delivery_in_stock&quot;).Elements(&quot;language&quot;))
{
    product.delivery_in_stock.Add(new PrestaLanguage { id = (string)x.Attribute(&quot;id&quot;), language = (string)x.Element(&quot;language&quot;) });
}

Which is completely wrong because it serializes it as:

&lt;product&gt;
&lt;id&gt;&lt;![CDATA[2678]]&gt;&lt;/id&gt;
... xml
&lt;delivery_in_stock&gt;
  &lt;PaLanguage id=&quot;1&quot;&gt;
    &lt;language&gt;&lt;![CDATA[]]&gt;&lt;/language&gt;
  &lt;/PaLanguage&gt;
  &lt;PaLanguage id=&quot;2&quot;&gt;
    &lt;language&gt;&lt;![CDATA[]]&gt;&lt;/language&gt;
  &lt;/PaLanguage&gt;
&lt;/delivery_in_stock&gt;

It feels like I've tried everything one can find online and in official documentation and only get further from my intended result with each attempt.

I should note the class actually has dozens more fields and they're all either just a string or another combination of id and a language value.

Any and all help is appreciated.

答案1

得分: 0

在XML中,delivery_in_stockdelivery_out_stock元素似乎可以包含具有不同id属性的多个language元素。因此,您需要修改foreach循环以处理多个language元素。

不要使用Elements("language"),而应该使用Descendants("language") 来获取delivery_in_stockdelivery_out_stock下的所有language元素。

foreach (XElement x in gotProduct.Element("delivery_in_stock").Descendants("language"))
{
    product.delivery_in_stock.Add(new PaLanguage { id = (string)x.Attribute("id"), language = (string)x });
}

foreach (XElement x in gotProduct.Element("delivery_out_stock").Descendants("language"))
{
    product.delivery_out_stock.Add(new PaLanguage { id = (string)x.Attribute("id"), language = (string)x });
}

此外,在PaLanguage类中,language属性应该是XmlCDataSection类型,而不是字符串,因为它包含CDATA。

public class PaLanguage
{
    [XmlText]
    public XmlCDataSection language { get; set; }

    [XmlAttribute("id")]
    public string id { get; set; }
}

最后,在product类中,您应该为那些没有[XmlElement]属性的属性添加[XmlElement]属性,如id_shop_defaultreferencesupplier_reference等。

[XmlType("product")]
public class Product
{
    public Product()
    {
        id = "";
        active = "1";
        available_for_order = "1";
        indexed = "1";
        visibility = "both";
        delivery_in_stock = new List<PaLanguage>();
        delivery_out_stock = new List<PaLanguage>();
        name = new List<PaLanguage>();
    }

    [XmlElement("id")]
    public XmlCDataSection C_id { get { return new XmlDocument().CreateCDataSection(id); } set { id = value.Value; }

    [XmlElement("cache_default_attribute")]
    public XmlCDataSection C_cache_default_attribute { get { return new XmlDocument().CreateCDataSection(cache_default_attribute); } set { cache_default_attribute = value.Value; }

    [XmlElement("id_shop_default")]
    public XmlCDataSection C_id_shop_default { get { return new XmlDocument().CreateCDataSection(id_shop_default); } set { id_shop_default = value.Value; }

    [XmlElement("reference")]
    public XmlCDataSection C_reference { get { return new XmlDocument().CreateCDataSection(reference); } set { reference = value.Value; }

    [XmlElement("supplier_reference")]
    public XmlCDataSection C_supplier_reference { get { return new XmlDocument().CreateCDataSection(supplier_reference); } set { supplier_reference = value.Value; }

    [XmlElement("location")]
    public XmlCDataSection C_location { get { return new XmlDocument().CreateCDataSection(location); } set { location = value.Value; }

    [XmlElement("width")]
    public XmlCDataSection C_width { get { return new XmlDocument().CreateCDataSection(width); } set { width = value.Value; }

    [XmlElement("height")]
    public XmlCDataSection C_height { get { return new XmlDocument().CreateCDataSection(height); } set { height = value.Value; }
    // 等等..
}
英文:

Seems like the delivery_in_stock and delivery_out_stock elements in the XML can contain multiple language elements with different id attributes. Therefore, you need to modify your foreach loop to handle multiple language elements.

Instead of using Elements("language"), you can use Descendants("language") to get all language elements under delivery_in_stock and delivery_out_stock.

foreach (XElement x in gotProduct.Element(&quot;delivery_in_stock&quot;).Descendants(&quot;language&quot;))
{
product.delivery_in_stock.Add(new PaLanguage { id = (string)x.Attribute(&quot;id&quot;), language = (string)x });
}
foreach (XElement x in gotProduct.Element(&quot;delivery_out_stock&quot;).Descendants(&quot;language&quot;))
{
product.delivery_out_stock.Add(new PaLanguage { id = (string)x.Attribute(&quot;id&quot;), language = (string)x });
}

Also, in the PaLanguage class, the language property should be of type XmlCDataSection, not string, since it contains CDATA.

public class PaLanguage
{
[XmlText]
public XmlCDataSection language { get; set; }
[XmlAttribute(&quot;id&quot;)]
public string id { get; set; }
}

Lastly, the product class, you should add [XmlElement] attributes to the properties that don't have them, such as id_shop_default, reference, supplier_reference, etc.

[XmlType(&quot;product&quot;)]
public class Product
{
public Product()
{
id = &quot;&quot;;
active = &quot;1&quot;;
available_for_order = &quot;1&quot;;
indexed = &quot;1&quot;;
visibility = &quot;both&quot;;
delivery_in_stock = new List&lt;PaLanguage&gt;();
delivery_out_stock = new List&lt;PaLanguage&gt;();
name = new List&lt;PaLanguage&gt;();
}
[XmlElement(&quot;id&quot;)]
public XmlCDataSection C_id { get { return new XmlDocument().CreateCDataSection(id); } set { id = value.Value; } }
[XmlElement(&quot;cache_default_attribute&quot;)]
public XmlCDataSection C_cache_default_attribute { get { return new XmlDocument().CreateCDataSection(cache_default_attribute); } set { cache_default_attribute = value.Value; } }
[XmlElement(&quot;id_shop_default&quot;)]
public XmlCDataSection C_id_shop_default { get { return new XmlDocument().CreateCDataSection(id_shop_default); } set { id_shop_default = value.Value; } }
[XmlElement(&quot;reference&quot;)]
public XmlCDataSection C_reference { get { return new XmlDocument().CreateCDataSection(reference); } set { reference = value.Value; } }
[XmlElement(&quot;supplier_reference&quot;)]
public XmlCDataSection C_supplier_reference { get { return new XmlDocument().CreateCDataSection(supplier_reference); } set { supplier_reference = value.Value; } }
[XmlElement(&quot;location&quot;)]
public XmlCDataSection C_location { get { return new XmlDocument().CreateCDataSection(location); } set { location = value.Value; } }
[XmlElement(&quot;width&quot;)]
public XmlCDataSection C_width { get { return new XmlDocument().CreateCDataSection(width); } set { width = value.Value; } }
[XmlElement(&quot;height&quot;)]
public XmlCDataSection C_height { get { return new XmlDocument().CreateCDataSection(height); } set { height = value.Value; } }
// etc..

答案2

得分: 0

你可以将当前的PaLanguage替换为下面的PaLanguage,并尝试在所有出现问题的字段上执行相同的操作:

[XmlElement(ElementName = "language")]
public class PaLanguage
{
    [XmlText] 
    public string value { get; set; }
    [XmlAttribute("id")] 
    public string id;
}
英文:

what you can do is to replace your current PaLanguage by PaLanguage below, and try to do the same things on all the fields where you found a problem:


[XmlElement(ElementName = &quot;language&quot;)]
public class PaLanguage
{
    [XmlText] 
    public string value { get; set; }
    [XmlAttribute(&quot;id&quot;)] 
    public string id;
}

</details>



# 答案3
**得分**: 0

我先前在代码中的修改是正确的,我将`C_language`更改为`XmlNode[]`,并且具有略有不同的getter和setter

然后,我还更改了`Product`中的列表。

最后,根据Sebastian的建议,我使用`Descendants`而不是`Elements`。

感谢所有帮助过我的人。

<details>
<summary>英文:</summary>

I was on the right track with 

public class PaLanguage
{
[XmlElement("language")] public XmlCDataSection C_language { get { return new XmlDocument().CreateCDataSection(language); } set { language = value.Value; } }
[XmlIgnore] public string language { get; set; }
[XmlAttribute("id")] public string id;
}

First I changed C_language into an XmlNode[] with a slightly different getter and setter 

public class PaLanguage
{
[XmlText] public XmlNode[] C_language
{
get { var dummy = new XmlDocument(); return new XmlNode[] { dummy.CreateCDataSection(language) }; }
set { var dummy = (XmlCDataSection)value[0]; language = dummy.Data; }
}
[XmlIgnore] public string language { get; set; }
[XmlAttribute("id")] public string id;
}

Then I also changed the lists in Product

[XmlArray("delivery_in_stock")] [XmlArrayItem("language")] public List<PaLanguage> delivery_in_stock;
[XmlArray("delivery_out_stock")] [XmlArrayItem("language")] public List<PaLanguage> delivery_out_stock

Finally as Sebastian recommended, I used Descendants instead of Elements.

foreach (XElement x in gotProduct.Element("delivery_in_stock").Descendants("language"))
{
product.delivery_in_stock.Add(new PrestaLanguage { id = (string)x.Attribute("id"), language = (string)x.Element("language") });
}
foreach (XElement x in gotProduct.Element("delivery_out_stock").Descendants("language"))
{
product.delivery_out_stock.Add(new PrestaLanguage { id = (string)x.Attribute("id"), language = (string)x.Element("language") });
}

Thanks to everyone that helped.
</details>

huangapple
  • 本文由 发表于 2023年2月23日 22:04:37
  • 转载请务必保留本文链接:https://go.coder-hub.com/75545868.html
匿名

发表评论

匿名网友

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

确定