如何在将 List<T> 序列化到现有 XML 文档时删除 <ArrayOfX> 容器元素
How to remove an <ArrayOfX> container element when serializing a List<T> into an existing XML document
我有这些 classes:
public class WikiEntry
{
public string Id { get; set; }
public string Title { get; set; }
public string Content { get; set; }
[XmlArray]
public List<Category> Categories { get; set; }
}
public class Category
{
[XmlAttribute]
public string Id { get; set; }
[XmlAttribute]
public string Text { get; set; }
}
一开始我有这个XML结构:
<Wiki>
<Categories></Categories>
<Tags></Tags>
<WikiEntries></WikiEntries>
</Wiki>
我正在序列化 wiki.Categories
并将其添加到现有的 XML 中,如下所示:
var xDoc = XDocument.Load("Data.xml");
WikiEntry wiki = new WikiEntry
{
Id = Guid.NewGuid().ToString(),
Title = "Simple title",
Content = "Simple content here",
Categories = new List<Category>
{
new Category
{
Id = Guid.NewGuid().ToString(),
Text = "CATEGORYA"
},
new Category
{
Id = Guid.NewGuid().ToString(),
Text = "CATEGORYB"
}
}
};
var categories = xDoc.Root.Element("Categories");
var categoriesBuilder = new StringBuilder();
using (var writer = XmlWriter.Create(categoriesBuilder, new XmlWriterSettings { Indent = true, ConformanceLevel = ConformanceLevel.Auto, OmitXmlDeclaration = true }))
{
var ns = new XmlSerializerNamespaces();
ns.Add("", "");
var xs = new XmlSerializer(typeof(List<Category>), "");
xs.Serialize(writer, wiki.Categories, ns);
}
categories.Add(XElement.Parse(categoriesBuilder.ToString().Trim()));
xDoc.Save(file);
问题是,当我这样做时,我得到了这个:
<Categories>
<ArrayOfCategory>
<Category Id="482ce9f6-5d4c-48f9-b84f-33c3cf9b0b0f" Text="CATEGORYA" />
<Category Id="73e6c671-fb6d-40a4-8694-1d5dbcf381d5" Text="CATEGORYB" />
</ArrayOfCategory>
<ArrayOfCategory>
<Category Id="3c0f2a15-4623-4f33-b356-75e8c8b89624" Text="CATEGORYA" />
<Category Id="d8720ca9-06f5-401d-90e2-c7f43e1c91f5" Text="CATEGORYB" />
</ArrayOfCategory>
所以,我的问题是如何序列化我的类别 class ,以便我得到这个(省略 <ArrayOfCategory>
父级):
<Categories>
<Category Id="482ce9f6-5d4c-48f9-b84f-33c3cf9b0b0f" Text="CATEGORYA" />
<Category Id="73e6c671-fb6d-40a4-8694-1d5dbcf381d5" Text="CATEGORYB" />
<Category Id="3c0f2a15-4623-4f33-b356-75e8c8b89624" Text="CATEGORYA" />
<Category Id="d8720ca9-06f5-401d-90e2-c7f43e1c91f5" Text="CATEGORYB" />
</Categories>
注意:我想删除它,而不是重命名它。
将根名称作为参数传递给 XMLSerializer
调用可以达到目的。
XmlSerializer serializer = new XmlSerializer(typeof(List), new XmlRootAttribute("RootElementName"));
这里有一些 Linq-to-Xml 来实现你正在寻找的东西:
categories.Add(XElement.Parse(categoriesBuilder.ToString().Trim()));
XDocument output =
new XDocument(
new XElement(xDoc.Root.Name,
new XElement("Categories",
from comp in xDoc.Root.Elements("Categories").Elements("ArrayOfCategory").Elements("Category")
select new XElement("Category",
new XAttribute("Id", comp.Attribute("Id").Value),
new XAttribute("Text", comp.Attribute("Text").Value)
))));
output.Save("c:\so\test.xml");
您可以使用 XContainer.CreateWriter()
直接序列化为 XDocument
。这反过来将允许您直接序列化到 categories
元素的子 XElement
中,而无需任何中间字符串表示。
首先,定义如下扩展方法:
public static class XObjectExtensions
{
public static XElement SerializeToXElement<T>(this T obj, XContainer parent = null, XmlSerializer serializer = null, XmlSerializerNamespaces ns = null)
{
if (obj == null)
throw new ArgumentNullException();
// Initially, write to a fresh XDocument to cleanly avoid the exception described in
//
var doc = new XDocument();
using (var writer = doc.CreateWriter())
{
(serializer ?? new XmlSerializer(obj.GetType())).Serialize(writer, obj, ns ?? NoStandardXmlNamespaces());
}
// Now move to the incoming parent.
var element = doc.Root;
if (element != null)
{
element.Remove();
if (parent != null)
{
parent.Add(element);
}
}
return element;
}
public static XmlSerializerNamespaces NoStandardXmlNamespaces()
{
var ns = new XmlSerializerNamespaces();
ns.Add("", ""); // Disable the xmlns:xsi and xmlns:xsd lines.
return ns;
}
}
现在您可以将 WikiEntry
的 Categories
添加到 xDoc
,如下所示:
var categories = xDoc.Root.Element("Categories");
foreach (var category in wiki.Categories)
{
category.SerializeToXElement(categories);
}
工作示例 .Net fiddle here.
我有这些 classes:
public class WikiEntry
{
public string Id { get; set; }
public string Title { get; set; }
public string Content { get; set; }
[XmlArray]
public List<Category> Categories { get; set; }
}
public class Category
{
[XmlAttribute]
public string Id { get; set; }
[XmlAttribute]
public string Text { get; set; }
}
一开始我有这个XML结构:
<Wiki>
<Categories></Categories>
<Tags></Tags>
<WikiEntries></WikiEntries>
</Wiki>
我正在序列化 wiki.Categories
并将其添加到现有的 XML 中,如下所示:
var xDoc = XDocument.Load("Data.xml");
WikiEntry wiki = new WikiEntry
{
Id = Guid.NewGuid().ToString(),
Title = "Simple title",
Content = "Simple content here",
Categories = new List<Category>
{
new Category
{
Id = Guid.NewGuid().ToString(),
Text = "CATEGORYA"
},
new Category
{
Id = Guid.NewGuid().ToString(),
Text = "CATEGORYB"
}
}
};
var categories = xDoc.Root.Element("Categories");
var categoriesBuilder = new StringBuilder();
using (var writer = XmlWriter.Create(categoriesBuilder, new XmlWriterSettings { Indent = true, ConformanceLevel = ConformanceLevel.Auto, OmitXmlDeclaration = true }))
{
var ns = new XmlSerializerNamespaces();
ns.Add("", "");
var xs = new XmlSerializer(typeof(List<Category>), "");
xs.Serialize(writer, wiki.Categories, ns);
}
categories.Add(XElement.Parse(categoriesBuilder.ToString().Trim()));
xDoc.Save(file);
问题是,当我这样做时,我得到了这个:
<Categories>
<ArrayOfCategory>
<Category Id="482ce9f6-5d4c-48f9-b84f-33c3cf9b0b0f" Text="CATEGORYA" />
<Category Id="73e6c671-fb6d-40a4-8694-1d5dbcf381d5" Text="CATEGORYB" />
</ArrayOfCategory>
<ArrayOfCategory>
<Category Id="3c0f2a15-4623-4f33-b356-75e8c8b89624" Text="CATEGORYA" />
<Category Id="d8720ca9-06f5-401d-90e2-c7f43e1c91f5" Text="CATEGORYB" />
</ArrayOfCategory>
所以,我的问题是如何序列化我的类别 class ,以便我得到这个(省略 <ArrayOfCategory>
父级):
<Categories>
<Category Id="482ce9f6-5d4c-48f9-b84f-33c3cf9b0b0f" Text="CATEGORYA" />
<Category Id="73e6c671-fb6d-40a4-8694-1d5dbcf381d5" Text="CATEGORYB" />
<Category Id="3c0f2a15-4623-4f33-b356-75e8c8b89624" Text="CATEGORYA" />
<Category Id="d8720ca9-06f5-401d-90e2-c7f43e1c91f5" Text="CATEGORYB" />
</Categories>
注意:我想删除它,而不是重命名它。
将根名称作为参数传递给 XMLSerializer
调用可以达到目的。
XmlSerializer serializer = new XmlSerializer(typeof(List), new XmlRootAttribute("RootElementName"));
这里有一些 Linq-to-Xml 来实现你正在寻找的东西:
categories.Add(XElement.Parse(categoriesBuilder.ToString().Trim()));
XDocument output =
new XDocument(
new XElement(xDoc.Root.Name,
new XElement("Categories",
from comp in xDoc.Root.Elements("Categories").Elements("ArrayOfCategory").Elements("Category")
select new XElement("Category",
new XAttribute("Id", comp.Attribute("Id").Value),
new XAttribute("Text", comp.Attribute("Text").Value)
))));
output.Save("c:\so\test.xml");
您可以使用 XContainer.CreateWriter()
直接序列化为 XDocument
。这反过来将允许您直接序列化到 categories
元素的子 XElement
中,而无需任何中间字符串表示。
首先,定义如下扩展方法:
public static class XObjectExtensions
{
public static XElement SerializeToXElement<T>(this T obj, XContainer parent = null, XmlSerializer serializer = null, XmlSerializerNamespaces ns = null)
{
if (obj == null)
throw new ArgumentNullException();
// Initially, write to a fresh XDocument to cleanly avoid the exception described in
//
var doc = new XDocument();
using (var writer = doc.CreateWriter())
{
(serializer ?? new XmlSerializer(obj.GetType())).Serialize(writer, obj, ns ?? NoStandardXmlNamespaces());
}
// Now move to the incoming parent.
var element = doc.Root;
if (element != null)
{
element.Remove();
if (parent != null)
{
parent.Add(element);
}
}
return element;
}
public static XmlSerializerNamespaces NoStandardXmlNamespaces()
{
var ns = new XmlSerializerNamespaces();
ns.Add("", ""); // Disable the xmlns:xsi and xmlns:xsd lines.
return ns;
}
}
现在您可以将 WikiEntry
的 Categories
添加到 xDoc
,如下所示:
var categories = xDoc.Root.Element("Categories");
foreach (var category in wiki.Categories)
{
category.SerializeToXElement(categories);
}
工作示例 .Net fiddle here.