1

I have to create an xml document and do following item by LINQ to XML concepts.

  1. add new asset,
  2. edit asset,
  3. remove asset.

I was creating a xml document by the notepad and save that file by "asset.xml" then I copy that file into debug folder

my xml document format is

<?xml version="1.0" encoding="utf-8"?>
<Assets>
  <assetId>1
       <assetName>lenova</assetName>
       <model>12kj320</model>
       <price>22000</price>
       <quantity>12</quantity>
   </assetId>
</Assets>

my code is

class program
{

public static void AddSingleAsset()
{
    static List<Asset> Assets = new List<Asset>();

    int assetId;
    string assetName;
    string model;
    double price;
    int quantity;
    assetId = Assets.Count + 1;
    Console.WriteLine("Asset id :{0}", assetId);
    Console.WriteLine("Enter the asset name");
    assetName = Console.ReadLine();
    Console.WriteLine("Enter the asset model");
    model = Console.ReadLine();
    Console.WriteLine("Enter the price of asset");
    price = int.Parse(Console.ReadLine());
    Console.WriteLine("Enter the quantity of asset");
    quantity = int.Parse(Console.ReadLine());
    Assets.Add(new Asset() { assetId = assetId, assetName = assetName, modelNo = model, price = price, quantity = quantity });
    string path = "linqtoxml1.xml";
    XDocument doc = XDocument.Load(path);
    doc.Elements("Assets").First().AddFirst(new XElement("assetId", assetId, new XElement("assetName", assetName), new XElement("model", model), new XElement("price", price), new XElement("quantity", quantity)));
    doc.Save(path);

}
public static void EditAssetInformation()
{
    Console.WriteLine("select the option to edit");
    Console.WriteLine("1.To change Asset Name\n2.To change Model NO\n3.To change price\n4.To change Quantity");
    int option = int.Parse(Console.ReadLine());
    switch (option)
    {
        case 1:
            string newname;
            Console.WriteLine("Enter the ID number to change the information");
            int id = int.Parse(Console.ReadLine());
            Console.WriteLine("Enter the Asset new name");
            newname = Console.ReadLine();
            ModifyName(newname, id);    
            break;

        case 2:
            string newModelNo;
            Console.WriteLine("Enter the ID number to change the information");
            int id1 = int.Parse(Console.ReadLine());
            Console.WriteLine("Enter the Asset new model No");
            newModelNo = Console.ReadLine();
            ModifyModelNo(newModelNo, id1);
            break;

        case 3:
            double newPrice;
            Console.WriteLine("Enter the ID number to change the information");
            int id2 = int.Parse(Console.ReadLine());
            Console.WriteLine("Enter the Asset new price");
            newPrice = int.Parse(Console.ReadLine());
            ModifyPrice(newPrice, id2);
            break;

        case 4:
            int newQuantity;
            Console.WriteLine("Enter the ID number to change the information");
            int id3 = int.Parse(Console.ReadLine());
            Console.WriteLine("Enter the Asset new price");
            newQuantity = int.Parse(Console.ReadLine());
            Modifyquantity(newQuantity, id3);
            break;

        }
    }
    static void ModifyName(string newname, int id)
    {
        var doc = XElement.Load(path);
        var namechange = doc.Element("Assets").Elements("assetId").Where(c => c.Element("assetId").Value == Convert.ToString(id)).Single();
        namechange.Element("assetName").Value = newname;
        doc.Save(path);
    }
    static void ModifyModelNo(string newModelNo, int id1)
    {
        string path = "linqtoxml1.xml";
        XDocument doc = XDocument.Load(path);
        XElement modelchange = doc.Descendants("AssetId").Where(c => c.Attribute("AssetId").Value.Equals(id1.ToString())).FirstOrDefault();
        modelchange.Element("model").Value = newModelNo;
        doc.Save(path);
    }
    static void ModifyPrice(double newPrice, int id2)
    {
        string path = "linqtoxml1.xml";
        XDocument doc = XDocument.Load(path);
        XElement pricechange = doc.Descendants("AssetId").Where(c => c.Attribute("AssetId").Value.Equals(id2.ToString())).FirstOrDefault();
        pricechange.Element("price").Value = newPrice.ToString();
        doc.Save(path);
    }
    static void Modifyquantity(int newQuantity, int id3)
    {
        string path = "linqtoxml1.xml";
        XDocument doc = XDocument.Load(path);
        XElement quantitychange = doc.Descendants("AssetId").Where(c => c.Attribute("AssetId").Value.Equals(id3.ToString())).FirstOrDefault();
        quantitychange.Element("quantity").Value = newQuantity.ToString();
        doc.Save(path);
    }
    public static void DeleteAssetInformation()
    {
        string path = "linqtoxml1.xml";
        Console.WriteLine("Enter the ID to delete information");
        int id = int.Parse(Console.ReadLine());
        XDocument doc = XDocument.Load(path);
        XElement cStudent = doc.Descendants("AssetId").Where(c => c.Attribute("ID").Value.Equals(id.ToString())).FirstOrDefault();
        cStudent.Remove();
        doc.Save(path);
    }
}
public class Asset
{
    public int assetId
    { get; set; }
    public string assetName
    { get; set; }
    public string modelNo
    { get; set; }
    public double price
    { get; set; }
    public int quantity
    { get; set; }
}

