Inserting elements into a child node, based on a condition - c#

I have the following XML
XElement xe =
new XElement("Schedule",
new XElement("Team",
new XElement("Name", "SomeName"),
new XElement("Dates"),
new XElement("Game",
new XElement("Bench"),
new XElement("Date")
)
)
);
Eventually i'll want to add to the Bench and Date field.
I've tried something like:
foreach(Name name in names)
{
doc.Element("Schedule").Element("Team").Element("Dates")
.Elements()
.FirstOrDefault(item => (string)item.Parent.Element("Name") == name.TeamName)
.Add(
new XElement("Game",
new XElement("Bench", "SomeBench"),
new XElement("Date", SomeDate.ToShortDateString())
)
);
}
I get an Object not set to an instance of an object error.
Any help would be great
EDIT: Forgot to mention that the insertions would happen with a loop
My End result would end up something like:
<Schedule>
<Team>
<Name>SomeName</Name>
<Dates>
<Bench>SomeBench</Bench>
<Date>12/10/2012</Date>
</Dates>
</Team>
<Team>
<Name>SomeName2</Name>
<Dates>
<Bench>SomeBench2</Bench>
<Date>12/13/2012</Date>
</Dates>
</Team>
<Team>
<Name>SomeName3</Name>
<Dates>
<Bench>SomeBench3</Bench>
<Date>12/16/2012</Date>
</Dates>
</Team>
</Schedule>

The original OP's code could have an exception by several reasons:
In doc.Element("Schedule").Element("Team").Element("Dates") the segment Element("Schedule") is extra, if doc == xe, i.e. Schedule is the root xml element.
.Elements() segment is extra as the Dates element in xe does not contain any child elements.
The question is very confusing to me. Nevertheless I'll try to speculate.
foreach (var dates in doc.Elements("Team")
.Where(t => names.Any(n => n.TeamName == t.Element("Name").Value))
.Select(t => t.Element("Dates")))
{
dates.Add(
new XElement("Bench", "SomeBench"),
new XElement("Date", SomeDate.ToShortDateString())
);
}

Related

add elements multiple values in XDocument C#

I want to add a section with tag name called properties, and have one item value called property with multiple value, like node name, value
org xml file is like this
<testsuites>
<testsuite>
blah blah
</testsuite>
</testsuites>
After add, i want it show like this
<testsuites>
<testsuite>
<properties>
<property name="name" "value"="desirevalue"/>
</properties>
blah blah
</testsuite>
</testsuites>
The code that i wrote has some problems, it actually create two line of property, but i want them as one line. How should i update my code? Also seems last two line has problems. i get "object reference not set to an instance of an object" error
XDocument doc = XDocument.Load(fileOfReportInXML);
XElement root= new XElement("properties");
root.Add(new XElement("property", "name= node"));
root.Add(new XElement("property","value=desirevalue"));
doc.Element("testsuite").Add(root);
doc.Save(fileOfReportInXML);
Try following code:
//Load XML file
XDocument doc = XDocument.Load(fileOfReportInXML);
Edit: Add element to the first element of your xdocument
doc.Root.Elements("testsuite").First().Add(new XElement("properties", new XElement("property", new XAttribute("name", "name"), new XAttribute("value", "desirevalue"))));
if you want to add new elements to all your testsuite elements:
foreach (var element in doc.Root.Elements("testsuite"))
{
//Skip adding element if element already exists
if (element.HasElements && element.Element("properties") != null) continue;
element.Add(new XElement("properties", new XElement("property", new XAttribute("name", "name"), new XAttribute("value", "desirevalue"))));
}
Save the XML document
//Save XML file
doc.Save(fileOfReportInXML);

use LINQ on XmlNodeList

<X version="1.0">
<Y id="abc" abv="a"/>
<Y id="edf" abv="e"/>
</X>
I want to select the node whose id is "abc", and return its abv "a".
XmlDocument doc = new XmlDocument();
doc.Load(filePath);
XmlNodeList list = doc.SelectNodes("X/Y");
var node = list.Cast<XmlNode>().Where(node => node["id"].InnerText == "abc")
.Select(x=>x["abv"].InnerText);
But it does't work, node["id"].InnerText is always "". Can you point out where is a problem?
Thanks a lot
Aside from the fact what your code snippet wouldn't be compiled because of non-unique node variable (first outside of linq query and second in "where" method lambda), you have also missed Attributes in your query.
It should be something like
var node = list.Cast<XmlNode>()
.Where(n => n.Attributes["id"].InnerText == "abc")
.Select(x => x.Attributes["abv"].InnerText);
The InnerText for a node is the text that appears between <node> and </node>. So for, eg <Y attributes /> there is no inner text.
You need to use node => node.Attributes["id"].Value == "abc"
Just cast XmlNodeList to List, like that:
List<XmlNode> list = new List<XmlNode>();
foreach(XmlNode a in xmlNodeList)
{
list.Add(a);
}
list.OrderBy((element) => element.ChildNodes[0].InnerText);

How do I parse text from complex type xml in c# using XDocument?

<?xml version="1.0" encoding="UTF-8"?>
<meta>
<field type="xs-string" name="AssetId">TF00000002</field>
<field type="xs-string" name="Title">TitleOfAsset</field>
</meta>
I have this XML loaded in to a XDocument using the function
XDocument doc = XDocument.Parse(xmlData)
However, I want to be able to retrieve the text fields "TF00000002" and "TitleOfAsset" ... How do I go about doing this?
templateMetaData.assetID = doc
.Descendants()
.Where(p => p.Name.LocalName == "AssetId")
.ToString();
returns:
System.Linq.Enumerable+WhereEnumerableIterator`1[System.Xml.Linq.XElement]
Can anyone shine a light on this?
In your query, you are calling ToString on an IEnumerable<XElement> which will never give you the expected result, instead look for field elements under your Root and get their value:
var values = doc.Root
.Elements("field")
.Select(element => (string)element);
If you want to access your values using the name attribute you can use Dictionary:
var values = doc.Root
.Elements("field")
.ToDictionary(x => (string)x.Attribute("name"), x => (string)x);
Then you can access the value of AssetId:
var id = values["AssetId"];

Linq to XML Add element to specific sub tree

My XML:
<Bank>
<Customer id="0">
<Accounts>
<Account id="0" />
<Account id="1" />
</Accounts>
</Customer>
<Customer id="1">
<Accounts>
<Account id="0" />
</Accounts>
</Customer>
<Customer id="2">
<Accounts>
<Account id="0" />
</Accounts>
</Customer>
</Bank>
I want to add new Account element to lets say Customer with id 2. I know how to add the line what I dont know how do I specify the customer (where do I write the Customer's ID ?)
My LINQ to XML code:
XDocument document = XDocument.Load("database.xml");
document.Element("Bank").Element("Customer").Element("Accounts").Add
(
new XElement
(
"Account", new XAttribute("id", "variable")
)
);
document.Save("database.xml");
Thanks for the help. XML is not my good friend :(
You are almost there, your code will be default add the element to the first Customer. You need to search for the attribute id in collection of Customers whose value is 2 -
document.Element("Bank").Elements("Customer")
.First(c => (int)c.Attribute("id") == 2).Element("Accounts").Add
(
new XElement
(
"Account", new XAttribute("id", "variable")
)
);
I know how to add the line what I dont know how do I specify the customer (where do I write the Customer's ID ?)
You need to find the Customer element with the right ID first. For example:
var customer = document.Root
.Elements("Customer")
.Single(x => (int) x.Attribute("id") == id);
customer.Element("Accounts").Add(new XElement("Account",
new XAttribute("id", "variable")));
Note that this will fail on the Single call if there isn't exactly one Customer element with the right ID. If you want to create a new customer, you'll need to do a bit more work - but presumably that would be in a different call anyway.
var cust = xDoc.Descendants("Customer")
.First(c => c.Attribute("id").Value == "2");
cust.Element("Accounts").Add(new XElement("Account", new XAttribute("id","3") ));

How to get just the root element from Xelement

I have the following XElement:
<Assembly name="3">
<Component name="2" />
</Assembly>
I would like to get just the root element. <Assembly name="3"> I cant see any method which suits for me.
XElement.????? I cant find XElement.Root;
Does any clue?
You can try this in VB.NET
Dim elm as XElment = XElement.Parse(<Assembly name="3">
<Component name="2" />
</Assembly>)
Dim strName as string
strName = elm.AncestorsAndSelf.First.Name
Code in C#
XElement elm = XElement.Parse("<Assembly name='3'><Component name='2' /></Assembly>");
string name =elm.AncestorsAndSelf().First().Name;
You can get the root element this way :
XDocument.Root
Here is an example of implementation :
XDocument doc = new XDocument(
new XComment("This is a comment."),
new XElement("Pubs",
new XElement("Book",
new XElement("Title", "Artifacts of Roman Civilization"),
new XElement("Author", "Moreno, Jordao")
),
new XElement("Book",
new XElement("Title", "Midieval Tools and Implements"),
new XElement("Author", "Gazit, Inbar")
)
),
new XComment("This is another comment.")
);
Console.WriteLine(doc.Root.Name.ToString());
link : http://msdn.microsoft.com/en-us/library/system.xml.linq.xdocument.root.aspx
You could call RemoveNodes on it... create a copy first if you need to preserve the original content for other reasons.
It's not really clear what you're trying to do with this. The element logically contains all its children - there's no concept of XElement.Root because an element "is itself". RemoveNodes will remove all the child nodes, but if you just want to get the name of the element, or its attributes, you can do that without changing the structure at all.
Copy the name & attributes to a new element;
var root = new XElement(el.Name, el.Attributes());

Categories

Resources