Simple XPath Usage

Posted on Updated on

If you’re like me, you use a zillion different techniques, but some only rarely. I learned XPath a long time ago, and haven’t used it lately. So, I had to struggle a bit to make it work this time around. To make it easier next time, I’m saving my code where I can find it again quickly. You might find it useful too!

My Task: Extracting Custom Fields from XML

Our ERP allows us to create custom fields, as many as we want; it stores our custom fields in XML format. Here’s a sample, with the fields whimsically renamed to protect everyone’s privacy:

<?xml version="1.0"?>
<ArrayOfEntityPropertyOfString>
	<EntityPropertyOfString>
		<Name>Account Manager</Name>
		<Value>Marge Innovera</Value>
	</EntityPropertyOfString>
	<EntityPropertyOfString>
		<Name>Temporary Housing Provider</Name>
		<Value>Horseshoe Road Inn</Value>
	</EntityPropertyOfString>
	<EntityPropertyOfString>
		<Name>Weight Loss Consultant</Name>
		<Value>Hugh Jazz</Value>
	</EntityPropertyOfString>
	<EntityPropertyOfString>
		<Name>Collection Agent</Name>
		<Value>Amanda Recconwith</Value>
	</EntityPropertyOfString>
	<EntityPropertyOfString>
		<Name>Audiologist</Name>
		<Value>Isabelle Ringing</Value>
	</EntityPropertyOfString>
</ArrayOfEntityPropertyOfString>

My task: extract a couple of these fields and send the values to our eCommerce partner. For example, let’s say I need the name of our Audiologist, ‘Isabelle Ringing’, for our partner. The tool to use is XPath, which is designed for that very purpose. In fact, the XPath query to extract her looks like this:

/ArrayOfEntityPropertyOfString/EntityPropertyOfString[Name=’Audiologist’]/Value

What this XPath query does is:

  • Start at the root, represented by the forward slash ‘/’.
  • From there, find the child XML node named ‘ArrayOfEntityPropertyOfString
  • Find a grandchild node named ‘EntityPropertyOfString
  • With a Name having a value of ‘Audiologist
  • From that node, descend one more level to the child node ‘Value
  • Once we have that node, we can extract its inner text, which should be ‘Isabelle Ringing’

For a tutorial on XPath syntax, you could try W3Schools.

Tip: Use Notepad++ Plugins to Get Started

Notepad++ has a ton of useful plugins, you can use the XML tools for building and testing XPath queries. Start by asking it to give you a starter XPath query, as shown in the screen shot below:

Screen Shot Showing Notepad++ Plugin for XML
The current XML path is part of my XPath query; I just need to add the part where I select using the value of the Name child node

Once you have the XML path, you can modify it to meet your exact needs. If you don’t have the XML Tools Plugin, use the Plugin Manager to download it – the price is free.

Use your XPath Query in Code

I needed different fields from that same XML at different points, so I wrote a routine to extract different field values based on the name. That allowed me to reuse the code a couple times.

using System.Xml;
using System.IO;

public static string ExtractCustomField(string xml, string fieldCaption) {
  string result = "";
  if (!string.IsNullOrWhiteSpace(xml)) {
    string xPath = "/ArrayOfEntityPropertyOfString/EntityPropertyOfString[Name='{0}']/Value";
    string xPathQuery = string.Format(xPath, fieldCaption);
    XmlDocument xDoc = new XmlDocument();
    //We need a stream to load the XML, and StringReader works fine
    StringReader sr = new StringReader(xml);
    xDoc.Load(sr);
    XmlNode targetNode = xDoc.SelectSingleNode(xPathQuery);
    if (targetNode != null) {
      result = targetNode.InnerText;
    }
  }
  return result;
}

And, here is some sample usage:

string xml = ErpGetCustomFieldXml(orderId);
string audiologist = ExtractCustomField(xml, "Audiologist");
string collectionAgent = ExtractCustomField(xml, "Collection Agent");

One more Notepad++ tip: you can use it to test your XPath queries, which is a lot easier than doing so in your code!

Step One: Use the Menu to Start testing your XPath Query
Step One: Use the Menu to Start testing your XPath Query
Step Two: Enter your XPath Expression and See the Results
Step Two: Enter your XPath Expression and See the Results

Alternate Means to the Same End

I could have done a couple different techniques:

  1. Regular expression. Problem: each node would require a slightly different regex
  2. Linq to XML. [Edit: I wasn’t familiar with Linq to XML until now. Having spent a couple hours studying it, it seems somewhat easier than XPath.]
private string ExtractCustomField(string xml, string fieldCaption) {
  XDocument myXDoc = XDocument.Load(new StringReader(xml));
  //Try and get the Audiologist's name
  var matches = from n in myXDoc.Descendants("EntityPropertyOfString")
                where n.Element("Name").Value == "Audiologist"
                select n.Element("Value").Value;

  string result = (matches.Count() > 0)
                ? matches.FirstOrDefault()
                : "";
  return result;
}

 

Summary

XPath allows you to search for the field you want. If you write a reusable method, you can extract different field values by passing a field name and reuse the same code.

Leave a comment