【问题标题】:C# create nested XML from another XMLC# 从另一个 XML 创建嵌套 XML
【发布时间】:2015-07-10 16:25: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);

它只在内部和作者节点输出我,没有条目。

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

【问题讨论】:

  • 看起来您实际上并没有尝试转换某些内容。我在您的问题中只看到输入数据和预期结果 - 并且看不到您的任何尝试。到目前为止有什么努力吗?你遇到过什么问题?
  • 您是否考虑过使用 Xsl 转换来解决这个问题?如果你的输出也是 Xml 并且你不需要对数据进行复杂的处理,这应该比使用 Linq 更容易。
  • 你可以看看stackoverflow.com/questions/5603284/linq-to-xml-groupby。看起来与您尝试做的非常相似。
  • @Andy Korneyev - 抱歉,我很着急,没有发布我已经尝试过的代码。以前我将“ var query = from author in root.Root.Elements("author") group author by author.Attribute("name") 编码为 groupedAuthor select groupedAuthor; 在 VS 中尝试了此代码,但只给了我一个错误。跨度>

标签: c# xml linq-to-xml


【解决方案1】:
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);

【讨论】:

  • .ToArray() 都可以删除
【解决方案2】:

假设您已经在一个名为 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. 获取所有名为“作者”的元素:doc.Root.Elements("author")
  2. 使用名为“name”的属性值对元素进行分组,并插入名为“book”的元素列表。由于这些元素位于另一个名为“books”的元素下,我们希望获取作者标签的后代而不是直接子代,这就是使用 Elements() 的内容。 lambda 表达式

    • a =&gt; a.Attribute("name").Value 获取我们正在分组的值,但我们知道如果缺少“名称”标签,这可能会引发 NullReferenceException
    • a =&gt; a.Descendants("book") 获取位于作者标签下somewhere 的名为“book”的元素。这让我们不必直接指定“书籍”标签(a.Element("books").Elements("book") 是同一件事的漫长方式)
  3. 创建一个包含分组元素的IEnumerable&lt;XElement&gt;g.Key 是我们分组的作者的名字,g 是该键下分组对象的IEnumerable

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

【讨论】:

    【解决方案3】:

    试试这个

    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();
                    }
                }
            }
    
        }
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-03
      • 2015-07-31
      • 2023-01-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多