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

XPath reader-writer

Rate me:
Please Sign up or sign in to vote.
4.87/5 (15 votes)
26 May 20033 min read 116.2K   3.2K   45  
Writes data in an XML file using XPath
using System;
using System.Xml;

namespace XPathXmlStore
{
	/// <summary>
	/// Reads & writes data in xml file with XPath that doesn't exists yet.
	/// </summary>
	public class XPathStore
	{
		protected System.Xml.XmlDocument doc;
		protected string sXmlFileName;

		public XPathStore()
		{
			doc = new XmlDocument();
			sXmlFileName = "..\\..\\settings.xml";
			LoadSettings();
		}

		public void LoadSettings()
		{
			bool bReadOK = false;

			try
			{
				// load the XML from file
				doc.Load(sXmlFileName);
				Console.WriteLine ("\nSETTINGS RELOADED" );
				bReadOK = true;
			}
			catch (Exception e)
			{
				Console.WriteLine ("Exception: {0}", e.ToString());
			}

			if(!bReadOK)
			{
				doc.CreateComment("<?xml version=\"1.0\" ?>");
				Console.WriteLine ("\nCREATED NEW" );
			}
		}

		public void SaveSettings()
		{
			try{	doc.Save(sXmlFileName);
					Console.WriteLine ("SETTINGS SAVED");}
			catch (Exception e)	{	Console.WriteLine ("Exception: {0}", e.ToString()); 	}
		}


		/// <summary>
		/// Get a xml node from xPath, if it doesn,t exists create it.
		///
		/// __________ EXAMPLES ____________
		///  FdisSettings/User[@Name="FDIS_DTO"]/@AutoHide
		///  FdisSettings/User[@Name="FDIS_DTO"]/ReportFilter/Report[@Name="Afvoermeldingen per Categorie"]/@ReloadThisSettings
		/// </summary>
		/// <param name="sXPath"></param>
		/// <returns></returns>
		public System.Xml.XmlNode QueryCreatNode( string sXPath )
		{
			Console.WriteLine ("Query xml document with Xpath={0}", sXPath );
			XmlNode		node = null;

			try
			{	
				XmlNodeList list = doc.SelectNodes( sXPath );
				if( list.Count==1 )
					return list.Item(0);		// The easy way (The node exists)
				else if( list.Count==0 )
				{
					Console.WriteLine ("	ACTION) create XPath to node");

					// Parses XPath in separate parts.
					bool	bParsingRandomText	= false;
					int		nXpathPartStart		= -1;
		
					for( int i=0; i<sXPath.Length; i++ )
					{
						if( !bParsingRandomText												&&
							( (sXPath[i]=='/' || sXPath[i]=='\0') || i==sXPath.Length-1 )	&&
							nXpathPartStart!=-1													)
						{
							if( i==sXPath.Length-1 )
								i++;					// Include last caracter

							// handle this XPath part
							node = QueryCreateNode( node, sXPath.Substring( nXpathPartStart, i-nXpathPartStart ) );

							nXpathPartStart = -1;
						}
						else if( sXPath[i]=='\"' )
							bParsingRandomText = !bParsingRandomText;	//  After '"' every character is possible, even '/'
						else if( nXpathPartStart==-1 )
							nXpathPartStart = i;
					}
				}
				else 
				{
					// ERROR (only one node expected)
					Console.WriteLine ("ERROR   Xpath:{0}  returns {1} nodes\n	Change XPath or XML so it returns ony one node", sXPath, list.Count );
				}
			}
			catch(Exception e)
			{	
				Console.WriteLine ("Exception: {0}", e.ToString()); 	
				return null;
			}

			return node;
		}


		// Create the required node for XPath
		protected System.Xml.XmlNode QueryCreateNode( System.Xml.XmlNode node, string sXPathPart )
		{
			if( node==null )
				node = doc;
			Console.WriteLine ("	HANDLE XPathPart) current node={0}    XPath={1}", node.Name, sXPathPart );

			//------------------------------------------------------------------------------------
			// Step 1)	Handle select part
			int	nNodeStart = -1;
			int nAttrStart = -1;
			int nLoc = 0;

			for( ; nLoc<sXPathPart.Length; nLoc++ )
			{
				if( nAttrStart==-1 && nNodeStart==-1 )
				{
					if(sXPathPart[nLoc]=='@')
						nAttrStart = nLoc+1;
					else
						nNodeStart = nLoc;
				}

				if( sXPathPart[nLoc]=='[' || nLoc==sXPathPart.Length-1 )
					break;
			}
			if( nLoc==sXPathPart.Length-1 )
				nLoc++;					// Include last caracter


			if( nNodeStart!=-1 )
			{	
				Console.WriteLine ("		ACTION) query node={0}   with XPath={1}", sXPathPart.Substring(nNodeStart,nLoc-nNodeStart), sXPathPart) ;
	
				// Query child Node
				XmlNodeList NodeList = node.SelectNodes( sXPathPart );
				if( NodeList.Count==1 )
					return  NodeList.Item(0);
				else if( NodeList.Count==0 )
				{
					Console.WriteLine ("		ACTION) create node={0}", sXPathPart.Substring(nNodeStart,nLoc-nNodeStart) );
					node = node.AppendChild( doc.CreateElement( sXPathPart.Substring(nNodeStart,nLoc-nNodeStart) ) );
				}
				else 
					Console.WriteLine ("ERROR   XpathPart:{0}  returns {1} nodes\n	Change XPath or XML so it returns ony one node", sXPathPart, NodeList.Count );
			}
			else if( nAttrStart!=-1 )
			{
				// Get Attribute
				Console.WriteLine ("		ACTION) Query node={0} for  Attribute={1}", node.Name, sXPathPart.Substring(nAttrStart,nLoc-nAttrStart) );
				XmlAttributeCollection  AttrCol = node.Attributes;
				node = AttrCol.GetNamedItem( sXPathPart.Substring(nAttrStart,nLoc-nAttrStart) );
				if( node==null )
				{
					Console.WriteLine ("		ACTION) create attibute={0}", sXPathPart.Substring(nAttrStart,nLoc-nAttrStart) );
					node = AttrCol.SetNamedItem( doc.CreateAttribute( sXPathPart.Substring(nAttrStart,nLoc-nAttrStart) ) );
				}
			}


			//------------------------------------------------------------------------------------
			// Step 2)	Handle filter parts
			int nAttrNameStart = -1;
			int nAttrTextStart = -1;

			for( ; nLoc<sXPathPart.Length; nLoc++ )
			{
				if( sXPathPart[nLoc]=='@' )
					nAttrNameStart = nLoc+1;
				else if( sXPathPart[nLoc]=='\"' )
				{
					if( nAttrTextStart==-1 )
						nAttrTextStart = nLoc+1;
					else
					{
						Console.WriteLine ("		ACTION) query node={0} for attribute={1}", node.Name, sXPathPart.Substring(nAttrNameStart, nAttrTextStart-nAttrNameStart-2 ) );
						XmlNode attrNode = node.Attributes.GetNamedItem( sXPathPart.Substring(nAttrNameStart, nLoc-nAttrNameStart) );
						if( attrNode==null )
						{
							Console.WriteLine ("		ACTION) create attibute={0}", sXPathPart.Substring(nAttrNameStart, nAttrTextStart-nAttrNameStart-2) );
							attrNode = doc.CreateAttribute( sXPathPart.Substring(nAttrNameStart, nAttrTextStart-nAttrNameStart-2) );
							attrNode.Value = sXPathPart.Substring(nAttrTextStart, nLoc-nAttrTextStart);
							node.Attributes.SetNamedItem( attrNode );
						}

						nAttrNameStart = -1;
						nAttrTextStart = -1;
					}
				}
				else if( sXPathPart[nLoc]==']' )
					break;
			}

			return node;
		}
	}
}

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
Netherlands Netherlands
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions