XPath and XML My first serious use of XPath came along only relatively recently when one considers the lifespan of halfgk.com. I had created a schema for use in a nerdy datagrid of software experience. The schema calls for two elements that contain elements -- one for platforms and one for languages. The concept is simple enough: the platforms node can contain multiple "platform" nodes (operating system platforms, like Windows 10, Apple OSX and the like), and the "languages" node can likewise contain multiple "language" nodes (programming languages, like Visual Basic. NET, JavaScript, and so forth). Some software runs on multiple platforms, while some are Web-based systems and run independently of operating systems. Some software supports multiple programming languages, while others aren't programming software at all. I needed a way to list the platforms and languages in a datagrid all in a single row of a datagrid. If the schema looks like this: . . . I want to display it on a single row of the datagrid, like this: NAME TYPE PLATFORMS LANGUAGES ================================================================================= EditPad Pro Text Editor Microsoft Windows CSS, HTML, JavaScript, Regular Expressions, XML --------------------------------------------------------------------------------- I don't intend to get too deep into the mechanics of the datagrid control here -- the purpose of this how-to is to walk you through using XPath -- though there are places where the two topics converge. I'll try to keep such unions are brief as possible. ============ CODE FORWARD ============ About the only thing I want to say about the code forward is that the datagrid columns for the platforms and languages nodes are the plural nodes ("languages") -- not for the singular ones ("language"), as below:   The secret sauce here is in the lblLanguages label in the item template of the "Languages" template column. Or at least, it's where the secret sauce goes. Also important is the lblName label in the "Name" template column, because that's the value we're going to use to specify which languages we want. Read on. =========== CODE BEHIND =========== We're going to skip over most of the contents of the code behind pertaining to the datagrid -- suffice it to say, the datagrid is configured and bound to the dataset. But the datagrid will require an ItemDataBound event handler, because that's where our XPath goop comes into play. Essentially, each data item in each row will get populated by the standard data binding method, and then the ItemDataBound event handler will use XPath to mine the dataset for the individual platform and language data. We're going to do that in part by creating a function to handle the heavy lifting, then call that function from the ItemDataBound event handler. Here's our heavy lifter. We're going to pass in the name of a software and the path of the node we're interested in, and use navigator and iterator objects to find the goop we're looking for in the XML file called "software.xml": Private Function getXpathData (ByVal strName As String, ByVal strPath As String) As ArrayList Dim listOut As New ArrayList If Not (strName = String.Empty) AndAlso Not (strPath = String.Empty) Then Dim doc As New XPathDocument(Server.MapPath("~/software.xml")) Dim objNavigator As XPathNavigator = doc.CreateNavigator() Dim objIterator As XPathNodeIterator = objNavigator.Select("/toolset/tool[name = '" & strName & "']" & strPath) While objIterator.MoveNext() listOut.Add(objIterator.Current.Value) End While 'sort the arraylist listOut.Sort() End If 'Not (strName = String.Empty) AndAlso Not (strPath = String.Empty) Return listOut End Function Take a good long look at the line where the iterator object is instantiated, and compare it with the schema near the top of the file. We're telling the iterator to look at the specific node the navigator can select with the path "/toolset/ tool[name = 'foo']", plus whatever other path information we choose to append (in the case of the language data, we'd pass in "/languages/language"). Compare with the schema: If this data is found, the iterator's job is to add every language node it finds for software "foo" to the ArrayList object. Next, we're going to sort that list and return it back to the ItemDataBound event handler. The code in the ItemDataBound event handler that calls our function is as follows: If e.Item.ItemType = ListItemType.Item Or e.Item.ItemType = ListItemType.AlternatingItem Then Try 'strName is used to feed the XPath queries Dim lblName As Label = CType(e.Item.FindControl("lblName"), Label) Dim strName As String = lblName.Text.Trim Dim lblLanguages As Label = CType(e.Item.FindControl("lblLanguages"), Label) . . . Dim listLanguages As ArrayList = getXpathData(strName, "/languages/language") For intCount = 0 To (listLanguages.Count - 1) lblLanguages.Text += CType(listLanguages(intCount), String) If intCount < (listLanguages.Count - 1) Then lblLanguages.Text += ", " End If Next . . . End If Let's walk this through. That "If" is a BIG "If" -- without it this code will blow up every time you try to run it, because the first row the event handler will attempt to evaluate will be a header row, with none of this code in it. Inside the Try-Catch-End Try block (only the "Try" appears), our first order of business is to get the name of the software in the row being examined. We do that by grabbing the label called "lblName" from the "Name" column in the code forward, and passing its value along with the path for the languages we want into the function. (If we were looking for the platform information instead, we'd pass in the platform path instead.) We're also getting a reference to the lblLanguages label control for reasons that will become clear shortly. As we've already discovered, the function will return for us a neatly sorted ArrayList object containing all of the languages found for software "foo." The For-Next loop simply iterates through the list and adds each value to the Text property of the Languages label ("lblLanguages") which, as stated above, is the label in the item template of the "Languages" data column. See? I told you it's where the secret sauce goes! When the page is loaded, the datagrid is populated, and as each object is data bound, the ItemDataBound event handler examines each item by type, calls our XPath function, finds data using the software name and the language path and returns it to us so we can slap it all in a label. Whew -- that was a long sentence. The same is true for the platform data elsewhere in the event handler. Once all of the items are data bound, the completed grid is displayed. Contact me using the site's contact form if you have questions. Feel free to use the code in your projects. A shout out in your project would be thoughtful. Also, drop me a line and let me know how you might have tweaked things to better suit your needs. Finally, I wouldn't profess to be THE expert on matters represented in my code -- so drop me a line if you have constructive suggestions, too. I'd like to hear from you! Best, halfgk copyright 2018 halfgk.com