我有一个使用自定义部分进行配置的C#应用。我将XML的那一部分定义为字符串。字符串如下所示:
var xml = @"<departments>
<department id=""1"" name=""Sporting Goods"">
<products>
<product name=""Basketball"" price=""9.99"">
<add key=""Color"" value=""Orange"" />
<add key=""Brand"" value=""[BrandName]"" />
</product>
</products>
</department>
</departments>";
此XML与我所描述的类here定义的架构匹配。当我将上面的字符串传递给Departments.Deserialize
方法时,我收到一个错误。该错误显示:“无法识别的元素“添加””。调试器跳到我的Departments
类中的这一行。
public void ReadXml(XmlReader reader)
{
this.DeserializeElement(reader, false);
}
我认为错误是指“产品”元素中的“添加”元素。但是,Product
ConfigurationElement
具有一个名为KeyValueConfigurationCollection Items
的属性。因此,add
似乎可以工作。
为什么会出现此错误,如何解决我的代码,以便可以反序列化上面显示的XML字符串?
答案 0 :(得分:0)
除特殊的反序列化方法外,大多数代码都有效。
我能够纠正原始解决方案(here是我发现灵感的地方)。
我已更正且有效的部分(不要忘了原始post的IXmlSerializable):
private static string sectionName = "departments";
public static Departments Deserialize(string xml)
{
XmlSerializer serializer = new XmlSerializer(typeof(Departments), new XmlRootAttribute(sectionName));
Departments departments = null;
var xdoc = XDocument.Parse(xml);
departments = (Departments)serializer.Deserialize(xdoc.CreateReader());
//var serializer = new XmlSerializer(typeof(Departments));
//using (var reader = new StringReader(xml))
//{
// departments = (Departments)(serializer.Deserialize(reader));
//}
return departments;
}
希望它将帮助您继续前进。至少可以在我的机器上使用。让我知道是否需要完整的代码清单。
class Program
{
static void Main(string[] args)
{
string str = @"<departments>
<department id = ""1"" name = ""Sporting Goods"">
<products>
<product name=""Basketball"" price=""9.99"">
<add key = ""Color"" value = ""Orange""/>
<add key = ""Brand"" value = ""[BrandName]""/>
</product>
</products>
</department>
</departments>";
XmlDocument xmlDoc = LoadXmlsFromString(str);
string productXpath = "descendant-or-self::product";
var nodes = ExtractNodes(xmlDoc, productXpath);
foreach (XmlNode childrenNode in nodes)
{
var node = childrenNode.SelectSingleNode("descendant-or-self::*")?.OuterXml;
var obj = Product.Deserialize(node);
}
}
private static XmlNodeList ExtractNodes(XmlDocument xmlDoc, string xpath)
{
var nodes = xmlDoc.SelectNodes(xpath);
return nodes;
}
private static XmlDocument LoadXmlsFromString(string str)
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(str);
return xmlDoc;
}
}
[Serializable, XmlRoot("add")]
public class KeyValue
{
[XmlAttribute(AttributeName = "key")]
public string Key { get; set; }
[XmlAttribute(AttributeName = "value")]
public string Value { get; set; }
public static KeyValue Deserialize(string xml)
{
KeyValue keyValue = null;
var serializer = new XmlSerializer(typeof(KeyValue));
using (var reader = new StringReader(xml))
{
keyValue = (KeyValue)(serializer.Deserialize(reader));
}
return keyValue;
}
}
[Serializable, XmlRoot("product")]
public class Product
{
[XmlAttribute(AttributeName = "name")]
public string Name { get; set; }
[XmlAttribute(AttributeName = "price")]
public decimal Price { get; set; }
[XmlElement("add")]
public List<KeyValue> KeyValueList { get; set; }
public static Product Deserialize(string xml)
{
Product product = null;
var serializer = new XmlSerializer(typeof(Product));
using (var reader = new StringReader(xml))
{
product = (Product)(serializer.Deserialize(reader));
}
return product;
}
}
答案 1 :(得分:0)
我认为您必须阅读的配置不需要XmlSerializer
。 System.Configuration
为您提供的所有工具已绰绰有余。在这里,我重写了您的配置类(基本结构):
public class DepartmentsConfiguration : ConfigurationSection
{
[ConfigurationProperty("departments", IsRequired = false, IsDefaultCollection = true)]
public DepartmentItemCollection Departments
{
get
{
var departments = this["departments"] as DepartmentItemCollection;
return departments;
}
set
{
this["departments"] = value;
}
}
}
[ConfigurationCollection(typeof(DepartmentItemCollection), AddItemName = "department")]
public class DepartmentItemCollection : ConfigurationElementCollection
{
protected override ConfigurationElement CreateNewElement()
{
return new Department();
}
protected override object GetElementKey(ConfigurationElement element)
{
return ((Department)element).Name;
}
}
public class Department : ConfigurationElement
{
[ConfigurationProperty("id", IsRequired = false, IsKey = true)]
public int Id
{
get
{
return (int)(this["id"]);
}
set
{
this["id"] = value;
}
}
[ConfigurationProperty("name", IsRequired = true, IsKey = true, DefaultValue = "")]
public string Name
{
get
{
return (string)(this["name"]);
}
set
{
this["name"] = value;
}
}
[ConfigurationProperty("products", IsRequired = false, IsKey = false, IsDefaultCollection = false)]
public ProductCollection Products
{
get
{
return (ProductCollection)this["products"];
}
set
{
this["products"] = value;
}
}
}
[ConfigurationCollection(typeof(ProductCollection), AddItemName = "product")]
public class ProductCollection : ConfigurationElementCollection
{
protected override ConfigurationElement CreateNewElement()
{
return new Product();
}
protected override object GetElementKey(ConfigurationElement element)
{
return ((Product)element).Name;
}
}
public class Product : ConfigurationElement
{
[ConfigurationProperty("name", IsRequired = true, IsKey = true, DefaultValue = "")]
public string Name
{
get
{
return (string)(this["name"]);
}
set
{
this["name"] = value;
}
}
[ConfigurationProperty("price", IsRequired = false)]
public decimal Price
{
get
{
return (decimal)(this["price"]);
}
set
{
this["price"] = value;
}
}
[ConfigurationProperty("", IsRequired = false, IsKey = false, IsDefaultCollection = true)]
[ConfigurationCollection(typeof(KeyValueConfigurationCollection), AddItemName = "add")]
public KeyValueConfigurationCollection Items
{
get
{
var items = base[""] as KeyValueConfigurationCollection;
return items;
}
set
{
base[""] = value;
}
}
}
App.config 中的<configSections>
:
<configSections>
<section
name="departmentConfiguration"
type="Test.DepartmentsConfiguration, Test"
allowLocation="true"
allowDefinition="Everywhere"
/>
</configSections>
<departmentConfiguration>
<departments>
<department id="1" name="Sporting Goods">
<products>
<product name="Basketball" price="9.99">
<add key="Color" value="Orange" />
<add key="Brand" value="[BrandName]" />
</product>
</products>
</department>
</departments>
</departmentConfiguration>
以及如何使用ConfigurationManager
进行阅读:
DepartmentsConfiguration config = (DepartmentsConfiguration) ConfigurationManager
.GetSection("departmentConfiguration");
foreach (Department department in config.Departments)
{
Console.WriteLine($"{department.Id}, {department.Name}");
foreach (Product product in department.Products)
{
Console.WriteLine($"{product.Name}, {product.Price}");
foreach (string key in product.Items.AllKeys)
{
Console.WriteLine($"{key} -> {product.Items[key].Value}");
}
}
}
我知道这与您的问题不一致,请作为个人建议。
答案 2 :(得分:0)
如何使用System.Xml.Linq
的 XDocument
?
个人优点:
个人缺点:
static void Main(string[] args)
{
var xml =
@"<departments>
<department id=""1"" name=""Sporting Goods"">
<products>
<product name=""Basketball"" price=""9.99"">
<add key=""Color"" value=""Orange"" />
<add key=""Brand"" value=""[BrandName]"" />
</product>
</products>
</department>
</departments>";
var xDoc = XDocument.Load(new StringReader(xml));
var adds = xDoc.Root.Elements("department")
.Elements("products")
.Elements("product")
.Elements("add")
.Select(s => new KeyValuePair<string, string>(s.Attribute("key").ToString(), s.Attribute("value").ToString()))
.ToList();
foreach (var department in xDoc.Root.Elements("department"))
{
Console.WriteLine("department: {0}", department.Attribute("name"));
foreach (var products in department.Elements("products"))
{
foreach (var product in products.Elements("product"))
{
Console.WriteLine("product: {0}", product.Attribute("name"));
foreach (var config in product.Elements("add"))
{
Console.WriteLine("add: {0} -> {1}", config.Attribute("key"), config.Attribute("value"));
}
}
}
}