I have this xml file

<?xml version="1.0"?>
<xml> 
    <accounts> 
        <user name="User123" cellphone="000000000123" email="n/a" balance="123.12" pin="123" accNumber="123"/>
        <user name="User456" cellphone="000000000456" email="445@email.com" balance="456.45" pin="456" accNumber="456"/> 
    </accounts> 
</xml

This file is part of an ATM's database, containing the user's details. I would like to change a spesific value.
Say "User123" is login at the atm and deposit money, it must only get the balance of "User123" and change it.

So far i got this code but it isnt working:

    class ATMMachine
    {
        private const String DATAFILE = "AtmDatabase.xml";
        private const int minNum = 2;


        private String accNumber;
        private String Pin;
        private String amount;
        private String xmlAccNumber;
        private String xmlPin;
        private String xmlBalance;
        private String xmlName;         // get name from xml file
        private Boolean IsMember;
        private int newBalance;         // xmlbalance - minNum - amount
        private String stringNewBalance;
        private int choice;


        static void Main(string[] args)
        {
            ATMMachine atm = new ATMMachine();
            atm.StartAtm();
        }

        public void StartAtm()
        {
            Console.Clear();    // So that the next user cant se prev users data
            Console.WriteLine("*** -Welcome to the EEI ATM- ***");
            Console.WriteLine("** -Please login below- **");

            Console.WriteLine("\nAccount number: ");
            accNumber = Console.ReadLine();
            Console.WriteLine("PIN: ");
            Pin = Console.ReadLine();

            IsHeMember();

            if (IsMember == true)
            {
                Console.WriteLine("* -Welcome {0}- *", xmlName);
                Console.WriteLine("* -Please choose an option below- *");
                while (true)
                {
                    Console.WriteLine("\n1 - Check balance.");
                    Console.WriteLine("2 - Deposit.");
                    Console.WriteLine("3 - Withdraw.");
                    Console.WriteLine("4 - Logout.");
                    Console.Write("\nChoice: ");

                    choice = int.Parse(Console.ReadLine());

                    switch (choice)
                    {
                        case 1:
                            GetBalance();
                            break;
                        case 2:
                            AddBalance();
                            break;
                        case 3:
                            WithDraw();
                            break;
                        case 4:
                            break;
                        default:
                            Console.WriteLine("Error! Invalid input.");
                            break;
                    }
                }
            }
            else if(IsMember == false)
            {
                Console.WriteLine("Error! Wrong account number / PIN combination.");
            }
        }
        // -end

        public Boolean IsHeMember()
        {
            XmlReader reader = XmlReader.Create(DATAFILE);

            while (reader.Read())
            {
                if (reader.Name == "user")
                {
                    xmlName = reader["name"];
                    xmlAccNumber = reader["accNumber"];
                    xmlPin = reader["pin"];

                    if ((xmlAccNumber == accNumber) && (xmlPin == Pin))
                    {
                        IsMember = true;
                        break;
                    }
                }
            }
            reader.Close();
            return IsMember;
        }
        // -end

        public void GetBalance()
        {
            XmlReader reader = XmlReader.Create(DATAFILE);

            while (reader.Read())
            {
                if (reader.Name == "user")
                {
                    xmlAccNumber = reader["accNumber"];
                    xmlPin = reader["pin"];

                    if ((xmlAccNumber == accNumber) && (xmlPin == Pin))
                    {
                        xmlBalance = reader["balance"];
                        Console.WriteLine(xmlBalance);
                        break;
                    }
                }
            }
        }
        // -end

        public void AddBalance()
        {
            Console.Write("Enter the amount you would like to deposit: ");
            amount = Console.ReadLine();

            newBalance = int.Parse(xmlBalance) + int.Parse(amount);
            stringNewBalance = newBalance.ToString();

            XDocument xDoc = XDocument.Load(DATAFILE);
            xDoc.Root.Element("accounts").Attribute("balance").Value = stringNewBalance;
            xDoc.Save(DATAFILE);
        }
        // -end

        public void WithDraw()
        {
            Console.Write("Enter the amount you would like to withdraw: ");
            amount = Console.ReadLine();

            newBalance = (int.Parse(xmlBalance) - minNum) - int.Parse(amount);

            if (newBalance >= 0)
            {
                XDocument xDoc = XDocument.Load(DATAFILE);
                xDoc.Root.Element("accounts").Attribute("balance").Value = stringNewBalance;
                xDoc.Save(DATAFILE);
            }
            else
            {
                Console.WriteLine("Error! You do not have enough funds in your account.");
            }
        }
        // -end
    }

It gives a compiler error when i try to run it.
The errror is:

An unhandled exception of type 'System.ArgumentNullException' occurred in mscorlib.dll

Additional information: Value cannot be null.

Another problem that i am facing is that "User456" also has an attribute called balance. But I only want to change the value of the user that is currently logedin

What is wrong and how do i fix it?

Here's one way to change a specific value in an .xml document. Load the file into an XDocument variable, then find the appropriate element with a foreach loop and make an XElement variable equal that element. When you change an attribute in the XElement it is reflected in the XDocument. All that's left is to save the XDocument. I modified your code to do this, also added a few tweaks. Hope you find this useful:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.IO;
using System.Xml.XPath;

