-1

I have a requirement to update xml file by reading another xml file.

eg:

Source.xml

<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="package1" version="1.0.26.0"/>
  <package id="package3" version="1.0.12.0"/>
  <package id="package4" version="1.0.40.0"/>
  <package id="package12" version="1.0.38.0"/>
  <package id="package6" version="1.0.8.0"/>
</packages>

Target.xml

<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="package1" version="1.0.2.0"/>
  <package id="package2" version="1.0.1.0"/>
  <package id="package3" version="1.0.4.0"/>
  <package id="package4" version="1.0.3.0"/>
</packages>

In the above example, "package1" exists in both the files. So the version of "package1" in Target.xml has to get update with the value in Source.xml.

I tried the below code, but encountered exception during execution(no error during compilation):

Unhandled Exception: System.NullReferenceException: Object reference not set to an instance of an object.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;

namespace XMLUpdate
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("In Execute..");
            string SourceFile = args[0];
            string TargetFile = args[1];
            string SourcePackageId = null;
            string SourcePackageVersion = null;
            XmlDocument SourceXmlDoc = new XmlDocument();
            XmlDocument TargetXmlDoc = new XmlDocument();
            SourceXmlDoc.Load(SourceFile);
            TargetXmlDoc.Load(TargetFile);
            XmlElement SourceRootElement = SourceXmlDoc.DocumentElement;
            //XmlElement SourceElement = SourceRootElement["packages"];
            XmlNodeList SourcexnList = SourceXmlDoc.SelectNodes("/packages");
            foreach (XmlNode Sourcexn in SourcexnList)
            {
                Console.WriteLine("In source loop..");
                SourcePackageId = Sourcexn["id"].InnerText;
                SourcePackageVersion = Sourcexn["version"].InnerText;
                Console.WriteLine("In source loop SourcePackageId.." + SourcePackageId);
                XmlElement TargetRootElement = TargetXmlDoc.DocumentElement;
                XmlNodeList TargetxnList = TargetXmlDoc.SelectNodes("/packages");
                foreach (XmlNode Targetxn in TargetxnList)
                {
                    Console.WriteLine("In Target loop..");
                    string TargetPackageId = Targetxn["id"].InnerText;
                    //string TargetPackageVersion = Targetxn["version"].InnerText;

                    if (SourcePackageId.Equals(TargetPackageId))
                    {
                        Targetxn["version"].InnerText = SourcePackageVersion;
                    }
                }
            }
        }
    }
}

Any help?

Thanks

AnilKumar
  • 121
  • 1
  • 3
  • 7
  • Do you have any more details for `Unhandled Exception: System.NullReferenceException: Object reference not set to an instance of an object.`? – Hauns TM Oct 07 '14 at 09:13
  • 1
    You certainly have tried debugging this code yourself before posting it here, right? So which line gives the exception? – JoriO Oct 07 '14 at 09:14
  • Below is the only error i am getting: Unhandled Exception: System.NullReferenceException: Object reference not set to an instance of an ob ject. at XMLUpdate.Program.Main(String[] args) in c:\D-Drive\Tasks\CIChanges\Aumentum\Temp\XMLUpdate\XM LUpdate\XMLUpdate\Program.cs:line 29 – AnilKumar Oct 07 '14 at 09:15
  • possible duplicate of [What is a NullReferenceException and how do I fix it?](http://stackoverflow.com/questions/4660142/what-is-a-nullreferenceexception-and-how-do-i-fix-it) – Matthew Haugen Oct 07 '14 at 09:16
  • You should use the [Attributes collection](http://msdn.microsoft.com/en-us/library/system.xml.xmlnode.attributes(v=vs.110).aspx) of the XmlNode to retrieve the attributes. The item indexing is looking for child elements and you dont have any so they are null when you are trying to get InnerText. – pln Oct 07 '14 at 09:17
  • And now lets count lines...why not write in question which line is source of problem? – Renatas M. Oct 07 '14 at 09:17
  • I am getting the error in line 29 and the code is SourcePackageId = Sourcexn["id"].InnerText; During debug the value of SourcePackageId is null. – AnilKumar Oct 07 '14 at 09:20
  • 1
    I think the answer to my last question is something like "No, of course I haven't debugged anything. Let other people do it, that's what they are here for." – JoriO Oct 07 '14 at 09:20
  • JoriO, I have already answered to your question. You no need to debug the code. I just need guidance. – AnilKumar Oct 07 '14 at 09:23
  • I would suggest not to do the updates on the xml, but read both into objects, update the target fro the source there and re-generate the xml from the updated object (by XMLSerializers). – fast Oct 07 '14 at 09:24
  • SourcePackageId = Sourcexn["id"].InnerText is null because there is no node value and/or child node values, it is a node that just has attributes but no InnerText (meaning the InnerText is null), if I'm not mistaken. – Paul Weiland Oct 07 '14 at 09:35

2 Answers2

1

Try the following:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;

namespace XMLUpdate
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("In Execute..");
            string SourceFile = args[0];
            string TargetFile = args[1];
            string SourcePackageId = null;
            string SourcePackageVersion = null;
            XmlDocument SourceXmlDoc = new XmlDocument();
            XmlDocument TargetXmlDoc = new XmlDocument();
            SourceXmlDoc.Load(SourceFile);
            TargetXmlDoc.Load(TargetFile);
            XmlElement SourceRootElement = SourceXmlDoc.DocumentElement;
            //XmlElement SourceElement = SourceRootElement["packages"];
            XmlNodeList SourcexnList = SourceXmlDoc.SelectNodes("/packages");
            foreach (XmlNode Sourcexn in SourcexnList)
            {
                Console.WriteLine("In source loop..");
                foreach(XmlNode childS in Sourcexn.ChildNodes)
                {
                    SourcePackageId = childS.Attributes["id"].InnerText;
                    SourcePackageVersion = childS.Attributes["version"].InnerText;
                    Console.WriteLine("In source loop SourcePackageId.." + SourcePackageId);
                    XmlElement TargetRootElement = TargetXmlDoc.DocumentElement;
                    XmlNodeList TargetxnList = TargetXmlDoc.SelectNodes("/packages");
                    foreach (XmlNode Targetxn in TargetxnList)
                    {
                        Console.WriteLine("In Target loop..");
                        foreach (XmlNode childT in Targetxn.ChildNodes)
                        {
                            string TargetPackageId = childT.Attributes["id"].InnerText;
                            if (SourcePackageId.Equals(TargetPackageId))
                            {
                                childT.Attributes["version"].InnerText = SourcePackageVersion;
                            }
                        }
                    }
                }
            }
        }


    }
}

You need to check inside the ChildNodes of the xmlNode.

blfuentes
  • 2,731
  • 5
  • 44
  • 72
  • You were pointed to the attributes collection in comments but you wanted someone to write the code for you? – pln Oct 07 '14 at 10:26
1

This should work, just include System.Xml.Linq and System.Linq.

var source = XDocument.Load("Source.xml");
var sPackages = source.Descendants("package");

var target = XDocument.Load("Target.xml");
var tPackages = target.Descendants("package");

foreach (var sPackage in sPackages)
{
    var tPackage = tPackages.FirstOrDefault(x => x.Attribute("id").Value == sPackage.Attribute("id").Value);

    if (tPackage != null && tPackage.Attribute("version").Value != sPackage.Attribute("version").Value)
    {
        target.Descendants("package").Single(x => x.Attribute("id").Value == sPackage.Attribute("id").Value)
                                     .SetAttributeValue("version", sPackage.Attribute("version").Value);
    }
}

target.Save("Target.xml");

This will update every target file's package version number that is also in the source file. You can easily add more functionality based on the above code. As you see, Linq to XML is very clean and easy.

B.K.
  • 9,982
  • 10
  • 73
  • 105