I've been searching all the weekend, but haven't found any results, I'm looking for a program or C# code, that i select a file, and i can select a node, and the child node i want the mother node to be ordered by,
<SelectedProfile>
<Name>Default</Name>
<InstalledAssemblies>
<LeagueSharpAssembly>
<InstallChecked>true</InstallChecked>
<InjectChecked>true</InjectChecked>
<Status>Ready</Status>
<DisplayName>Library - Common</DisplayName>
</LeagueSharpAssembly>
</InstalledAssemblies>
</SelectedProfile>
I want to select "LeagueSharpAssembly", and order all the "LeagueSharpAssembly" this by "DisplayName"
Any of u know something?
Using Linq to XML
var result = x.Descendants("LeagueSharpAssembly")
.OrderBy(r => r.Descendants("DisplayName").Single().Value);
This answer works, but I first misread the question, so the query should be:
var result=x.Descendants("LeagueSharpAssembly")
.OrderBy(r=>r.Element("DisplayName").Value);
This was posted first by #RichardSchneider, so if you are going to use Linq to XML his answer should be accepted.
You can use Linq and XML to select and order the elements, then a simple foearch to process them.
var doc = XDocument.Load("...");
var assemblies = doc.Descendants("LeagueSharpAssembly")
.OrderBy(r => r.Element("DisplayName").Value);
foreach (var a in assemblies)
{
Console.WriteLine("Assembly {0}", a.DisplayName);
}
Related
I have an XML document containing processing instructions. I know that, with the XmlDocument class, you can use
var node = xmlDoc.SelectSingleNode("processing-instruction('xml-stylesheet')") as XmlProcessingInstruction;
but I want to use XDocument. How can I do this?
This is how I access an XML file's nodes with the XDocument class.
However, you'll have to be more specific on what you want to do with it.
XDocument doc = XDocument.Load("filepath");
var node = doc.Nodes().OfType<XElement>().SingleOrDefault(n => n.Name == "node name");
var node_value = node.Value;
var node_descendants = node.Descendants();
UPDATE:
As you may have noticed there's no SelectSingleNode in XDocument, in fact, to retrieve the node you want you'll have to fetch it from the corresponding ienumerable collection, or alternatively from the predefined FirstNode, NextNode, PreviousNode, LastNode, but you cannot apply any filters to those. Therefore the only ways to retrieve ProcessingInstruction nodes are
var pI_nodes = doc.Nodes().OfType<XProcessingInstruction>();
And
var pI_nodes = (from node in doc.Nodes()
where node.NodeType == System.Xml.XmlNodeType.ProcessingInstruction
select node);
If you expect to retrieve several ProcessingInstructions and need to filter these as well, the equivalent to the node name would the Target property
var filtered_pIs = pI_nodes_1.Where(pI => pI.Target == "xml-stylesheet");
And as a final reminder the value of the processing instruction is stored in the Data property.
string pI_value = filtered_pIs.First().Data
Here is one way:
var node = xDoc.Root.Nodes().OfType<XProcessingInstruction>().First();
Using the example below, I would like to use xPath to find the first occurence of two different elements. For example, I want to figure out if b or d appears first. We can obviously tell that b appears before d (looking top-down, and not at the tree level). But, how can I solve this using xpath?
<a>
<b>
</b>
</a>
<c>
</c>
<d>
</d>
Right now, I find the node (b and d in this case) by getting the first element in the nodeset, which I find using the following code:
String xPathExpression = "//*[local-name()='b']";
XPathNodeIterator nodeSet = (XPathNodeIterator)navigator.Evaluate(xPathExpression);
and
String xPathExpression = "//*[local-name()='d']";
XPathNodeIterator nodeSet = (XPathNodeIterator)navigator.Evaluate(xPathExpression);
Now using xpath, I just can't figure out which comes first, b or d.
You want to scan the tree in document order (the order the elements occur). As though by chance this is the default search order, and all you've got to do is select the first element which is a <b/> or <d/> node:
//*[local-name() = 'b' or local-name() = 'd'][1]
If you want the name, add another local-name(...) call:
local-name(//*[local-name() = 'b' or local-name() = 'd'][1])
If you wanted to use LINQ to XML to solve the same solution you can try the following:
XDocument xmlDoc = new XDocument(filepath);
XElement first = (from x in xmlDoc.Descendants()
where x.Name == "b" || x.Name == "d"
select x).FirstOrDefault();
Now you can run a simple if statement to determine if "b" or "d" was the first element found that matches our criteria.
if(first.Name.Equals("b")
//code for b being first
else if(first.Name.Equals("d")
//code for d being first
Per a commentator's suggestion your code would is cleaner to use a lambda expression instead of a full LINQ query, but this can sometimes be confusing if you are new to LINQ. The following is the exact same query for my XElement assignment above:
XElement first = xmlDoc.Descendants().FirstOrDefault(x => x.Name == "b" || x.Name == "d");
I hope that's what you're looking for if you were open to not using xpath.
This XPath expressions would work:
//*[local-name()='b' or local-name()='d'][1]
Or for a shorter solution, you could try this:
(//b|//d)[1]
Both expressions will select either b elements or d elements, in the order in which they appear, and only select the first element from the result set.
I'm new to both XML and C#; I'm trying to find a way to efficiently parse a given xml file to retrieve relevant numerical values, base on the "proj_title" value=heat_run or any other possible values. For example, calculating the duration of a particular test run (proj_end val-proj_start val).
ex.xml:
<proj ID="2">
<proj_title>heat_run</proj_title>
<proj_start>100</proj_start>
<proj_end>200</proj_end>
</proj>
...
We can't search by proj ID since this value is not fixed from test run to test run. The above file is huge: ~8mb, and there's ~2000 tags w/ the name proj_title. is there an efficient way to first find all tag names w/ proj_title="heat_run", then to retrieve the proj start and end value for this particular proj_title using C#??
Here's my current C# code:
public class parser
{
public static void Main()
{
XmlDocument xmlDoc= new XmlDocument();
xmlDoc.Load("ex.xml");
//~2000 tags w/ proj_title
//any more efficient way to just look for proj_title="heat_run" specifically?
XmlNodeList heat_run_nodes=xmlDoc.GetElementsByTagName("proj_title");
}
}
8MB really isn't very large at all by modern standards. Personally I'd use LINQ to XML:
XDocument doc = XDocument.Load("ex.xml");
var projects = doc.Descendants("proj_title")
.Where(x => (string) x == "heat_run")
.Select(x => x.Parent) // Just for simplicity
.Select(x => new {
Start = (int) x.Element("proj_start"),
End = (int) x.Element("proj_end")
});
foreach (var project in projects)
{
Console.WriteLine("Start: {0}; End: {1}", project.Start, project.End);
}
(Obviously adjust this to your own requirements - it's not really clear what you need to do based on the question.)
Alternative query:
var projects = doc.Descendants("proj")
.Where(x => (string) x.Element("proj_title") == "heat_run")
.Select(x => new {
Start = (int) x.Element("proj_start"),
End = (int) x.Element("proj_end")
});
You can use XPath to find all nodes that match, for example:
XmlNodeList matches = xmlDoc.SelectNodes("proj[proj_title='heat_run']")
matches will contain all proj nodes that match the critera. Learn more about XPath: http://www.w3schools.com/xsl/xpath_syntax.asp
MSDN Documentation on SelectNodes
Use XDocument and use the LINQ api.
http://msdn.microsoft.com/en-us/library/bb387098.aspx
If the performance is not what you expect after trying it, you have to look for a sax parser.
A Sax parser will not load the whole document in memory and try to apply an xpath expression on everything in memory. It works more in an event driven approach and in some cases this can be a lot faster and does not use as much memory.
There are probably sax parsers for .NET around there, haven't used them myself for .NET but I did for C++.
I have problem i'm trying to update a specific part of the XML with the linq query but it doesn't work. So i an xml file:
<?xml version="1.0" encoding="utf-8"?>
<DesignConfiguration>
<Design name="CSF_Packages">
<SourceFolder>C:\CSF_Packages</SourceFolder>
<DestinationFolder>C:\Documents and Settings\xxx</DestinationFolder>
<CopyLookups>True</CopyLookups>
<CopyImages>False</CopyImages>
<ImageSourceFolder>None</ImageSourceFolder>
<ImageDesinationFolder>None</ImageDesinationFolder>
</Design>
</DesignConfiguration>
I want to select the part where the part where there is Design name="somethning" and get the descendants and then update the descendants value that means this part:
<SourceFolder>C:\CSF_Packages</SourceFolder>
<DestinationFolder>C:\Documents and Settings\xxx</DestinationFolder>
<CopyLookups>True</CopyLookups>
<CopyImages>False</CopyImages>
<ImageSourceFolder>None</ImageSourceFolder>
<ImageDesinationFolder>None</ImageDesinationFolder>
I have this code:
XDocument configXml = XDocument.Load(configXMLFileName);
var updateData = configXml.Descendants("DesignConfiguration").Elements().Where(el => el.Name == "Design" &&
el.Attribute("name").Value.Equals("CSF_Packages")).FirstOrDefault();
configXml.Save(configXMLFileName);
I'm getting the null data in the updateData varibale. When I'm trying the Descendat's function through QuickWatch it also returns a null value. When I'm checking the configXML variable it has data that is my whole xml. What am I doing wrong?
Try this:
var updateData =
confixXml
.Root //Root Element
.Elements("Design") //All elements under root called Design
.Where(element => (String)element.Attribute("name") == "AFP_GRAFIKA") //Find the one with the name Attribute of AFP_GRAFIKA
.FirstOrDefault(); //Grab the first one it finds or return null.
if (updateData != null)
{
var myElements =
updateData
.Elements(); //All the elements under the Design node
}
XDocument xml = XDocument.Load("");
XElement settings = (from children in xml.Descendants("DesignConfiguration")
where children.Name.Equals("Design") && children.Attribute("name").Equals("CSF_Packages")
select children).FirstOrDefault();
settings.Element("SourceFolder").SetValue("filepath");
settings.Element("CopyImages").SetValue(true);
Ok, so I've managed to fix the problem. I don't know why but it worked. It seems that the Descendants function returns null as a stand alone function but with linq it works. So for my solution only thing what should be done is this:
var updateData = (from s in configXml.Descendants("Design")
where s.Attribute("name").Value == design.DesignName
select s).First();
At first before I sent you my question I've tried this but I didn't have the select s part. Besides when I wrote the where s.Atribute part in the curly brackets I've inserted the design.DesignName object instead of the name of the attribute. So no it works ok. Thanks for your help and everything. Til nex time. Have a nice day/night everyone :)
Because DesignConfiguration was your root node, the Descendants("DesignConfiguration) was returning null. By using the .Descendants("Design"), you were looking at child nodes, not the self.
I have the following XML:
<?xml version="1.0" encoding="UTF-8"?>
<game>
<name>Space Blaster</name>
<description></description>
<version>1</version>
<fullscreen>false</fullscreen>
<width>640</width>
<height>640</height>
<c2release>6900</c2release>
</game>
It's guaranteed to only have 1 game record in it. I'd like to retrieve each property value, this is what I've tried:
string ArcadeXMLLocation = Settings.GamePergatoryLocation + UserID + "/unzipped/arcade.xml";
XDocument loaded = XDocument.Load(ArcadeXMLLocation);
var q = (from c in loaded.Descendants("game") select (string)c.Element("name")).SingleOrDefault();
Response.Write(q.name);
But I can't seem to take any values like this (intellisense hates it!) Can someone show me how it's done?
I think you just need to get the value of the element:
string val = doc.Descendants("game")
.Select(x => x.Element("name").Value).FirstOrDefault();
As a prerequisite to the above, and so intellisense picks it up, make sure that you import the System.Linq and System.Xml.Linq namespaces.
This will get you all the descendants with the tag "game"
You just need the FirstOrDefault() to get the only record if it exists.
var q = from c in loaded.Descendants("game")
select new { Name = c.Element("name").Value
Description = c.Element("description").Value
};
q.FirstOrDefault();
You query is actually correct (tested and worked for me) for extracting the value of the name node - the (string) cast that you are doing will extract the value of the name node as string and not give you the node object itself, this is one of the shortcuts built into Linq to Xml. All that is left is to print out the name:
Response.Write(q);
var q = (from c in loaded.Descendants("game") select (string)c.Element("name")).SingleOrDefault();
Console.WriteLine(q);
is enough. or to avoid the cast
var q = (from c in loaded.Descendants("game") select c.Element("name").Value).SingleOrDefault();
Console.WriteLine(q);