Compare two xml with C# - c#

I have created two XML files namely XML1 and XML2 Which contain Some Employee ID in this case it is Test1,2,3 apparently
Where I compare both the XML file and find the difference between them
XML1:
<?xml version="1.0"?>
<Employees>
<Employee ID="Test1" />
<Employee ID="Test2" />
<Employee ID="Test3" />
<Employees>
XML2:
<?xml version="1.0"?>
<Employees>
<Employee ID="Testing1" />
<Employee ID="Testing2" />
<Employee ID="Test3" />
<Employees>
C#:
public string CompareXML(XmlTextReader xmlDocument1, XmlTextReader xmlDocument2)
{
var diff = new XmlDiff
{
IgnoreComments = true,
IgnorePI = true,
IgnoreWhitespace = true,
IgnoreChildOrder = true,
Algorithm = XmlDiffAlgorithm.Precise,
};
var wString = new StringWriter();
var xmltw = new XmlTextWriter(wString);
xmltw.Formatting = Formatting.Indented;
var status = diff.Compare(xmlDocument1, xmlDocument2, xmltw);
difference = wString.ToString();
xmltw.Close();
return difference;
}
Basically, I'm comparing two xml files and finding the difference(using Microsoft.XmlDiffPatch), and getting the desired output. But,
What I get
<?xml version="1.0" encoding="utf-16"?>
<xd:xmldiff version="1.0" srcDocHash="11148343190120608020" options="IgnoreChildOrder IgnoreComments IgnorePI IgnoreWhitespace " fragments="no" xmlns:xd="http://schemas.microsoft.com/xmltools/2002/xmldiff">
<xd:node match="2">
<xd:node match="4">
<xd:change match="#ID">Test1</xd:change>
</xd:node>
<xd:node match="1">
<xd:change match="#ID">Test2</xd:change>
</xd:node>
</xd:node>
</xd:xmldiff>
What I need
<?xml version="1.0" encoding="utf-16"?>
<Employees>
<Employee ID="Test1" />
<Employee ID="Test2" />
<Employees>

Related

Bulk Editing Specific Elements in an XML with C#

I have an .xml file that shares an attribute between two different elements. I am trying to multiply the attributes inside one elements with one variable, and multiply the attributes in the other element with a different variable.
<acquirecosts>
<item>
<key>COST_SHOP_DEFAULT</key>
<quantity value="1"/>
<costtype>COST_TYPE_PRICE</costtype>
<items>
<item>
<item>CURRENCY_CASH</item>
<quantity value="6000"/>
</item>
</items>
<unlocks/>
</item>
</acquirecosts>
<sellprices>
<item>
<key>SELL_SHOP_DEFAULT</key>
<quantity value="1"/>
<costtype>COST_TYPE_PRICE</costtype>
<items>
<item>
<item>CURRENCY_CASH</item>
<quantity value="6000"/>
</item>
</items>
<unlocks/>
</item>
</sellprices>
The "CURRENCY_CASH" quantity value inside <./acquirecosts> is being multiplied by 2, and the "CURRENCY_CASH" quantity value inside <./sellprices> is being multiplied by 0.5.
using System;
using System.Xml;
using System.Xml.XPath;
XmlDocument doc = new XmlDocument();
doc.Load(#"C:\Users\Darkye\Desktop\shopprices.xml");
var buyModifier = 2;
var sellModifier = 0.5;
var caItNodesBuy = caNode.XPathSelectElement("./acquirecosts").Elements();
foreach (var caItNodeBuy in caItNodesBuy)
{
var caItNodeItems = caItNodeBuy.XPathSelectElement("./items").Elements();
foreach (var item in caItNodeItems)
{
var caItNodeItemKey = item.Element("item").Value;
if (caItNodeItemKey != "CURRENCY_CASH") continue;
var caItNodeItemValue = (int)Math.Floor((double)int.Parse(item.Element("quantity").Attribute("value").Value) * buyModifier);
item.Element("quantity").SetAttributeValue("value", caItNodeItemValue);
}
caItNodeBuy.XPathSelectElement("./items").ReplaceNodes(caItNodeItems);
}
caNode.XPathSelectElement("./acquirecosts").ReplaceNodes(caItNodesBuy);
var caItNodesSell = caNode.XPathSelectElement("./sellprices").Elements();
foreach (var caItNodeSell in caItNodesSell)
{
var caItNodeItems = caItNodeSell.XPathSelectElement("./items").Elements();
foreach (var item in caItNodeItems)
{
var caItNodeItemKey = item.Element("item").Value;
if (caItNodeItemKey != "CURRENCY_CASH") continue;
var caItNodeItemValue = (int)Math.Floor((double)int.Parse(item.Element("quantity").Attribute("value").Value) * sellModifier);
item.Element("quantity").SetAttributeValue("value", caItNodeItemValue);
}
caItNodeSell.XPathSelectElement("./items").ReplaceNodes(caItNodeItems);
}
caNode.XPathSelectElement("./sellprices").ReplaceNodes(caItNodesSell);
But I am struggling to figure out what and where to introduce "caNode" as. I'm assuming it's a variable, but I'm lost beyond that. When changing caNode to "doc" it just introduces errors on XPathSelectElement. Unless there's an easier way of applying these edits inside specific elements, I'm not sure what else to try.
Please try the following solution.
It is using so called Identity Transform pattern.
It will modify <quantity> element #value attribute value based on the required logic without touching anything else.
Input XML
<root>
<acquirecosts>
<item>
<key>COST_SHOP_DEFAULT</key>
<quantity value="1"/>
<costtype>COST_TYPE_PRICE</costtype>
<items>
<item>
<item>CURRENCY_CASH</item>
<quantity value="6000"/>
</item>
</items>
<unlocks/>
</item>
</acquirecosts>
<sellprices>
<item>
<key>SELL_SHOP_DEFAULT</key>
<quantity value="1"/>
<costtype>COST_TYPE_PRICE</costtype>
<items>
<item>
<item>CURRENCY_CASH</item>
<quantity value="6000"/>
</item>
</items>
<unlocks/>
</item>
</sellprices>
</root>
XSLT
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="utf-8" indent="yes" omit-xml-declaration="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="quantity">
<xsl:choose>
<xsl:when test="preceding-sibling::*='CURRENCY_CASH'">
<xsl:copy>
<xsl:attribute name="value">
<xsl:if test="ancestor::*[local-name() = 'acquirecosts']">
<xsl:value-of select="#value * 2"/>
</xsl:if>
<xsl:if test="ancestor::*[local-name() = 'sellprices']">
<xsl:value-of select="#value * 0.5"/>
</xsl:if>
</xsl:attribute>
</xsl:copy>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="."/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Output XML
<root>
<acquirecosts>
<item>
<key>COST_SHOP_DEFAULT</key>
<quantity value="1" />
<costtype>COST_TYPE_PRICE</costtype>
<items>
<item>
<item>CURRENCY_CASH</item>
<quantity value="12000" />
</item>
</items>
<unlocks />
</item>
</acquirecosts>
<sellprices>
<item>
<key>SELL_SHOP_DEFAULT</key>
<quantity value="1" />
<costtype>COST_TYPE_PRICE</costtype>
<items>
<item>
<item>CURRENCY_CASH</item>
<quantity value="3000" />
</item>
</items>
<unlocks />
</item>
</sellprices>
</root>
c#, XSLT transformation
void Main()
{
const string SOURCEXMLFILE = #"e:\Temp\input.xml";
const string XSLTFILE = #"e:\Temp\process.xslt";
const string OUTPUTXMLFILE = #"e:\temp\output.xml";
try
{
XsltArgumentList xslArg = new XsltArgumentList();
using (XmlReader src = XmlReader.Create(SOURCEXMLFILE))
{
XslCompiledTransform xslt = new XslCompiledTransform();
xslt.Load(XSLTFILE, new XsltSettings(true, true), new XmlUrlResolver());
XmlWriterSettings settings = xslt.OutputSettings.Clone();
settings.IndentChars = "\t";
// to remove BOM
settings.Encoding = new UTF8Encoding(false);
using (XmlWriter result = XmlWriter.Create(OUTPUTXMLFILE, settings))
{
xslt.Transform(src, xslArg, result, new XmlUrlResolver());
result.Close();
}
}
Console.WriteLine("File '{0}' has been generated.", OUTPUTXMLFILE);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
Use Xml Linq and do two passes
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
XElement acquiredcosts = doc.Descendants("acquirecosts").FirstOrDefault();
List<XElement> currentCash = acquiredcosts.Descendants("item").Where(x => (string)x.Element("item") == "CURRENCY_CASH").ToList();
foreach (XElement c in currentCash)
{
XElement quantity = c.Element("quantity");
quantity.SetAttributeValue("value", 2 * (int)quantity.Attribute("value"));
}
XElement sellPrices = doc.Descendants("sellprices").FirstOrDefault();
currentCash = sellPrices.Descendants("item").Where(x => (string)x.Element("item") == "CURRENCY_CASH").ToList();
foreach (XElement c in currentCash)
{
XElement quantity = c.Element("quantity");
quantity.SetAttributeValue("value", .5 * (int)quantity.Attribute("value"));
}
}
}
}

Delete data in XML with C#

I have the following XML File:
<order id="1234">
<users>
<user id="102030" nick="nickname" done="false" />
<user id="123456" nick="nickname" done="false" />
</users>
<machines>
<machine id="123" sd="123" ref="" done="false" />
<machine id="456" sd="456" ref="" done="false" />
<machine id="789" sd="789" ref="" done="false" />
</machines>
</order>
I want to delete the user with the id 102030, so the xml looks like this:
<users>
<user id="123456" nick="nickname" done="false" />
</users>
<machines>
<machine id="123" sd="123" ref="" done="false" />
<machine id="456" sd="456" ref="" done="false" />
<machine id="789" sd="789" ref="" done="false" />
</machines>
</order>
This is my code which doesn't work:
XmlDocument doc = XmlDocument.Load(path);
XmlNodeList nodes = doc.GetElementsByTagName("users");
foreach(XmlNode node in nodes){
foreach(XmlAttribute attribute in node.Attributes){
if(attribute.Name== "id" && attribute.Value == "102030"){
node.RemoveAll();
}
}
}
doc.Save(path);
I am a newbie in C# so I need every help!
Thanks in advance, geibi
XmlNode.RemoveAll() does not remove a node. Instead it:
Removes all the child nodes and/or attributes of the current node.
Thus, instead you need to remove the node from its parent:
node.ParentNode.RemoveChild(node);

c# - Adding new parent node to existing Xml File

I have the following xml file and want to add a new parent node after the last existing node.
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<testsuite id="" name="Test Projekt test">
<node_order />
<details />
<testsuite id="" name="Test Suite 1">
<node_order />
<details />
<testsuite id="" name="Test Suite Operation 2">
<node_order />
<details />
</testsuite>
</testsuite>
</testsuite>
<new node here>
i tryed to use the following code but it didnĀ“t worked
XmlElement testsuite = doc_save.CreateElement("testsuite");
XmlAttribute ID = doc_save.CreateAttribute("id");
XmlAttribute Name = doc_save.CreateAttribute("name");
XmlElement node_order = doc_save.CreateElement("node_order");
XmlElement details = doc_save.CreateElement("details");
doc_save.DocumentElement.AppendChild(testsuite);
testsuite.Attributes.Append(ID);
testsuite.Attributes.Append(Name);
testsuite.AppendChild(node_order);
testsuite.AppendChild(details);
How can I do this?
Expanding on the comment by #hotfix, rename your root element and when I ran your code it was working for me. See the XML and code I was using below.
XML:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<testsuites id="" name="Test Projekt test">
<node_order />
<details />
<testsuite id="" name="Test Suite 1">
<node_order />
<details />
<testsuite id="" name="Test Suite Operation 2">
<node_order />
<details />
</testsuite>
</testsuite>
<testsuite id="" name="">
<node_order />
<details />
</testsuite>
</testsuites>
Code:
XmlDocument document = new XmlDocument();
document.Load(#"your\xml\file");
XmlElement testsuite = document.CreateElement("testsuite");
XmlAttribute ID = document.CreateAttribute("id");
XmlAttribute Name = document.CreateAttribute("name");
XmlElement node_order = document.CreateElement("node_order");
XmlElement details = document.CreateElement("details");
document.DocumentElement.AppendChild(testsuite);
testsuite.Attributes.Append(ID);
testsuite.Attributes.Append(Name);
testsuite.AppendChild(node_order);
testsuite.AppendChild(details);
document.Save(#"your\xml\file");

Parsing XML Document in C#

I am writing a C# code to parse the following XML doc :
<?xml version="1.0" encoding="utf-8" ?>
<teams>
<team id="1">
<name>RealMadrid</name>
<players>
<player id="1" role="Forward">
<firstname>Cristiano</firstname>
<lastname>Ronaldo</lastname>
<number>7</number>
</player>
<player id="2" role="Forward">
<firstname>Gareth</firstname>
<lastname>Bale</lastname>
<number>11</number>
</player>
<player id="3" role="Midfield">
<firstname>Toni</firstname>
<lastname>Kroos</lastname>
<number>8</number>
</player>
<player id="4" role="Midfield">
<firstname>Luka</firstname>
<lastname>Modric</lastname>
<number>19</number>
</player>
<player id="5" role="Defence">
<firstname>Sergio</firstname>
<lastname>Ramos</lastname>
<number>4</number>
</player>
<player id="6" role="Defence">
<firstname>Raphael</firstname>
<lastname>Varane</lastname>
<number>2</number>
</player>
<player id="7" role="Goalkeeper">
<firstname>Keylor</firstname>
<lastname>Navas</lastname>
<number>1</number>
</player>
</players>
</team>
<team id="2">
<name>Barcelona</name>
<players>
<player id="1" role="Forward">
<firstname>Lionel</firstname>
<lastname>Messi</lastname>
<number>10</number>
</player>
<player id="2" role="Forward">
<firstname>Neymar</firstname>
<lastname>Jr.</lastname>
<number>11</number>
</player>
<player id="3" role="Midfield">
<firstname>Ivan</firstname>
<lastname>Rakitic</lastname>
<number>4</number>
</player>
<player id="4" role="Midfield">
<firstname>Andres</firstname>
<lastname>Iniesta</lastname>
<number>8</number>
</player>
<player id="5" role="Defence">
<firstname>Gerard</firstname>
<lastname>Pique</lastname>
<number>3</number>
</player>
<player id="6" role="Defence">
<firstname>Javier</firstname>
<lastname>Mascherano</lastname>
<number>14</number>
</player>
<player id="7" role="Goalkeeper">
<firstname>Andre</firstname>
<lastname>Ter Stegen</lastname>
<number>1</number>
</player>
</players>
</team>
<team id="3">
<name>Liverpool</name>
<players>
<player id="1" role="Forward">
<firstname>Daniel</firstname>
<lastname>Sturridge</lastname>
<number>15</number>
</player>
<player id="2" role="Forward">
<firstname>Roberto</firstname>
<lastname>Firmino</lastname>
<number>11</number>
</player>
<player id="3" role="Midfield">
<firstname>Philippe</firstname>
<lastname>Coutinho</lastname>
<number>10</number>
</player>
<player id="4" role="Midfield">
<firstname>Adam</firstname>
<lastname>Lallana</lastname>
<number>20</number>
</player>
<player id="5" role="Defence">
<firstname>Joel</firstname>
<lastname>Matip</lastname>
<number>32</number>
</player>
<player id="6" role="Defence">
<firstname>Dejan</firstname>
<lastname>Lovren</lastname>
<number>6</number>
</player>
<player id="7" role="Goalkeeper">
<firstname>Simon</firstname>
<lastname>Mignolet</lastname>
<number>22</number>
</player>
</players>
</team>
</teams>
I want to write the firstname and lastname for players of a specific team.
I wrote the following code :
var realTeam = from db in xelement.Elements("team")
where (string)db.Element("name")=="RealMadrid"
select db;
//Console.WriteLine("Real Madrid");
foreach (var e in realTeam)
{
Console.WriteLine(e);
}
This code is giving all the xml part related to "RealMadrid".
What should I do write on the firstname and lastname of this part?
Any help is appreciated!!
Do it like this:
var xmlContent = "YOUR XML";
var xmlDoc = XDocument.Parse(xmlContent);
var realTeamName = "RealMadrid";
var realTeam = from team in xmlDoc.Elements("teams")
.Descendants("team")
where team.Element("name").Value == realTeamName
select team;
var players = realTeam.Elements("players").Elements(); // get players
foreach (var player in players) // iterate over players
{
Console.WriteLine("First name: " + player.Element("firstname").Value);
Console.WriteLine("Last name: " + player.Element("lastname").Value);
}
So far you've got the team, but now you need to step into the team elements to get the players list and then the single player with firstname, lastname....
As I mentioned in my comment, you're not selecting the players element in your statement. Try the following:
var realTeam = from db in xelement.Elements("team")
where (string)db.Element("name")=="RealMadrid"
select db.Elements("players");
//Console.WriteLine("Real Madrid");
if (realTeam.Count() != 1)
{
//more than 1 team called RealMadrid was found, handle this case here
return;
}
foreach (var e in realTeam.Single())
{
Console.WriteLine("First Name: " + e.Element("firstname").Value); //or e.Element("firstname").ToString()
Console.WriteLine("Last Name: " + e.Element("lastname").Value);
}

XML extracting attributes using XMLDocument

i am trying to parse an xml element using XMLDocument (DItem >> Title)
below is my code but somehow i am not getting hold of it.... any help?
XmlDocument xmldoc = new XmlDocument();
XmlNamespaceManager xmlns = new XmlNamespaceManager(xdoc.NameTable);
xmlns.AddNamespace("DItems", "http://namespace.xsd");
xmldoc.Load(url);
var title = xmldoc.SelectNodes("content", xmlns);
foreach (XmlNode node in title)
{
string title = node.Attributes["Title"].Value;
//this.ddlTitle.Items.Add(new ListItem(title));
}
here is my XML:
<?xml version='1.0'?>
<root xmlns="http://www.w3.org/2005/Atom">
<title type="text">title</title>
<entry>
<content type="application/xml">
<Items xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.namespace.xsd">
<CatalogSource Acronym="ABC" OrganizationName="organization name" />
<Item Id="28466" CatalogUrl="url">
<DItem xmlns:content="http://namespace.xsd" TargetUrl="http://index.html" Title="my title1">
<content:Source Acronym="ABC" OrganizationName="ABC" />
</DItem>
</Item>
</Items>
</content>
</entry>
<entry>
<content type="application/xml">
<Items xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.namespace.xsd">
<CatalogSource Acronym="ABC" OrganizationName="organization name" />
<Item Id="28466" CatalogUrl="url">
<DItem xmlns:content="http://namespace.xsd" TargetUrl="http://index.html" Title="my title2">
<content:Source Acronym="ABC" OrganizationName="ABC" />
</DItem>
</Item>
</Items>
</content>
</entry>
<entry>
<content type="application/xml">
<Items xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.namespace.xsd">
<CatalogSource Acronym="ABC" OrganizationName="organization name" />
<Item Id="28466" CatalogUrl="url">
<DItem xmlns:content="http://namespace.xsd" TargetUrl="http://index.html" Title="my title3">
<content:Source Acronym="ABC" OrganizationName="ABC" />
</DItem>
</Item>
</Items>
</content>
</entry>
</root>
var xmldoc = new XmlDocument();
var xmlns = new XmlNamespaceManager(xmldoc.NameTable);
xmlns.AddNamespace("DItems", "http://www.namespace.xsd");
xmldoc.Load(url);
var titleNodes = xmldoc.SelectNodes("//DItems:DItem/#Title", xmlns);
var result = titleNodes.Cast<XmlAttribute>().Select(a => a.Value).ToList();
Output (list of objects):
my title1
my title2
my title3

Categories