-5

I am trying to add my code for already existing code. I have below two xmls:

Out.xml

<School>
  <Classes>
    <Class>
     <Students>
       <Student SequenceNumber="1">
        <ID>123</ID>
        <Name>AAA</Name>
     </Student>
    </Students>
  </Class>
</Classes>  
</School>

In.xml

<School>
 <Classes>
  <Class>
   <Students>
     <Student SequenceNumber="1">
      <ID>456</ID>
      <Name>BBB</Name>
    </Student>
    <Student SequenceNumber="2">
      <ID>123</ID>
      <Name>AAA</Name>
    </Student>
    <Student SequenceNumber="3">
      <ID>789</ID>
      <Name>CCC</Name>
    </Student>
    </Students>
    </Class>
   </Classes>  
  </School>

Now I need to check Out.xml and In.xml and my final Out.xml must be like below. The rule here is check StudentID in Out and In xmls. If Out xml doesnot have it and In xml has it add it to Out.xml at end of already existing elements.

Out.xml

<School>
<Classes>
<Class>
  <Students>
    <Student SequenceNumber="1">
      <ID>123</ID>
      <Name>AAA</Name>
    </Student>
    <Student SequenceNumber="2">
      <ID>456</ID>
      <Name>BBB</Name>
    </Student>       
    <Student SequenceNumber="3">
      <ID>789</ID>
      <Name>CCC</Name>
    </Student>
  </Students>
  </Class>
 </Classes>  
</School>

Already existing code is as below

string inFileName = @"C:\In.xml";
string inXml = System.IO.File.ReadAllText(inFileName);
var xmlReaderSource = XmlReader.Create(new StringReader(inXml));
var mgr = new XmlNamespaceManager(xmlReaderSource.NameTable); 
mgr.AddNamespace("m", "http://www.mismo.org/residential/2009/schemas");
XDocument sourceXmlDoc = XDocument.Load(xmlReaderSource);

string outFileName = @"C:\Out.xml";
string outXml = System.IO.File.ReadAllText(outFileName);
XmlDocument targetXmlDoc = new XmlDocument();           
targetXmlDoc.LoadXml(outXml);

I cannot change above code now I need add my logic.

I added like below

string xpath = @"/m:School/m:Classes/m:Class/m:Students";

XmlNodeList outStudentNodes = targetXmlDoc.SelectNodes(xpath + "/m:Student", namespaceManager);

if(outStudentNodes== null || outStudentNodes.Count <= 0)
 { 
    return;
 }

XElement root = sourceXmlDoc.Root;
IEnumerable<XElement> inStudentsColl = from item in root.Elements("Classes").Descendants("Class")
                                             .Descendants("Students").Descendants("Student")
                             select item;

Now I have XmlNodeList and IEnumerble, trying to see whether I can use LINQ statement and make code simple for my comparison.

Node: I am not asking how to add nodes/elements using C#. I am looking for how to compare two xmls and then add nodes/elements into the one which is missing those nodes/elements. My issue here is one xml is read like XDocument and other using XmlDocument.

UPDATE

Thank you very much @TheAnatheme. I really appreciate it.

I followed what TheAnatheme suggested me and it worked. I marked TheAnatheme's answer as real solution. Please see below what I did in foreach block so that if anyone wants to use they can refer to this post.

string xpath = @"/m:School/m:Classes/m:Class/m:Students
XmlNode studentsNode = targetXmlDoc.SelectSingleNode(xpath, namespaceManager);  

