【问题标题】:How to remove an <ArrayOfX> container element when serializing a List<T> into an existing XML document将 List<T> 序列化为现有 XML 文档时如何删除 <ArrayOfX> 容器元素
【发布时间】:2018-08-31 04:27:06
【问题描述】:

我有这些课程:

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>

所以,我的问题是如何序列化我的 Category 类,以便得到这个(省略 &lt;ArrayOfCategory&gt; 父级):

  <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>

注意:我想删除它,而不是重命名它。

【问题讨论】:

标签: c# asp.net xml serialization linq-to-xml


【解决方案1】:

您可以使用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
        // https://stackoverflow.com/questions/19045921/net-xmlserialize-throws-writestartdocument-cannot-be-called-on-writers-created
        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;
    }
}

现在您可以将WikiEntryCategories 添加到您的xDoc,如下所示:

var categories = xDoc.Root.Element("Categories");
foreach (var category in wiki.Categories)
{
    category.SerializeToXElement(categories);
}

工作示例 .Net fiddle here.

【讨论】:

    【解决方案2】:

    将根名称作为参数传递给 XMLSerializer 调用可以解决问题。

    XmlSerializer serializer = new XmlSerializer(typeof(List), new XmlRootAttribute("RootElementName"));

    【讨论】:

    • 聪明,但不,它只是使内部元素与外部父节点同名,就像这样
    【解决方案3】:

    这里有一些 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");
    

    【讨论】:

    • 该解决方案是否满足您的需求?
    • 我已经使用过 LINQ-to-XML,但不是我想要的。不过,感谢您的建议!
    • 没问题,尽管无法想象为什么这对您不起作用。如果您要避免解决方案,下次请具体说明您的问题,这样这里的人就不会浪费时间试图帮助您解决不需要的问题。
    • 我不是在“回避”解决方案。我足够具体,@dbc 可以真正帮助我解决我的问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-09-28
    • 1970-01-01
    • 1970-01-01
    • 2020-03-03
    • 2018-10-30
    • 1970-01-01
    相关资源
    最近更新 更多