Sort XmlNodeList with a specific Node value - c#

I searched the web for this, but I am not able to find any related solution.
I have following XML
<Table>
<Entity>Employee</Entity>
<EntityID>2786</EntityID>
<Goal>
<GoalId>31931</GoalId>
<FilterData>LastModifiedOn¥2014-03-20T18:11:01.0000000+05:30ÆActiveTaskCount¥0</FilterData>
</Goal>
<Goal>
<GoalId>31932</GoalId>
<FilterData>LastModifiedOn¥2014-03-22T15:26:09.0000000+05:30ÆActiveTaskCount¥0</FilterData>
</Goal>
<Goal>
<GoalId>31932</GoalId>
<FilterData>LastModifiedOn¥2014-03-22T09:25:00.0000000+05:30ÆActiveTaskCount¥0</FilterData>
</Goal>
</Table>
From above XML when I read the data I got 2 separate DataTables; 1 for Employees and another one for related Goals.
What I needed is I want to sort all the Goals related to an employee with respect to LastModifiedOn from FilterData node.
NOTE: I am getting the LastModifiedOn value by split node value like this
nodevalue.Split('Æ')[0].Split('¥')[1]
Right now I am using System.XML namespace for doing operations. I also looked at LINQ TO XML but I am unable to make it work.
I am getting the XMLNodelist by following code
XmlNodeList GoalNodesList = doc.DocumentElement.SelectNodes("/NewDataSet/Table[Entity='Employee' and EntityID='" + EntityId + "']/Goal");
Here I want the Sorted Goals (with respect to LastModifiedOn).
I also looked at some useful links but didn't get any idea so far
Sorting XML nodes based on DateTime attribute C#, XPath
XMLdocument Sort
I am ready to convert the code into LINQ TO XML but needed a brief example.

One thing you could try is creating a collection of key value pairs where key is the goal and value is the date. You could then override the CompareTo method by comparing the dates and then you could just use [collection name].Sort(). Hope this helps

Related

How to select multiple nodes based on a maximum child element value in XPath 1.0 (C#, WPF)

Environment:
Writing a WPF application using C# (and Visual Studio 2015)
Restricted to using XPath 1.0
Goal: I need to select multiple specific xml nodes from an XML document based on the value of a child element within the specific node
Situation so far: Currently, I have several XPath queries that select individual nodes and get the Value of attributes and elements. The one I am having trouble with is shown below.
var xUsageSummary = xDoc.XPathSelectElements("
/root
/table[not(contains(#tagname,'pole'))]
/*[not(maximum_usage < ../*/maximum_usage)]");
Edited to show modified table and updated maximum_usage
It seems that the issue is coming from the last section of the XPath string, at the ../*/maximum_usage. While the elements being selected are filtered by the not(contains(#tagname,'pole')) predicate, I think that ../*/maximum_usage is not getting the correct data based on the filter. Perhaps the * should be replaced with something that would represent the name of the element from which the maximum_usage value is being taken.
<root>
<table tagname="summary_of_brace_usages">
<summary_of_brace_usages>
<brace_label>brace1</brace_label>
<maximum_usage>55.00</maximum_usage>
<load_case>CaseA</load_case>
</summary_of_brace_usages>
<summary_of_brace_usages>
<brace_label>brace2</brace_label>
<maximum_usage>70.00</maximum_usage>
<load_case>CaseA</load_case>
</summary_of_brace_usages>
</table>
<table tagname="summary_of_pole_usages">
<summary_of_pole_usages>
<pole_label>pole1</pole_label>
<maximum_usage>23.63<maximum_usage>
<load_case>CaseB<load_case>
</summary_of_pole_usages>
<summary_of_pole_usages>
<pole_label>pole1</pole_label>
<maximum_usage>85.25<maximum_usage>
<load_case>CaseB<load_case>
</summary_of_pole_usages>
</table>
<table tagname="summary_of_x_arm_usages">
<summary_of_x_arm_usages>
<brace_label>xarm1</brace_label>
<maximum_usage>42.00</maximum_usage>
<load_case>CaseA</load_case>
</summary_of_x_arm_usages>
<summary_of_x_arm_usages>
<brace_label>xarmA</brace_label>
<maximum_usage>95.00</maximum_usage>
<load_case>CaseA</load_case>
</summary_of_x_arm_usages>
</table>
</root>
Edited to show modified sample XML
The desired output from the XML sample above should be an IEnumerable that contains two XElements;
/root/table/summary_of_brace_usages //(where #maximum_usage 70, because it is the largest "maximum_usage" value)
and
/root/table/summary_of_x_arm_usages //(where #maximum_usage is 95, because it is the largest "maximum_usage" value)
After the correct IEnumerable is returned, I will be able to get the other element values and write them to variables and ultimately properties of a class so they can be put into a FlowDocument for printing with my WPF application.
Any help is much appreciated and I will be glad to give any additional information if it is needed - thank you in advance!
The problem was that name()/maximum_usage isn't valid XPath expression. Replace name() with ../*/maximum_usage to get all maximum_usage within within current table. Also, # is used to reference attribute, so you need to remove that since it is a child element instead of attribute that you're working with in this case :
/root
/table
/*[not(maximum_usage < ../*/maximum_usage)]
xpath demo

Query XDocument based on the depth of the node

I have the following XML and I want to be able to query the XML based on the depth of it. I am aware of the depth before hand.
UPDATED QUESTION:
I have the following XML and I want to be able to query the XML based on if the nodes are repetitive.
So, this is my XML
<Books>
<BookID>12345</BookID>
<BookName>BookName</BookName>
<Authors>
<Author>
<Name>AuthorNameOne</Name>
<City>New York</City>
</Author>
<Author>
<Name>AuthorNameTwo</Name>
<City>New York</City>
</Author>
</Authors>
</Books>
Via XDocument I want to be able to query this XML and get node names for the elements where there is repetitive data such as Authors. Or I want to be able to query it based on the Depth of the Node.
UPDATED QUESTION:
Via XDocument I want to be able to query this XML and get node names for the elements where there is repetitive data such as Authors.
Any help will be much appreciated.
Your XML still doesn't really make sense, but I'm putting together this answer hoping that it will at least point you in the right direction. I'm going to completely ignore the portion of your question that references node depth because I'm not really sure how it applies to the following question that you posted:
Via XDocument I want to be able to query this XML and get node names for the elements where there is repetitive data such as Authors.
Here's how to do just that simple type query assuming that your XDocument is named xml:
List<XElement> repeatedNodes = new List<XElement>();
for(XElement node in xml.Descendants())
{
if(node.Parent.Elements(node.Name).Count() > 1))
{
repeatedNodes.Add(node);
}
}
Here's the same code compressed into a lambda that will provide you with an IEnumerable<XElement> containing all of the elements that would go into the List in my first example:
var dupes = xml.Descandants().Where(n => n.Parent.Elements(n.Name).Count() > 1);
This algorithm will look at every node in the xml tree and then from the parent of the current node it will count how many nodes with that same name exist. If that number is greater than one it will add it to our list of repeated nodes. This does not care what depth the current node is and it will only count duplicate named nodes at the same depth. Additionally this algorithm will put dupes in the List structure, but you can add in your own logic to prevent it from doing that or use a different structure that doesn't allow duplicates.

Get node from UrlName in Umbraco

I am working on an Umbraco set up (Umbraco 7) and I need to be able to load a node from a node.UrlName.
I tried Xpath but that didn't work. Here is my xpath:
var facNode = umbraco.NodeFactory.Node.GetNodeByXpath("/*[#UrlName='" + urlName + "']");
I have also tried a few variations of this without /, with // and just looking for an id instead of a UrlName.
This seems to be something fairly simple but I seem to be missing something. I am pretty new to Umbraco so any help would be greatly appreciated.
Id there a better way than xpath? What class should I be using for this?
Thanks in advance!
Well, there are a couple of things here. Firstly, the xpath is case-sensitive, so you need to target #urlName not #UrlName.
Also it's worth pointing out that trying to locate a node by the urlName property isn't a very good strategy because multiple nodes could have an identical urlName property. This is possible because Umbraco only insists that the urlName property is unique where the node shares the same parent.
This makes sense because (e.g. when grouping news/blog articles) you may want a node called October under a node called 2014 but also a node called October under a parent called 2013. In this scenario, your xpath would locate both October nodes and therefore not work.
As far as a btter way, it depends on what the context is and what you are trying to achieve. You certainly should be avoiding using the umbraco.NodeFactory.Node as from Umbraco 4.8 the standard has been to use the IPublishedContent interface which is arguably more flexible.

Retrieve Values manually from XML InnerXML

I have been trying to deserialize the InnerXML into a class and for some reason the XML keeps changing shape and however many times I try to get the class right it seems to change shape again.
So I have given up and decided to try another method.
Is it possible to retrieve the value of a parameter within the InnerXML manually using c#?
Say for example, my XML innerXML looked like this:
<Timestamp>2014-08-22T21:45:00Z</Timestamp>
<Subscriber>https://www.dogdoza.co.uk</Subscriber>
<Order>
<OrderID>111867</OrderID>
<InvoiceNumber>DOZA-9725410</InvoiceNumber>
<CustomerID>4542</CustomerID>
Is it possible to pull out say the value of Subscriber
If this is possible I can just pull out the values I want manually. Not ideal, but there are only about 10...
I have looked around but not managed to find any code I can get working..
Can anyone please give me any guidance?
Thanks
You can do achieve what you want using LINQ to XML:
XElement myXml = XElement.Load(#"XmlLocationHere");
XElement subscriber = myXml.Descendants("Subscriber").FirstOrDefault();
XElement.Descendants returns a collection of the descendant elements for this document or element, in document order. This method will return an IEnumerable<XElement>, since there might be more than one "Subscriber" element, but in your case, we choose FirstOrDefault, which returns the first occurrence.
Try loading your XML into an XDocument. Then try to use XPathSelectElement to find the specific value you want.
It could be that you need to wrap your inner xml into a root element, because it doesn't accept multiple roots.
Pseudo example:
// set up your xml document
string xml = "<rootelement>" + myInnerXml + "</rootelement>";
XDocument doc = new XDocument();
doc.Parse(xml);
XElement subscriber = doc.XPathSelectElement("/rootelement/Subscriber");
string value = subscriber.Value;

how to load a hashtable from a simple xml file using xmltextreader

using xmltextreader, how would I load a hashtable.
XML:
<base><user name="john">2342343</user><user name="mark">239099393</user></base>
This was asked before but it was using some funky linq that I am not fully comfortable with just yet.
Well, the LINQ to XML solution is really easy, so I suggest we try to make you comfortable with that instead of creating a more complex solution. Here's the code, with plenty of explanation...
// Load the whole document into memory, as an element
XElement root = XElement.Load(xmlReader);
// Get a sequence of users
IEnumerable<XElement> users = root.Elements("user");
// Convert this sequence to a dictionary...
Dictionary<string, string> userMap = users.ToDictionary(
element => element.Attribute("name").Value, // Key selector
element => element.Value); // Value selector
Of course you could do this all in one go - and I'd probably combine the second and third statements. But that's about as conceptually simple as it's likely to get. It would become more complicated if you wanted to put error handling around the possibility that a user element might not have a name, admittedly. (This code will throw a NullReferenceException in that case.)
Note that this assumes you want the name as the key and id as value. If you want the hashtable the other way round, just switch the order of the lambda expressions.

Categories

Resources