namespace ConsoleApplication1
{
    class ATMMachine
    {
        private const String DATAFILE = "AtmDatabase.xml";
        private const int minNum = 2;
        private String accNumber;
        private String Pin;
        private String amount;
        private String xmlAccNumber;
        private String xmlPin;
        private String xmlBalance;
        private String xmlName; // get name from xml file
        XDocument Doc = XDocument.Load(DATAFILE);
        XElement CurrentAccount;
        static void Main(string[] args)
        {
            ATMMachine atm = new ATMMachine();
            atm.StartAtm();
        }
        public void StartAtm()
        {
            Console.Clear(); // So that the next user cant see prev users data
            Console.WriteLine("*** -Welcome to the EEI ATM- ***");
            Console.WriteLine("** -Please login below- **");
            Console.WriteLine("\nAccount number: ");
            accNumber = Console.ReadLine();
            Console.WriteLine("PIN: ");
            while (true)
            {
                ConsoleKeyInfo input = Console.ReadKey(true);
                if (input.Key != ConsoleKey.Enter && char.IsDigit(input.KeyChar))
                {
                    Pin += input.KeyChar;
                    Console.Write("*");
                }
                else if(input.Key == ConsoleKey.Enter)
                {
                    Console.WriteLine();
                    break;
                }
            }
            if (IsHeMember())
            {
                Console.WriteLine("* -Welcome {0}- *", xmlName);
                Console.WriteLine("* -Please choose an option below- *");
                while (true)
                {
                    Console.WriteLine("\n1 - Check balance.");
                    Console.WriteLine("2 - Deposit.");
                    Console.WriteLine("3 - Withdraw.");
                    Console.WriteLine("0 - Logout.");
                    Console.Write("\nChoice: ");
                    char choice = Console.ReadKey().KeyChar;
                    Console.Clear();
                    switch (choice)
                    {
                        case '1':
                            GetBalance();
                            break;
                        case '2':
                            AddBalance();
                            break;
                        case '3':
                            WithDraw();
                            break;
                        case '0':
                            return;
                        default:
                            Console.WriteLine("Error! Invalid input.");
                            break;
                    }
                }
            }
            else
            {
                Console.WriteLine("Error! Wrong account number / PIN combination.");
            }
        }
        // -end
        public Boolean IsHeMember()
        {
            foreach (XElement xe in Doc.Root.Element("accounts").Elements("user"))
            {
                if (xe.Attribute("accNumber").Value == accNumber)
                {
                    xmlPin = xe.Element("data").Attribute("pin").Value;
                    if (xmlPin == Pin)
                    {
                        CurrentAccount = xe;
                        xmlAccNumber = CurrentAccount.Attribute("accNumber").Value;
                        xmlBalance = CurrentAccount.Element("data").Attribute("balance").Value;
                        xmlName = CurrentAccount.Element("data").Attribute("name").Value;
                        return true;
                    }
                }
            }
            return false;
        }
        // -end
        public void GetBalance()
        {
            Console.WriteLine("Your Balance is: " + xmlBalance);
        }
        // -end
        public void AddBalance()
        {

            amount = ChangeBalance("Enter the amount you would like to deposit: ");
            xmlBalance = (double.Parse(xmlBalance) + double.Parse(amount)).ToString();
            CurrentAccount.Element("data").Attribute("balance").Value = xmlBalance;
            GetBalance();
            SaveBalance();
        }
        // -end
        public void WithDraw()
        {
            double newBalance; // xmlbalance - minNum - amount
            amount = ChangeBalance("Enter the amount you would like to withdraw: ");
            newBalance = (double.Parse(xmlBalance) - minNum) - double.Parse(amount);
            if (newBalance >= 0)
            {
                xmlBalance = newBalance.ToString();
                CurrentAccount.Element("data").Attribute("balance").Value = xmlBalance;
                SaveBalance();
            }
            else
            {
                Console.WriteLine("Error! You do not have enough funds in your account.");
            }
            GetBalance();
        }
        public string ChangeBalance(string message)
        {
            double input = 0;
            Console.WriteLine(message);
            while (!double.TryParse(Console.ReadLine(), out input))
            {
                Console.WriteLine("Please try again only numbers please");
            }
            return input.ToString();
        }       
        void SaveBalance()
        {
            Doc.Save(DATAFILE);
        }
        // -end
    }
}

One of the things I added was to echo *'s to the screen when typing in the pin. Also I made your main menu single key entry and added some validations for your inputs.

Since your amounts can include decimal numbers I changed any amounts to do with the balance to doubles. You had them as int.
Also the logut option in your main menu has a break; statement. This will only exit it out of the switch block not the while loop.

Edited 3 Years Ago by tinstaafl

oops almost forgot I changed the structure of the xml data a little bit. The code is quite easy to adapt to your original structure. Simply remove every occurence of '.Element("data")'. Here's the file I used.

<?xml version="1.0" encoding="utf-8"?>
<xml>
  <accounts>
    <user accNumber="123">
      <data name="User123" cellphone="000000000123" email="n/a" balance="471.12" pin="123" />
    </user>
    <user accNumber="456">
      <data name="User456" cellphone="000000000456" email="445@email.com" balance="854.45" pin="456" />
    </user>
  </accounts>
</xml>

Edited 3 Years Ago by tinstaafl

This question has already been answered. Start a new discussion instead.