c#从另一个XML创建嵌套的XML

本文关键字:XML 嵌套 创建 另一个 | 更新日期: 2023-09-27 18:01:45

我正在尝试将XML转换为具有元素属性的嵌套XML。我在谷歌上搜索了很多,也浏览了一些问题和答案,但我还是想不起来。

我想使用c#, linq to xml对同一作者名下的子节点进行分组。

示例XML:

<authors>
  <author name="John">
    <books>
       <book type="Children">ABC</book>
    </books>
    <published> ---<new
      <print year="2011"> ---<new
         <publisher>Msoft</publisher> ---<new
      </print> ---<new
    </published> ---<new
  </author>
  <author name="May">
    <books>
       <book type="Children">A beautiful day</book>
    </books>
    <published> ---<new
      <print year="2011"> ---<new
         <publisher>hardsoft</publisher> ---<new
      </print> ---<new
    </published> ---<new
  </author>
  <author name="John">
    <books>
       <book type="Fiction">BBC</book>
    </books>
    <published> ---<new
      <print year="2013"> ---<new
         <publisher>dsney</publisher> ---<new
      </print> ---<new
    </published> ---<new
  </author>
</authors>

输出期望:

<authors>
  <author name="John">
    <books>
       <book type="Children">ABC</book>
       <book type="Fiction">BBC</book>
    </books>
    <published>
      <print year="2011">
         <publisher>Msoft</publisher>
         <publisher>hardsoft</publisher>
      </print>
    </published>
  </author>
  <author name="May">
    <books>
       <book type="Children">A beautiful day</book>
    </books>
    <published>
      <print year="2013">
         <publisher>dsney</publisher>
      </print>
    </published>
  </author>
</authors>

如果有附加的节点属性需要分组在同一作者,例如,我应该只是添加另一个组或从前一组中选择元素?

到目前为止,我已经试过了:

XDocument doc = XDocument.Load(pathtoxmlfile);
var query = from e in doc.Elements("author")
        group e by e.Attribute("name").Value into g
        select new XElement("author", new XAttribute("name", g.Key),
               new XElement("books", 
                   g.Select(x => x.Element("books").Elements("book"))
                   , new XElement("published",
                         g.Select(y=>y.Elements("publisher")
                   )
            )
        )
 );
 XElement root = new XElement("authors", query);

它只输出me和author节点,没有条目。

<author>
  <books>...this part is output as expect...
  </books>
  <published>
    <publisher />
  </published>
</author>

c#从另一个XML创建嵌套的XML

string xml = @"<authors>
  <author name=""John"">
    <books>
       <book type=""Children"">ABC</book>
    </books>
  </author>
  <author name=""May"">
    <books>
       <book type=""Children"">A beautiful day</book>
    </books>
  </author>
  <author name=""John"">
    <books>
       <book type=""Fiction"">BBC</book>
    </books>
  </author>
</authors>";
XElement root = XElement.Parse(xml);
var query = from e in root.Elements("author")
            group e by e.Attribute("name").Value into g
            select new XElement("author", new XAttribute("name", g.Key),
                   new XElement("books", 
                                 g.Select(x => x.Element("books").Elements("book")).ToArray()));
 XElement newRoot = new XElement("authors", query.ToArray());
 Console.WriteLine(newRoot);

在本例中,我们假设在名为ungrouped. XML 的文档中已经有未分组的XML。

XDocument doc = XDocument.Load(ungrouped.xml);
var groupedAuthors = doc.Root.Elements("author")
                        .GroupBy(a => a.Attribute("name").Value, 
                                 a => a.Descendants("book"))
                        .Select(g => new XElement("author", new XAttribute("name", g.Key,
                                                            new XElement("books", g.ToArray())
                                                 )
                                );

XElement root = new XElement("authors", groupedAuthors);

让我们逐步检查上面的代码来解释这里发生了什么。

首先,我们用输入示例中的无组织XML文件加载XDocument对象。然后我们开始使用Linq to XML

  1. 获取所有名为"author"的元素:doc.Root.Elements("author")
  2. 使用名为"name"的属性值对元素进行分组,并插入名为"book"的元素列表。由于这些元素在另一个名为"books"的元素下,我们希望获得作者标签的后代,而不是直接的子,这就是Elements()所使用的。lambda表达式

    • a => a.Attribute("name").Value获得我们正在分组的值,但我们意识到,如果缺少"name"标签,这可能会抛出NullReferenceException
    • a => a.Descendants("book")获取名为"book"的元素,这些元素位于作者标签下的某个位置。这允许我们跳过必须直接指定"books"标签(a.Element("books").Elements("book")是说同样事情的长方式)
  3. 创建包含分组元素的IEnumerable<XElement>g.Key是我们分组的作者的名字,g是该键下分组对象的IEnumerable

  4. 最后,我们创建一个根节点,并在它下面添加我们所有的新元素!

试试这个

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;

namespace ConsoleApplication34
{
    class Program
    {
        static void Main(string[] args)
        {
            string input =
                "<authors>" +
                  "<author name='"John'">" +
                    "<books>" +
                       "<book type='"Children'">ABC</book>" +
                    "</books>" +
                  "</author>" +
                  "<author name='"May'">" +
                    "<books>" +
                       "<book type='"Children'">A beautiful day</book>" +
                    "</books>" +
                  "</author>" +
                  "<author name='"John'">" +
                    "<books>" +
                       "<book type='"Fiction'">BBC</book>" +
                    "</books>" +
                  "</author>" +
                "</authors>";
            XElement element = XElement.Parse(input);
            var authors = element.Descendants("author").GroupBy(x => x.Attribute("name").Value).ToList();
            foreach (var author in authors)
            {
                var books = author.Descendants("books");
                for (int i = author.Count() - 1; i >= 1 ; i--)
                {
                    var book = author.Skip(i).FirstOrDefault().Descendants("book");
                    books.Elements("book").First().Add(book);
                    author.Skip(i).DescendantNodesAndSelf().Remove();
                }
            }
        }
    }
}
相关文章: