creating a "join" to update one XElement from another XElement - c#

I have an XElement, called "XUsers", that will contain XML which looks like this:
<users>
<user id="12345" name="Bob Smith" />
<user id="67890" name="Jamal Stevens" />
<user id="54321" name="Mary Jones" />
</users>
...and another XElement, called "XTasks", that will contain data like this:
<tasks>
<task id="1" title="Task 1" ownerId="54321" />
<task id="2" title="Task 2" ownerId="12345" />
<task id="3" title="Task 3" ownerId="67890" />
</tasks>
I want to add an attribute ("ownerName") to the task elements in the second XElement (XTasks), and set its values according to a "join" with the first XElement (XUsers). So, my final result will be that the XML in XTask will look like this:
<tasks>
<task id="1" title="Task 1" ownerId="54321" ownerName="Mary Jones" />
<task id="2" title="Task 2" ownerId="12345" ownerName="Bob Smith" />
<task id="3" title="Task 3" ownerId="67890" ownerName="Jamal Stevens" />
</tasks>
Is this possible using Linq? I haven't been able to find any examples of this sort of operation on the web. What is the most efficient way to accomplish this in my ASP.NET(C#) code?
Thanks for any advice you can give.

I am doing this without any IDE in front of me, so forgive me for any errors..
foreach (XElement task in XTasks.Elements())
{
XElement userNode = XUsers.Elements().Where(
e => e.Attribute("id").Value == task.Attribute("ownerId").Value).FirstOrDefault();
if (userNode != null)
{
task.Attribute("ownerName").SetValue(userNode.name);
}
}

Related

Iterating through linq results results in more items than query count

I'm fairly new to LINQ but this seemed pretty straightforward.
I have an XML doc which contains a structure like this:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<folders>
<folder id="-1" parent="-100">
<name><![CDATA[Root]]></name>
<children>
<folder id="2" parent="-1">
<name><![CDATA[Contribution]]></name>
<documents />
<children>
<folder id="775" parent="2">
<name><![CDATA[category1]]></name>
<documents />
<children>
<folder id="2319" parent="775">
<name><![CDATA[Acad_Depts1]]></name>
<documents />
<children>
<folder id="26965" parent="2319">
<name><![CDATA[Student1]]></name>
<documents>
<document>
</document>
</documents>
</folder
</children>
</folder>
<folder id="2319" parent="775">
<name><![CDATA[Acad_Depts2]]></name>
<documents />
<children>
<folder id="26965" parent="2319">
<name><![CDATA[Student1]]></name>
<documents>
<document>
</document>
</documents>
</folder
</children>
</folder>
etc...
</children>
</folder>
</children>
</folder>
</children>
</folder>
</folders>
What I'm trying to do is to select all the elements with an attribute 'parent="775"'.
XElement xelement = XElement.Load("folders_only_registrar_folder.xml");
IEnumerable <XElement> folders = xelement.Elements();
var query = from node in folders.Descendants("folder")
where node.Attribute("parent").Value == registrarNodeID
select node;
Console.WriteLine(query.Count());
Console.ReadKey();
foreach(XElement departmentNode in query.Descendants("name"))
{
Console.WriteLine(departmentNode.Value.ToString());
}
When I run the query and test the count, I get 48 results (which is good)... but when I try to write out those same nodes, I get hundreds of results. For some reason it's giving me almost ALL of the elements named "folder" including children folders.
Thoughts as to what I'm doing wrong?
UPDATE... ok so now I know why i'm getting all the folders but any thoughts on how to create a collection of each grouping of nodes and sub-nodes?
Can the selection in LINQ send each 775 folder node (plus it's collective sub-nodes) into some sort of collection of nodes and then I could parse through them in a foreach by grouping of node?
Replace query.Descendants() with just query. query.Descendants() gets every child of every node that was originally contained within query.

How to insert an XML File into Another XML File at Specific Node C#

I have two XML Files ,the first one is and Named as XMLTemplate
<DataSources>
<DataSource Name="XXXX">
</DataSource>
<DataSource Name="ABC">
</DataSource>
</DataSources>
<DataSets>
<DataSet Name="abc">
<Query>
</Query>
<ReportSections>
</ReportSections>
and the second xml file is named as XMLGenrated,
<Fields>
<Field >
</Field>
</Fields>
and I need the Output as,
<DataSource Name="XXXX">
</DataSource>
<DataSource Name="ABC">
</DataSource>
</DataSources>
<DataSets>
<DataSet Name="abc">
<Query>
<Fields>
<Field >
</Field>
</Fields>
</Query>
<ReportSections>
</ReportSections>
Both the Files are in .XML Extension and I dont know how to find the node by its Name Can anyone help me out.
I tried this,
XElement xFileRoot = XElement.Load(XMLTemplate.xml);
XElement xFileChild = XElement.Load(XMLGenerated.xml);
xFileRoot.Add(xFileChild);
xFileRoot.Save(file1.xml);
but the XML adds below the XMLTemplate I dont know how to insert at particular node.
Find the node using Linq to XML and Replace its contents
XElement xFileRoot = XElement.Load(XMLTemplate.xml);
XElement xFileChild = XElement.Load(XMLGenerated.xml);
var queryNode = xFileRoot.Element("Query");
queryNode.ReplaceWith(xFileChild) ;
Based on on this answer - How can I update/replace an element of an XElement from a string?
Be aware that you sample XML files contain multiple root nodes, and that if you need to keep the <Query> node you need to change this.

how to read all "Map" name and associate "Role"

I have a config file like below,
<Hello>
<Maps>
<Map name="X1">
<Roles>
<Role name="Y1" />
</Roles>
</Map>
<Map name="X2">
<Roles>
<Role name="Y2" />
</Roles>
</Map>
</Maps>
</Hello>
Now I want to loop through all the "Map" (X1, X2), but below line of code giving me only one map X2, how to get both,
var a = ConfigurationManager.GetSection("Hello");
This link may help:
XML reading child nodes
You need to have a for-each loop as one of the answers in the link.

XML sections to DataTable

I have an XML file that I need to load into a DataSet. The file looks like this:
<?xml version="1.0" encoding="utf-8" ?>
<computers>
<computer name="laptop">
<role roleId="1" roleName="Supervisor" />
<role roleId="2" roleName="Psuedo Pilot 1" />
<role roleId="3" roleName="Psuedo Pilot 2" />
</computer>
<computer name="triplescreen">
<role roleId="1" roleName="Tower Controllers" />
<role roleId="2" roleName="Final Controllers" />
<role roleId="3" roleName="Approach/Arrival" />
</computer>
</computers>
I can read it into a DataSet like so:
string xmlFile = string.Format(#"{0}\configuration.xml", Environment.CurrentCirectory);
DataSet xmlDataSet = new DataSet("XML DataSet");
xmlDataSet.ReadXml(xmlFile);
But when I step through the code and look at what tables are in the DataSet, I only computer and role in the Table dropdown:
I am trying to get the DataSet to have a Table for each 'computer' of a specific name.

How do I add a namespace to only ref elements in C#?

I have an XElement which contains the content that I want. However, I want to add a namespace prefix to only the ref elements. Is this possible in C#?
For example, the original XML looks like this:
<Root>
<Element1 />
<Element2 />
<Element3>
<Element3_Child1 />
<Element3_Child2 />
</Element3>
<Element4 />
<Element5>
<Element5_Child1>
<Element5_Child1_Child51 />
</Element5_Child1>
</Element5>
</Root>
I want to add a namespace prefix, so that the XML looks as below
<Root>
<Element1 />
<Element2 />
<ns:Element3>
<Element3_Child1 />
<Element3_Child2 />
</Element3>
<Element4 />
<ns:Element5>
<ns:Element5_Child1>
<Element5_Child1_Child51 />
</Element5_Child1>
</Element5>
</Root>
You can do as stated here : http://www.w3schools.com/xml/xml_namespaces.asp
<root
xmlns:foo="http://www.example.org/foo"
xmlns:bar="http://www.example.org/bar">
However, I'm pretty sure you'll need a valid URI and that you can't "fake" one. Otherwise, the namespace will be invalid. But you can test and let us know.

Categories

Resources