Replace third octets of multiple IP addresses

I have two input XML files, this is the first:

<?xml version="1.0" encoding="utf-8"?> <ipaddresses> <ip>192.168.45.12</ip> <ip>192.168.45.33</ip> <ip>192.168.45.54</ip> <ip>192.168.45.95</ip> </ipaddresses> 

and the second:

<ipaddresses>     <ip>192.168.15.12</ip>     <ip>192.168.25.13</ip>     <ip>192.168.35.14</ip>     <ip>192.168.45.15</ip> </ipaddresses> 

The desired output for me is:

<ipaddresses> <ip>192.168.15.12</ip> <ip>192.168.25.33</ip> <ip>192.168.35.54</ip> <ip>192.168.45.95</ip> </ipaddresses> 

In short I want to replace the thirds octets of the first input file with the third octets of the second input file.

The code I have written so far is:

using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Xml.Linq;  namespace IPModifier {     class Program     {         static void Main(string[] args)         {             XDocument ipAddressesToModify = XDocument.Load(args[0]);             XDocument sourceIPs = XDocument.Load(args[1]);             List<XElement> ipAddresses = new List<XElement>();             List<XElement> sourceIPAddresses = new List<XElement>();             List<byte> utilizedOctets = new List<byte>();             List<byte[]> ips = new List<byte[]>();              IEnumerable<XElement> allIPs = from ipAddress in ipAddressesToModify.Root.Elements()                                            select ipAddress;             foreach (XElement ipAddress in allIPs)             {                 ipAddresses.Add(ipAddress);                 Console.WriteLine(ipAddress.Value);             }              IEnumerable<byte> ipThirdOctets = from ipOctet in ipAddresses                                               let byteOctetsThree = IPAddress.Parse(ipOctet.Value).GetAddressBytes()[2]                                               select byteOctetsThree;             foreach (byte octetOfIP in ipThirdOctets)             {                 Console.WriteLine(octetOfIP.ToString());             }              IEnumerable<XElement> allsourceIP = from source in sourceIPs.Root.Elements()                                                 select source;              foreach (XElement sourceIP in allsourceIP)             {                 sourceIPAddresses.Add(sourceIP);                 Console.WriteLine(sourceIP.Value);             }              IEnumerable<byte> sourceOctets = from sourceIP in allsourceIP                                              let octets = IPAddress.Parse(sourceIP.Value).GetAddressBytes()[2]                                              select octets;             foreach (byte octet in sourceOctets)             {                 utilizedOctets.Add(octet);                 Console.WriteLine(octet);             }              foreach (XElement ipAdd in ipAddresses)             {                 byte[] ip = IPAddress.Parse(ipAdd.Value).GetAddressBytes();                 ips.Add(ip);             }               foreach (byte[] ipToModify in ips)             {                 foreach (byte oct in utilizedOctets)                 {                       ipToModify[2] = oct;                     IPAddress newIP = new IPAddress(ipToModify).MapToIPv4();                      Console.WriteLine(newIP.ToString());                 }              }          }     } } 

I have tried using a nested loop to tackle this problem, however I am getting the wrong output with the octet replaced with ’45’ the final octet that is in the second input XML file. The problem is that there is too much iteration happening. If anyone can help it will be much appreciated, I am new to C# coming from mainly Java experience.

Add Comment
3 Answer(s)
XDocument first = XDocument.Load(args[0]); XDocument second = XDocument.Load(args[1]);   var result = new XElement(     "ipaddresses",     first.Root.Elements("ip")         .Zip(second.Root.Elements("ip"),             (f, s) => {                 var first_bytes = IPAddress.Parse(f.Value).GetAddressBytes();                 var second_bytes = IPAddress.Parse(s.Value).GetAddressBytes();                  first_bytes[2] = second_bytes[2];                 return new IPAddress(first_bytes);             }         )         .Select(i => new XElement("ip", i.ToString())) ); 
Answered on July 17, 2020.
Add Comment

I created a class and used Xml Linq :

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Xml; using System.Xml.Linq;  namespace ConsoleApplication1 {     class Program     {         static void Main(string[] args)         {             string xml1 = @"<?xml version=""1.0"" encoding=""utf-8""?>                                 <ipaddresses>                                 <ip>192.168.45.12</ip>                                 <ip>192.168.45.33</ip>                                 <ip>192.168.45.54</ip>                                 <ip>192.168.45.95</ip>                                 </ipaddresses>                                 ";             XDocument doc1 = XDocument.Parse(xml1);             string xml2 = @"<?xml version=""1.0"" encoding=""utf-8""?>                                  <ipaddresses>                                     <ip>192.168.15.12</ip>                                     <ip>192.168.25.13</ip>                                     <ip>192.168.35.14</ip>                                     <ip>192.168.45.15</ip>                                 </ipaddresses>                                 ";             XDocument doc2 = XDocument.Parse(xml2);             IP.Merge(doc1, doc2);         }     }     public class IP     {         public string[] octets { get; set; }         public XElement xIP { get; set; }          public IP(XElement ip)         {             xIP = ip;             octets = ((string)ip).Split(new char[] { '.' }).ToArray();         }          public void ReplaceOctet(int i, string[] octets2)         {             octets[i] = octets2[i];             xIP.SetValue(string.Join(".", octets));         }         public static void Merge(XDocument doc1, XDocument doc2)         {             List<IP> ip1 = doc1.Descendants("ip").Select(x => new IP(x)).ToList();             List<IP> ip2 = doc2.Descendants("ip").Select(x => new IP(x)).ToList();              for (int i = 0; i < ip1.Count(); i++)             {                 ip1[i].ReplaceOctet(2, ip2[i].octets);             }         }     } } 
Add Comment

DataSet can read an XML, infer schema and create a tabular representation that’s easy to manipulate:

        DataSet ip1 = new DataSet();       //a DataSet is a collection of DataTable         ip1.ReadXml(@"c:\temp\ip1.xml");   //this will read the xml file and create a table named "ip" with a column "ip_Text"         DataSet ip2 = new DataSet();          ip2.ReadXml(@"c:\temp\ip2.xml");          var r1 = ip1.Tables[0].Rows;       //could say Tables["ip"] or Tables[0]          var r2 = ip2.Tables[0].Rows;       //because there is only one table in the set                                            //.Rows is a collection of DataRow, a bit like a 2D array          for (int i = 0; i < r1.Count; i++) { //iterate the rows in the collection             var a = r1[i][0].ToString().Split('.');    //2D array, indexed by i (the row) and 0 (the first column)             a[2] = r2[i][0].ToString().Split('.')[2];  //could also say [i]["ip_Text"]             r1[i][0] = string.Join(".", a);            //combine our edited array back to string and update the row         }         ip1.WriteXml(@"c:\temp\ip3.xml");              //write the rows back to xml 

A handy tip, when working with data sets and tables, is to set a breakpoint in the IDE (click to the left of the line number so it gains a red dot) after you’ve loaded the set, then run the program. When it stops, point to the dataset variable and wait for the tooltip. It contains a magnifying glass:

enter image description here

Clicking the magnifying glass brings a window you can use to view the data in a grid:

enter image description here

This can be really useful in terms of knowing what indexes or names columns have etc

Add Comment

Your Answer

By posting your answer, you agree to the privacy policy and terms of service.