foreach (var element in elementsToAdd)
{
   //Add Microsoft.CSharp.dll (if needed ) to your project for below statement to work
   dynamic studentElement = element as dynamic;
   if (studentElement != null)
    {
         XmlElement studentXmlElement = targetXmlDoc.CreateElement("Student");                               

          XmlElement studentIDXmlElement = targetXmlDoc.CreateElement("ID");

          studentIDXmlElement.InnerText = studentElement.ID;

          XmlElement studentNameXmlElement = targetXmlDoc.CreateElement("Name");
          studentNameXmlElement .InnerText = studentElement.Name;

          studentXmlElement.AppendChild(studentIDXmlElement);
          studentXmlElement.AppendChild(studentNameXmlElement);

          studentsNode.AppendChild(childElement);

    }
}
Ziggler
  • 3,361
  • 3
  • 43
  • 61
  • It's not hard to google this: http://csharp.net-tutorials.com/xml/writing-xml-with-the-xmldocument-class/ – ManoDestra Mar 04 '16 at 22:06
  • I don't see any code related with your question..... Just codes loding an xml file.... Have you tried anything? – Eser Mar 04 '16 at 22:07
  • @Mano... the problem is not adding nodes and elements... I know how to do.. I want to know how we can find what elements/nodes are missing from Out.xml that are present in In.xml. I am trying to see we can do without too many for and foreach loops... – Ziggler Mar 04 '16 at 22:08
  • @Eser.. I tried.. I am able to get nodes students from Out.xml into XmlNodeList and from In.xml into IEnumerable. – Ziggler Mar 04 '16 at 22:09
  • You'll have to recursively loop down through the nodes and check the child nodes at each recursion against the required output XmlDocument, I guess. Weird requirement; if you've already got an XmlDocument based on the out.xml, you don't need to do anything with the other one. – ManoDestra Mar 04 '16 at 22:12
  • @Ziggler And where is your code? So that we can try to fix it... – Eser Mar 04 '16 at 22:12
  • You should really show what you've tried already and why it isn't working. This isn't really a site for others to do your homework for you. – ManoDestra Mar 04 '16 at 22:13
  • 1
    Why are you reading them differently (XDocument vs XmlDocument)? – Frozenthia Mar 04 '16 at 22:18
  • @TheAnathema,,,, it is already written by someone and it is in production. – Ziggler Mar 04 '16 at 22:21
  • If you know how to use each of the documents objects, adding elements, attributes, etc, that's fine. Show us the code that you've tried already to do the job and why it is failing and we can then perhaps show you how to improve it? I'll try to be as helpful as I can, if you can do that. – ManoDestra Mar 04 '16 at 22:21
  • 1
    @Mano.. I added the code. From Out.xml I am able to read into XmlNodeList and from In.xml I am able to read into IEnumerable. Now I want to know instead of foreach/for loops can we use LINQ statements to do comparison and get list of elements that are in In.xml but not in Out.xml and so that I can add them back to Out.xml. – Ziggler Mar 04 '16 at 22:23
  • I'll need to look at this later, I'm afraid, but this may be of interest in the meantime: http://stackoverflow.com/questions/875625/is-there-an-easy-way-to-compare-if-2-xdocuments-are-equal-ignoring-element-attri. – ManoDestra Mar 04 '16 at 22:31
  • @Mano.. thanks.. I will also keep looking out... – Ziggler Mar 04 '16 at 22:35
  • 1
    I'm writing some code right now, will post in answer shortly. – Frozenthia Mar 04 '16 at 22:35
  • @Ziggler, I provided you some good code by which you can work on. – Frozenthia Mar 04 '16 at 23:12
  • @TheAnathema .. I am trying this.. will post you my findings.. – Ziggler Mar 04 '16 at 23:18

1 Answers1

1

This projects both sets into an anonymous object List, makes comparisons, and gives you a set of anonymous objects that don't yet exist by which you can add to the out XML.

public static List<object> GetInStudents(XDocument sourceXmlDoc)
{
    IEnumerable<XElement> inStudentsElements = 
    sourceXmlDoc.Root.Elements("Classes").Descendants("Class")
                     .Descendants("Students").Descendants("Student");

    return inStudentsElements.Select(i => 
        new { Id = i.Elements().First().Value, 
            Name = i.Elements().Last().Value }).Cast<object>().ToList();
}

public static List<object> GetOutStudents(XmlDocument targetXmlDoc)
{
    XmlNodeList outStudentsElements = targetXmlDoc.GetElementsByTagName("Students")[0].ChildNodes;

    var outStudentsList = new List<object>();

    for (int i = 0; i < outStudentsElements.Count; i++)
    {
        outStudentsList.Add(new { Id = outStudentsElements[i].ChildNodes[0].InnerText, 
                                  Name = outStudentsElements[i].ChildNodes[1].InnerText });
    }

    return outStudentsList;
}

And you compare them as such:

var inStudents = GetInStudents(sourceXmlDoc);
var outStudents = GetOutStudents(targetXmlDoc);

if (inStudents.SequenceEqual(outStudents))
{
    return;
}
else
{
    var elementsToAdd = inStudents.Except(outStudents);

    foreach (var element in elementsToAdd)
    {
        // create xmlNode with element properties, add element to xml
    }
}
MeanGreen
  • 3,098
  • 5
  • 37
  • 63
Frozenthia
  • 759
  • 3
  • 9
  • @TheAnatheme.. can you please let me know how can I read data inside element inside foreach loop... till there it is exactly what I want...I need to get data in element.. create nodes and add to XmlDocument... – Ziggler Mar 06 '16 at 21:51
  • @Ziggler Just type element.Id or element.Name. When adding it to the XmlDocument you'll have to get the last SequenceNumber, add one to it, and then increment as you're adding. This is outside your original question and Stack Overflow isn't a website for doing your homework. You'll have to do the rest. – Frozenthia Mar 06 '16 at 22:55
  • 1
    @TheAnatheme.. I got it...I am doing like this...dynamic newStudentElement = element as dynamic; string newStudentId = newStudentElement .ID; string newStudentName = newStudentElement .Name; .. I will post my complete solution once my task is done... Thank you very much.. Your answer really pointed me in right direction... I am marking this as answer... – Ziggler Mar 06 '16 at 23:02