my problem is

I need to auto generate the asset id. my code is works when I add an element continuously when I close this console and run again then the asset id will start again from 1.

also when I try to EDIT OR DELETE the previous record means that will show the error:

SYSTEM.NULL REFERENCE EXCEPTION

can any one please explain me what I did wrong in this program and also suggest me easy way to rectify this problem. Basically I am from non IT field, I am an ELECTRICAL ENGINEER so explain me in little depth.

  • From : Where(c => c.Attribute("ID").Value.Equals(id.ToString()) To : Where(c => (int)c == id) – jdweng Oct 03 '16 at 07:32
  • You'd be much better off using `XmlSerializer` for this. Make the changes to the `Asset` list / objects and serialise when you're done. Your LINQ to XML code is a muddle of typos (XML is *case sensitive*) and confuses elements and attributes. – Charles Mager Oct 03 '16 at 07:36

1 Answers1

0

Well, I see there is couple things going on with your code

XML File

Your xml looks like this

<?xml version="1.0" encoding="utf-8"?>
<Assets>
  <assetId>1
       <assetName>lenova</assetName>
       <model>12kj320</model>
       <price>22000</price>
       <quantity>12</quantity>
   </assetId>
</Assets>

The node is invalid - you should end this node right after the value. The <assetId> node is valid, but it would be better, to change this structure a little bit. If you have node called <Assets> it would be good idea, to encapsulate every asset in his own node, called <asset>

<?xml version="1.0" encoding="utf-8"?>
<Assets>
   <asset>
      <assetId>1</assetId>
      <assetName>lenova</assetName>
      <model>12kj320</model>
      <price>22000</price>
      <quantity>12</quantity>
   </asset>
</Assets>

After this changes you will be able to find all your assets with simple

var assets = root.Elements("asset");

If you would like to add new asset and get the correct new id value, you could do something like this

var assets = root.Elements("asset").OrderByDescending(asset => asset.Element("assetId").Value);

Right now, asset with highest id value is at the top, so, to calculate new id, you should do something like

var newestAsset = root.Elements("asset").OrderByDescending(asset => asset.Element("assetId").Value).FirstOrDefault();
int newId = int.Parse(newestAsset.Element("assetId").Value) + 1;

So adding new asset would look like this

XElement root = XElement.Load(path);
XElement newAsset = new XElement("asset", new XElement("assetId", newId)/*, other asset properties */);
root.Add(newAsset);
root.Save(path);

Null reference exception

This exception means, that you are trying to use some variable, but this variable is null, so it doesn't have any value. From the first look at your code I can see, that in some places you are trying to load xml element, using path variable, but it's not initialized. For example in ModifyName method.

Other possibility is, that there is something wrong with this line

var namechange = doc.Element("Assets").Elements("assetId").Where(c => c.Element("assetId").Value == Convert.ToString(1)).Single();

and with this one

XElement modelchange = doc.Descendants("AssetId").Where(c => c.Attribute("AssetId").Value.Equals(1.ToString())).FirstOrDefault();

I guess, that somewhere in both of this lines something is null, but you are trying to work on this element either way. In cases like this, you should really use debugger and see, where this exception is coming from. With this information you will know, which lines you should change in order to make this program work.

If you would like to find asset with id provided by user from the console window, code should look like this

var asset = root.Elements("asset").Where(asset => asset.Element("assetId").Value == id.ToString()); 

First, change your xml structure to the one I suggested, than rewrite these lines I pointed you out using snippets from this answer and you should be good to go!

Paweł Hemperek
  • 1,130
  • 10
  • 21
  • 'The node is invalid' - this isn't true. It might not be the ideal representation (your suggestion is better), but it's perfectly valid XML. – Charles Mager Oct 03 '16 at 08:03
  • In this case I will edit my answer - thank you for poiting that out! **Edit:** actually I don't know what I was thinking, because HTML like `Something very important` is indeed a perfectly valid syntax... – Paweł Hemperek Oct 03 '16 at 08:33
  • @Arunkumar if my answer is helpful to you, please go ahead and accept it – Paweł Hemperek Oct 03 '16 at 12:26
  • @PawełHemperek I have another doubt? I want to print that value without xml format how can I do this? –  Oct 04 '16 at 06:27
  • I'm sorry - what do you mean by "I want to print that value without xml format"? What value are you talking about? You don't want to save data to xml file or are you displaying this in console and it's xml formatted? – Paweł Hemperek Oct 04 '16 at 06:47
  • NO I want to save this xml file also but I need to display the value which is stored in the xml file for example, Asset ID-1 Asset Name- Lenovo and so on.. I tried like below XDocument xmlDocument = XDocument.Load(path); Console.WriteLine(xmlDocument); But it was print all the full xml document not a single element value –  Oct 04 '16 at 11:45
  • Simplest way of displaying content of XML file in your case would be deserializing it, so you can operate on `IEnumerable` rather than on `XElement`s. Please see [this answer](http://stackoverflow.com/a/18608384/5501613) on how to deserialize XElement to specific type – Paweł Hemperek Oct 04 '16 at 12:40