Hi folks,

I'm trying to write an XMLHandler for my epos app. The XML file (which is received by a network stream) will include multiple "operations" which may include updating the product database or opening the cash drawer etc..

My sample XML file looks like this:

<paypointXML>
	<op>
		<command>opendrawer</command>
	</op>
	<op>
		<command>updateDatabase</command>
		
		<item>
			<desc>Big Book of Tales</desc>
			<price>5.99</price>
			<category>100</category>
		</item>
		
		<item>
			<desc>Small book of Rhymes</desc>
			<price>1.99</price>
			<category>100</category>
		</item>
	</op>
</paypointXML>

So far my c# code looks like this:

private void XMLHandler(string data)
        {
            StringReader str = new StringReader(data);
            XPathDocument doc = new XPathDocument(str);
            XPathNavigator nav = doc.CreateNavigator();

            // Compile a standard XPath expression

            XPathExpression expr;
            expr = nav.Compile("/paypointXML/op/command");
            XPathNodeIterator iterator = nav.Select(expr);

            // Iterate on the node set

            
            try
            {
                while (iterator.MoveNext())
                {
                    XPathNavigator nav2 = iterator.Current.Clone();
                    if (nav2.Value == "opendrawer")
                    {
                        Device.drawerkick();
                    }
                    else if (nav2.Value == "updateDatabase")
                    {
                        //I want this to iterate through all the nodes inside THIS paticular op node..
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }

        }
        
      }

Now, as you can see above my c# code will only ever parse the opendrawer command. I am lost when it comes through iterating through the current node...

Can anyone please help me on how to achieve the above with regarding update my database?
Maybe my XML file struct could be better? Maybe the item details should be inside the command node?

Your help is appreciated thanks

Jonny

Recommended Answers

All 10 Replies

OK, i have managed to find a way around my problem above however I've had to change my XML structure which I don't really like.

Here is the new XML layout:

<paypointXML>

<commands>

<command>opendrawer</command>
<command>updateDatabase</command>

</commands>

<items>

<item>
<desc>Big Book of Tales</desc>
<price>5.99</price>
<category>100</category>
</item>

<item>
<desc>Small book of Rhymes</desc>
<price>1.99</price>
<category>100</category>
</item>

</items>

</paypointXML>

and my c# method looks like this:

private void XMLHandler(string data)
        {
            XmlDocument tdoc = new XmlDocument();
            tdoc.LoadXml(data);
            
            StringReader str = new StringReader(data);
            XPathDocument doc = new XPathDocument(str);
            XPathNavigator nav = doc.CreateNavigator();

            // Compile a standard XPath expression

            XPathExpression expr;
            expr = nav.Compile("/paypointXML/commands/command");
            XPathNodeIterator iterator = nav.Select(expr);

            // Iterate on the node set

            
            try
            {
                while (iterator.MoveNext())
                {
                    XPathNavigator nav2 = iterator.Current.Clone();
                    if (nav2.Value == "opendrawer")
                    {
                        Device.drawerkick();
                    }
                    else if (nav2.Value == "updateDatabase")
                    {
                        foreach (XmlElement item in
                        tdoc.SelectNodes("/paypointXML/items/item"))
                        {
                            string desc = item.SelectSingleNode("desc").InnerText;
                            MessageBox.Show(desc);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }

        }
        
      }

As you can see, I'm reading the XML file twice which probably isn't a good idea..

As you can see, I know next to nothing about XML!

Any ideas on how to make my code more efficient?
Your help is appreciated Thanks

Hi there. How about little change to your xml?

<paypointXML>

<commands>
	<command commandName="opendrawer">
	</command>

	<command commandName="updateDatabase">
		<items>
			<item>
				<desc>Big Book of Tales</desc>
				<price>5.99</price>
				<category>100</category>
			</item>

			<item>
				<desc>Small book of Rhymes</desc>
				<price>1.99</price>
				<category>100</category>
			</item>
		</items>
	</command>

</commands>

</paypointXML>

And then c# like the one below.

try
            {
                while (iterator.MoveNext())
                {
                    XPathNavigator nav2 = iterator.Current.Clone();
                    
                    if (nav2.GetAttribute("commandName", "") == "opendrawer") 
                    {
                        Device.drawerkick();
                    }
                    else if (nav2.GetAttribute("commandName", "") == "updateDatabase")
                    {
                        XPathNodeIterator temIterator = nav2.SelectDescendants(XPathNodeType.Element,false);

                        while (temIterator.MoveNext())
                        {
                            if(temIterator.Current.Name == "desc")
                                MessageBox.Show(temIterator.Current.Value);
                        }
                        
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }

Haven't tested that code. You might find a bug in it.

Change the compile expression!!

expr = nav.Compile("paypointXML/op/command");

Hi There,

Thanks for your reply. It's very close to what I want. What I am actually doing is adding to a database and the problem I think with the above code is that it woudn't be able to do multiple <item> node update?

Here is my XML File:

<paypointXML>

<commands>
	<command commandName="opendrawer">
	</command>


	<command commandName="updateDatabase">
	<items>
		<item>
			<desc>Apple Computer</desc>
			<barcode>5760</barcode>
			<price>899.99</price>
			<vatcode>1</vatcode>
			<category>300</category>
		</item>
                <item>
			<desc>Banana Computer</desc>
			<barcode>5761</barcode>
			<price>999.99</price>
			<vatcode>1</vatcode>
			<category>300</category>
		</item>
	</items>
	</command>
</commands>

</paypointXML>

And here is my c#:

while (iterator.MoveNext())
                {
                    XPathNavigator nav2 = iterator.Current.Clone();
                    if (nav2.GetAttribute("commandName", "") == "opendrawer")
                    {
                        Device.drawerkick();
                    }
                    else if (nav2.GetAttribute("commandName", "") == "updateDatabase")
                    {
                        string desc = "";
                        string barcode = "";
                        string category = "";
                        string vatcode = "";
                        string price = "";
                        
                        XPathNodeIterator temIterator = nav2.SelectDescendants(XPathNodeType.Element, false);

                        while (temIterator.MoveNext())
                        {
                            if (temIterator.Current.Name == "desc") desc = temIterator.Current.Value;
                            else if (temIterator.Current.Name == "barcode") barcode = temIterator.Current.Value;
                            else if (temIterator.Current.Name == "category") category = temIterator.Current.Value;
                            else if (temIterator.Current.Name == "vatcode") vatcode = temIterator.Current.Value;
                            else if (temIterator.Current.Name == "price") price = temIterator.Current.Value;
                        }
                        Remote.AddProduct(barcode, desc, category, vatcode, price);
                    }
                }

How would I get it to acount for multiple item nodes? It is not guarenteed that all the elements of item will be present (i.e. someone may leave out category or vatcode etc...)

Thanks

adatapost>Can I see the table structure?

The table structure may change in time (As different types of database may be used). The Remote.AddProduct method handles updating the table. Is it possible to use this? I'm trying to think of a way to make it check for different <item> nodes..

The table structure may change in time (As different types of database may be used). The Remote.AddProduct method handles updating the table. Is it possible to use this? I'm trying to think of a way to make it check for different <item> nodes..

Definitly, If Remote.AddProduct(..) is invoked from within the loop.

while (temIterator.MoveNext())
                        {
                            if (temIterator.Current.Name == "desc") desc = temIterator.Current.Value;
                            else if (temIterator.Current.Name == "barcode") barcode = temIterator.Current.Value;
                            else if (temIterator.Current.Name == "category") category = temIterator.Current.Value;
                            else if (temIterator.Current.Name == "vatcode") vatcode = temIterator.Current.Value;
                            else if (temIterator.Current.Name == "price") price = temIterator.Current.Value;
                        Remote.AddProduct(barcode, desc, category, vatcode, price);

                        }

I've got this so far:

while (iterator.MoveNext())
                {
                    XPathNavigator nav2 = iterator.Current.Clone();
                    if (nav2.GetAttribute("commandName", "") == "opendrawer")
                    {
                        Device.drawerkick();
                    }
                    else if (nav2.GetAttribute("commandName", "") == "updateDatabase")
                    {
                        string desc = "";
                        string barcode = "";
                        string category = "";
                        string vatcode = "";
                        string price = "";
                        
                        XPathNodeIterator temIterator = nav2.SelectDescendants(XPathNodeType.Element, false);

                        do
                        {
                            if (temIterator.Current.Name == "item")
                            {
                                while (temIterator.MoveNext() && temIterator.Current.Name != "item")
                                {
                                    if (temIterator.Current.Name == "desc") desc = temIterator.Current.Value;
                                    else if (temIterator.Current.Name == "barcode") barcode = temIterator.Current.Value;
                                    else if (temIterator.Current.Name == "category") category = temIterator.Current.Value;
                                    else if (temIterator.Current.Name == "vatcode") vatcode = temIterator.Current.Value;
                                    else if (temIterator.Current.Name == "price") price = temIterator.Current.Value;
                                }
                                Remote.AddProduct(barcode, desc, category, vatcode, price);
                            }
                        } while (temIterator.MoveNext());
                        
                    }
                }

It only adds the first item in the XML file though :(
Where am I going wrong?

Thanks

This will work:

private static void XMLHandler(string data)
        {
            StringReader str = new StringReader(data);
            XPathDocument doc = new XPathDocument(str);
            
            XPathNavigator nav = doc.CreateNavigator();

            // Compile a standard XPath expression

            XPathExpression expr;
            expr = nav.Compile("paypointXML/commands/command");
            XPathNodeIterator iterator = nav.Select(expr);

            // Iterate on the node set
                       
               while (iterator.MoveNext())
                {
                    XPathNavigator nav2 = iterator.Current.Clone();
                    if (nav2.GetAttribute("commandName", "") == "opendrawer")
                    {
                        Console.WriteLine("Command- DD");
                    }
                    else if (nav2.GetAttribute("commandName", "") == "updateDatabase")
                    {
                        string desc = "";
                        string barcode = "";
                        string category = "";
                        string vatcode = "";
                        string price = "";
                        
                        XPathNodeIterator temIterator = nav2.SelectDescendants(XPathNodeType.Element, false);

                        do
                        {
                            bool status = false;
                            if (temIterator.Current.Name == "item")
                            {

                                while (temIterator.MoveNext() && temIterator.Current.Name != "item")
                                {
                                    status = true;
                                    if (temIterator.Current.Name == "desc") desc = temIterator.Current.Value;
                                    else if (temIterator.Current.Name == "barcode") barcode = temIterator.Current.Value;
                                    else if (temIterator.Current.Name == "category") category = temIterator.Current.Value;
                                    else if (temIterator.Current.Name == "vatcode") vatcode = temIterator.Current.Value;
                                    else if (temIterator.Current.Name == "price") price = temIterator.Current.Value;
                                }
                                Console.WriteLine(barcode + " " +  desc + " " + category + " " +  vatcode + " " +  price);
                            }
                            if (status == false)
                                if (temIterator.MoveNext() == false)
                                    break;
                        } while (true);
                        
                    }
                }
        }

Thanks you very much! :) Works great

Just wondering though, do you reckon the above code is "more efficient" than creating another temp Iterator to go through all the items (Similar to what we did for the command node)?

Thanks

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.