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>
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
- 获取所有名为"author"的元素:
doc.Root.Elements("author")
使用名为"name"的属性值对元素进行分组,并插入名为"book"的元素列表。由于这些元素在另一个名为"books"的元素下,我们希望获得作者标签的后代,而不是直接的子,这就是
Elements()
所使用的。lambda表达式-
a => a.Attribute("name").Value
获得我们正在分组的值,但我们意识到,如果缺少"name"标签,这可能会抛出NullReferenceException
-
a => a.Descendants("book")
获取名为"book"的元素,这些元素位于作者标签下的某个位置。这允许我们跳过必须直接指定"books"标签(a.Element("books").Elements("book")
是说同样事情的长方式)
-
创建包含分组元素的
IEnumerable<XElement>
。g.Key
是我们分组的作者的名字,g
是该键下分组对象的IEnumerable
。- 最后,我们创建一个根节点,并在它下面添加我们所有的新元素!
试试这个
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();
}
}
}
}
}