简体   繁体   English

需要使用linq C#将xml元素添加到最后一个父级

[英]Need to add xml element to last parent using linq c#

I'm really new to Linq and C# and I'm stuck on what is probably an obvious problem. 我真的是Linq和C#的新手,我被困在一个明显的问题上。

I have an existing XML file 我有一个现有的XML文件

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<books>
  <book>
    <title>This is Title 1</title>
    <author>John Doe</author>
    <categories>
      <category>How to</category>
      <category>Technical</category>       
  </book>
  <book>
    <title>This is Title 2</title>
    <author>Jane Brown</author>
    <categories>
      <category>Fantasy</category>
    </categories>
  </book>
</books>

I want to add a 2nd category to the second book in this file. 我想在该文件的第二本书中添加第二个类别。

I've gotten this far: 我已经走了这么远:

var thiscat = doc.Root
  .Element("book")
  .Element("categories");

thiscat.Add(new XElement("category", "novel"));

But this adds a 3rd category to the first book. 但这在第一本书中增加了第三个类别。 I need to learn how to point 'thiscat' at the last categories element rather than the first one. 我需要学习如何将“ thiscat”指向最后一个类别元素而不是第一个。 I've been sniffing around LastNode but haven't managed to get the syntax right. 我一直在寻找LastNode,但没有设法正确使用语法。

This is my first question here. 这是我的第一个问题。 Please let me know if I'm not being clear or if I'm doing anything wrong. 如果我不清楚或做错任何事情,请告诉我。

Pete, 皮特,

Here is an example that will search for the book by title This is Title 2 and add another category. 这是一个按标题搜索这本书的示例, This is Title 2并添加了另一个类别。

var elem = doc.Root.Elements("book").FirstOrDefault(x => x.Element("title").Value.Equals("This is Title 2"));
if (elem != null)
{
    var category = elem.Element("categories");
    category.Add(new XElement("category", "novel"));
}

Edit: More explanatoin. 编辑:更多说明。

First of we search the documents book elements for the matching title of This is Title 2 (effectively your second entry). 首先,我们在文档book元素中搜索匹配的titleThis is Title 2 (实际上是您的第二个条目)。 By executing the FirstOrDefault extension method we either the get the first matching element (as XElement ) or null . 通过执行FirstOrDefault扩展方法,我们可以获取第一个匹配元素(作为XElement )或null

Because we 'could' get a null value we must check if the value is null if not we move into the next step of locating the categories element. 因为我们“可以”得到一个null值,所以我们必须检查该值是否为null ,否则我们将进入下一步查找categories元素的步骤。 This can be done simply calling the elem.Element() method as we only expect one element. 只需调用elem.Element()方法即可完成此操作,因为我们只期望一个元素。

Finally we add a new XElement to the category element. 最后,我们将新的XElement添加到category元素。

Hope this helps. 希望这可以帮助。

Cheers. 干杯。

To answer your question quite literally, you could modify the statement as follows: 要从字面上回答您的问题,您可以按以下方式修改语句:

var thiscat = doc.Root
.Elements("book")
.Skip(1)
.First()
.Element("categories");

The "Element" function returns the first element of that type found. “元素”功能返回找到的该类型的第一个元素。 In this case, we used "Elements" instead to return an IEnumerable containing all of the elements named "book", and then we used the LINQ "skip" function to skip the first (returning another IEnumerable of all the remaining elements), and then we took just the first element in the IEnumerable (back to a single XElement). 在这种情况下,我们使用“元素”代替返回包含所有名为“ book”的元素的IEnumerable,然后使用LINQ“跳过”功能跳过第一个(返回所有其余元素的另一个IEnumerable),并且然后我们只获取IEnumerable中的第一个元素(回到单个XElement)。

Another way you could have gotten to the answer is as follows: 您可能获得答案的另一种方法如下:

var thiscat = doc.Root
.Element("book")
.ElementsAfterSelf()
.First()
.Element("categories");

ElementsAfterSelf returns an IEnumerable of all the sibling elements after the calling object. ElementsAfterSelf返回调用对象之后所有同级元素的IEnumerable。

LINQ is a really critical part of programming in C# and it's good to see you're trying to learn it from the beginning. LINQ是C#编程中至关重要的部分,很高兴看到您正在尝试从一开始就学习它。 Although your methodology here in adding a specific element to a specific place programmatically is questionable (obviously it is a contrived example), in playing around like this you will probably learn a bit about LINQ and that is always good. 尽管您在此处以编程方式将特定元素添加到特定位置的方法存在疑问(显然这是一个人为的示例),但是在这种玩法中,您可能会学到一些有关LINQ的知识,而且这总是很好的。

First you should get your second book element.According to your code: 首先,您应该获得第二本书的元素。根据您的代码:

var thiscat = doc.Root
                 .Element("book")
                 .Element("categories");

This statement returns just one categories element which belongs to your first book.Because you are using Element instead of Elements . 该语句仅返回属于您的第一本书的一个category Elements 。因为您使用的是Element而不是Elements Let's go step by step. 让我们一步一步走。

A proper way to get second element is using Descendants like this: 获取第二个元素的正确方法是使用Descendants这样的:

var secondBook = doc.Descendants("book")[1];

Descendants returning a collection of your books.And we are getting second element with indexer.Now we need to select your categories element under the book element. 后代返回了您的书集。现在我们有了indexer的第二个元素。现在我们需要在book元素下选择Categories元素。

var categories = secondBook.Element("categories");

Now we have our categories element and we can add our new category and save Xml Document : 现在我们有了Categories元素,我们可以添加新的category并保存Xml Document

categories.Add(new XElement("category", "novel"));
doc.Save(path);

And that's all.If you understand that logic you can modify your html file however you like.Besides you can make all of these in one line: 仅此而已。如果您了解这种逻辑,则可以按自己的喜好修改html文件。此外,您还可以将所有这些文件制作成一行:

doc.Descendants("book")[1]
            .Element("categories")
            .Add(new XElement("category", "novel"));

This should work( slightly lengthy solution as it helps understand the fundamentals better): 这应该有效(稍微冗长的解决方案,因为它有助于更​​好地理解基本原理):

            XmlElement rootNode = xd.DocumentElement;  //gives <books> the root node
            XmlNodeList cnodes= rootNode.ChildNodes; //gets the childnodes of <books>
            XmlNode secondBook= cnodes.Item(1); //second child of <books> i.e., the <book> you want
            XmlNodeList bnodes= secondBook.ChildNodes; //gets the childnodes of that <book>
            XmlNode categories= bnodes.Item(2); //gets the third child i.e.,<categories>
//making the new <category> node
            string xmlContent = "<category>novel</category>";
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(xmlContent);
            XmlNode newNode = doc.DocumentElement;
//making the new node completes

            categories.AppendChild(newNode);  //append the new node to <categories> as a child

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM