1

I'm writing a program to parse XML file (with Book contents).

What I did,

XmlDoc = new XmlDocument();
XmlDoc.Load(path);
bookList = XmlDoc.GetElementsByTagName("book");
List<string> prices= new List<string>();

    foreach (XmlNode node in bookList)
    {
         XmlNode price = node["price"];
         prices.Add(price.InnerText);
    }
// to get the highest priced book(s)
prices.Sort();

What I wanna do now is use SelectNodes to look for the highest priced books, and return it as a XMLNodeList

//to store the highest price of a book
string highest = prices[0];

**// this is what i can't figure out
XmlNodeList expensiveList = XmlDoc.SelectNodes("descendant::book[price = highest]");**

Any help is appreciated, thanks!

EDIT: I managed to get around it by making a foreach loop for nodes in bookList with a if case to compare price.InnerText with highest. It's working perfectly but I'd still like to know if this can be done with XPath. Thanks!

EDIT #2: I get that it can be improved upon using different approaches, I just wanna know if it is possible to compare string variable with node values with XPath.

Ankit
  • 155
  • 1
  • 13
  • Any reason you aren't using Linq2Xml? Linq provides a very easy to way to select, sort, order and filter XML nodes. – Erik Philips Apr 23 '15 at 04:57
  • There is a sort mentioned in [social.msdn](https://social.msdn.microsoft.com/Forums/en-US/60ba8eef-4318-4361-a434-e07efc7bdc77/xml-filter-and-sort?forum=xmlandnetfx). have you tried that? – lloyd Apr 23 '15 at 05:01
  • @Erik I'm not familiar with Linq2Xml but i'll look into it. I researched Xpath for almost an hour and found many ways to compare values but not variables, thus the question. – Ankit Apr 23 '15 at 05:02
  • Possible duplicate of https://stackoverflow.com/questions/1128745/how-can-i-use-xpath-to-find-the-minimum-value-of-an-attribute-in-a-set-of-elemen – dbc Apr 23 '15 at 05:05
  • @dbc I want to compare string variable with a node value from the file, how is that related to range compare b/w the same node? – Ankit Apr 23 '15 at 05:07
  • That answer has some suggestions for finding nodes with largest and smallest attribute values directly, without needing to make and sort an intermediate price list. Very similar to the answer of @murtazat actually. – dbc Apr 23 '15 at 05:16

2 Answers2

1

If you decided to use Linq2XML the code would look something very similar to: (since I don't actually have your XML, this is what I came up with)

// load from a file
var xDoc = XDocument.Load(path);

// find all nodes where the tagname is book
var books = xDoc.Descendants("book")

var expensiveList = books

  // make sure that the book has a price node
  .Where(b => b.Descendants("price").FirstOrDefault() != null

    // compare the first price node Value to highest
    && b.Descendants("price").First().Value.Equals("highest",
      StringComparison.OrdinalIgnoreCase))

  // lets only return up to 10
  .Take(10)

  // return what we found as List<XElement>
  .ToList();

If price was actually an integer then:

   int tempParse;

   ...     

  // make sure that the book has only 1 price
  .Where(b => b.Descendants("price").Count() == 1

    // price is actually an integer (you can replace with decimal)
    && int.TryParse(b.Descendants("price").First().Value, out tempParse))

  // make a temporary anonymous object to sort price
  .Select(b => new 
  {
    Book = b,
    Price = int.Parse(b.Descendants("price").First().Value)
  })

  // order the anonymous object by price
  .OrderByDescending(b => b.Price)

  // select only the books
  .Select(b => b.Book)

  // lets only return up to 10
  .Take(10)

   // return what we found as List<XElement>
  .ToList();
Erik Philips
  • 53,428
  • 11
  • 128
  • 150
  • Interesting. This does look more thorough and direct approach. I'll definitely give it a try. Thanks Erik – Ankit Apr 23 '15 at 05:11
0

Some suggestions:

  1. You should not take a string array to store prices. Integer array would be better.
  2. Validate price.InnerText before adding it to list - it may be possible it is not a numeric value.
  3. Once you have an integer array - you could sort it and select the max. To select the book with highest price, you may use syntax like

    XmlNodeList expensiveList = XmlDoc.SelectNodes("//book[price = highest]");

If you do not want to find out the highest price separately - there is a way to grab the node with highest value directly. See this thread.

Selecting the min/max value of an attribute under multiple nodes in XPath 1.0

Hope this helps

Community
  • 1
  • 1
murtazat
  • 399
  • 3
  • 12