英文:
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:
<?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>
For this purpose I have a class like this:
[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;
...
With PaLanguage being:
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;
}
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("ShopApi") + "products/");
var gotProduct = getResponse
.Element("prestashop")
.Element("products")
.Elements("product")
.Where(e => e.Element("reference").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("delivery_in_stock").Elements("language"))
{
product.delivery_in_stock.Add(new PrestaLanguage { id = (string)x.Attribute("id"), language = (string)x.Element("language") });
}
Which is completely wrong because it serializes it as:
<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>
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_stock
和delivery_out_stock
元素似乎可以包含具有不同id
属性的多个language
元素。因此,您需要修改foreach
循环以处理多个language
元素。
不要使用Elements("language")
,而应该使用Descendants("language")
来获取delivery_in_stock
和delivery_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_default
,reference
,supplier_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("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 });
}
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("id")]
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("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; } }
// 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 = "language")]
public class PaLanguage
{
[XmlText]
public string value { get; set; }
[XmlAttribute("id")]
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>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论