Click here to Skip to main content
15,893,588 members
Articles / Web Development / ASP.NET

Advanced XPath Analyzer

Rate me:
Please Sign up or sign in to vote.
4.07/5 (10 votes)
30 Dec 20032 min read 113.3K   1.3K   25  
An advanced XPath Query Analyzer, based on the work of Enrico Elizar Samuel. This advanced version supports namespaces resolution.
using System;
using System.Data;
using System.Text;
using System.Web;
using System.Xml;
using System.Xml.XPath;
using System.Collections;

namespace AdvancedXPathAnalyzer
{
	public class AXAEngine {
		private int indentLevel;
		private XPathDocument document;
		private XPathNavigator navigator;
		private XPathExpression expression;
		private XmlNamespaceManager namespaceManager;
		private string xmlSourceFile;

		private ArrayList DetectedNamespaces;

		#region Contructors
		
		public AXAEngine(string xmlSourceFile) {
			indentLevel = 0;
			this.xmlSourceFile = xmlSourceFile;

			//Instantiate XPathDocument and load XML document
			document = new XPathDocument(xmlSourceFile);

			//Instantiate XPathNavigator
			navigator = document.CreateNavigator();
		}

		#endregion

		#region Public Methods

		public DataView Analyze(string xpathQuery, Array namespaces) {
			XPathNodeIterator nodeIterator;
			DataTable resultTable;
			DataRow resultRow;
			string attribute;
			int totalNode = 0;
			string nodeType;

			//Create temporary table to keep query result
			resultTable = new DataTable("QueryResult");
			resultTable.Columns.Add("node",  Type.GetType("System.String"));
			resultTable.Columns.Add("value",  Type.GetType("System.String"));
			resultTable.Columns.Add("attribute",  Type.GetType("System.String"));

			//Create a namespace manager
			namespaceManager = new XmlNamespaceManager(new NameTable());
			foreach(string ns in namespaces) {
				int tokenPos = ns.IndexOf(':');

				string prefix = ns.Substring(0, tokenPos);
				string uri = ns.Substring(tokenPos+1);

				namespaceManager.AddNamespace(prefix.Trim(), uri.Trim());
			}

			//Instantiate XPathExpression
			expression = navigator.Compile(xpathQuery);
			if (namespaceManager != null) 
				expression.SetContext(namespaceManager);

			//Execute XPath query
			nodeIterator = navigator.Select(expression);

			//Iterate through the resultant node set
			while (nodeIterator.MoveNext()) {

				//Count the number of nodes in the node set
				totalNode += 1;

				//Get the current node as XPathNavigator object
				navigator = nodeIterator.Current;

				//Create a new row in the temporary table
				resultRow = resultTable.NewRow();

				//Fill the first column of new row
				switch (navigator.NodeType) {

					case XPathNodeType.Element : 
						nodeType = "<>";
						break;
					
					case XPathNodeType.Attribute :
						nodeType = "=";
						break;

					case XPathNodeType.Text :
						nodeType = "Abc";
						break;
                        
					case XPathNodeType.Comment :
						nodeType = "<!>";
						break;

					default :
						nodeType = "";
						break;
				}
				
				resultRow["node"] = string.Format("<font color=\"red\"><b>{0}</b></font>{1}", nodeType, navigator.Name);

				//Fill the second column of new row
				if (navigator.MoveToFirstChild()) {
					resultRow["value"] = RenderTree();
					navigator.MoveToParent();
				} else {
					resultRow["value"] = navigator.Value;
				}

				//Fill the third column of new row
				attribute = string.Empty;
				if (navigator.NodeType == XPathNodeType.Attribute) {
					resultRow["attribute"] = "n/a";
				} else {
					//Iterate through attributes if any
					if (navigator.MoveToFirstAttribute()) {
						do {
							attribute += string.Format("{0}: {1}<br>", navigator.Name, navigator.Value);
						} while (navigator.MoveToNextAttribute());
						navigator.MoveToParent();
						resultRow["attribute"] = attribute;
					}
				}

				//Effectively add the new row to the temporary table
				resultTable.Rows.Add(resultRow);
			}

			return resultTable.DefaultView;
		}

		public Array DetectNamespaces() {
			XmlDocument xmlDoc = new XmlDocument();
			xmlDoc.Load(xmlSourceFile);

			DetectedNamespaces = new ArrayList();

			XmlNode xmlNode = xmlDoc.DocumentElement;
			NamespaceDiscover(xmlNode);

			return DetectedNamespaces.ToArray();
		}

		#endregion

		#region Private Methods

		private string RenderTree() {
			StringBuilder sb = new StringBuilder();

			//Iterate through all siblings
			do {
				switch (navigator.NodeType) {
					case XPathNodeType.Text :
						sb.Append(navigator.Value);
						break;

					case XPathNodeType.Comment :
						sb.AppendFormat("&lt;!-- {0} --&gt;<br>", navigator.Value);
						break;

					default :
						//Render indent
						sb.Append(RenderHTMLSpace(indentLevel));

						//Render opening tag
						sb.Append("&lt;");
						sb.Append(navigator.Name);

						//Render attributes if any
						if (navigator.MoveToFirstAttribute()) {
							do {
								sb.AppendFormat(" {0}=\"{1}\"", navigator.Name, navigator.Value);
							} while(navigator.MoveToNextAttribute());
							navigator.MoveToParent();
						}
						sb.Append("&gt;");

						//Render child nodes if any
						if (navigator.MoveToFirstChild()) {
							if (navigator.NodeType != XPathNodeType.Text) {
								sb.Append("<br>");
							}

							indentLevel += 2;

							//Invoke this function recursively
							sb.Append(RenderTree());

							indentLevel -= 2;

							//Move back to the parent node
							navigator.MoveToParent();
						}

						//Render closing tag
						sb.AppendFormat("&lt;/{0}&gt;<br>", navigator.Name);
						break;
					}
			} while (navigator.MoveToNext());

			return sb.ToString();
		}
	
		private string RenderHTMLSpace(int totalSpace) {
			StringBuilder spaces = new StringBuilder();

			if (totalSpace > 0)
				spaces.Insert(0, "&nbsp", totalSpace);

			return spaces.ToString();
		}

		private void NamespaceDiscover(XmlNode xNode) {
			string nsPrefix;
			string nsUri;

			namespaceManager = new XmlNamespaceManager(new NameTable());

			if (xNode.NodeType == XmlNodeType.Element) {
				if (xNode.Attributes.Count > 0) {
					int attrNum = 0;
					while (attrNum < xNode.Attributes.Count) {
						if (xNode.Attributes[attrNum].Name.StartsWith("xmlns")) {
							string nsDef = xNode.Attributes[attrNum].Name.Split('=')[0];
							if (nsDef != "xmlns") {
								nsPrefix = nsDef.Split(':')[1];
							}
							else {
								nsPrefix = "def";
							}
							nsUri = xNode.Attributes[attrNum].Value;

							DetectedNamespaces.Add(string.Format("{0}: {1}", nsPrefix, nsUri));
						}
						attrNum++;
					}
				}
				if (xNode.HasChildNodes) {
					int elemNum = 0;
					while (elemNum < xNode.ChildNodes.Count) {
						NamespaceDiscover(xNode.ChildNodes[elemNum]);
						elemNum++;
					}
				}
			}
		}
		
		#endregion
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
Italy Italy
Born in 1977, works as a freelancer, focusing on Database / Software Architecture.
In the free time writes articles for two of the major Italian programming magazines (Computer Programming and VBJ) and also develops nice and useful programs.
His major interests and skills are the .NET framework (C# in particular) and SQL Server.

Comments and Discussions