XML Combing Duplicate IDs to a single XML and removing the duplicate - c#

I have an XML file with several customers. When the customer ID is duplicated, I want to take the service from the duplicate customer record and add it to the initial customer record. I'm trying to do this in C#.
So the following two records:
<customer ID="200054598540" phone="352-555-1234" name="PAULSON ROBERT">
<services>
<service type="Electric" premise="5000001234" priority="0" />
</services>
<customFields>
<customField key="address" value="1521 NE 23RD AVE" />
<customField key="connection" value="CONNECTED" />
</customFields>
</customer>
<customer ID="200054598540" phone="352-555-1234" name="PAULSON ROBERT">
<services>
<service type="Water" premise="5000001235" priority="0" />
</services>
<customFields>
<customField key="address" value="1521 NE 23RD AVE" />
<customField key="connection" value="CONNECTED" />
</customFields>
</customer>
Become one, and it removes the duplicate, leading to:
<customer ID="200054598540" phone="352-555-1234" name="PAULSON ROBERT">
<services>
<service type="Electric" premise="5000001234" priority="0" />
<service type="Water" premise="5000001235" priority="0" />
</services>
<customFields>
<customField key="address" value="1521 NE 23RD AVE" />
<customField key="connection" value="CONNECTED" />
</customFields>
</customer>
private static void combineDuplicates()
{
XDocument doc = XDocument.Load(#"C:\customer_premise_osi_oms\customers.xml");
var customers = doc.Descendants("customer").GroupBy(x => (string)x.Attribute("ID")).ToList();
foreach (var customer in customers)
{
XElement firstAccount = customer.FirstOrDefault();
XElement firstServices = firstAccount.Element("services");
XElement firstCustomerField = firstAccount.Element("customFields");
for (int i = customer.Count() - 1; i >= 1; i--)
{
XElement account = customer.Skip(i).FirstOrDefault();
List<XElement> services = account.Descendants("service").ToList();
firstServices.Add(services);
//List<XElement> customFields = account.Descendants("customField").ToList();
//firstCustomerField.Add(customFields);
account.Remove();
}
}
doc.Save(#"c:\customer_premise_osi_oms\customers_dupe.xml");
}

Using Xml Linq :
using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication75
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
var customers = doc.Descendants("customer").GroupBy(x => (string)x.Attribute("ID")).ToList();
foreach (var customer in customers)
{
XElement firstAccount = customer.FirstOrDefault();
XElement firstServices = firstAccount.Element("services");
XElement firstCustomerField = firstAccount.Element("customFields");
for (int i = customer.Count() - 1; i >= 1; i--)
{
XElement account = customer.Skip(i).FirstOrDefault();
List<XElement> services = account.Descendants("service").ToList();
firstServices.Add(services);
List<XElement> customFields = account.Descendants("customField").ToList();
firstCustomerField.Add(customFields);
account.Remove();
}
}
}
}
}

Related

get decendents in XML where specific element contains value

<?xml version="1.0" encoding="utf-8" ?>
<Licenses>
<License>
<LicenseType>Temporary License</LicenseType>
<BundleType>Line</BundleType>
<Features>
<Feature>
<Value>Full</Value>
<Status>Full Access</Status>
<AccessLevel>Full</AccessLevel>
</Feature>
<Feature>
<Name>EnhancedUserAccounts</Name>
<LocalisedName>Enhanced User Accounts</LocalisedName>
<Value>Full</Value>
<Status>Full Access</Status>
<AccessLevel>Full</AccessLevel>
</Feature>
</Features>
</License>
<License>
<LicenseType>Temporary License</LicenseType>
<BundleType>Line</BundleType>
<Features>
<Feature>
<Value>Full</Value>
<Status>Full Access</Status>
<AccessLevel>Full</AccessLevel>
</Feature>
<Feature>
<Name>EnhancedUserAccounts</Name>
<LocalisedName>Enhanced User Accounts</LocalisedName>
<Value>Full</Value>
<Status>Full Access</Status>
<AccessLevel>Full</AccessLevel>
</Feature>
</Features>
</License>
</Licenses>
How to read the feature list into to IEnumerable if my BundleType = line
You can do this easily using XDocument
var xDocument = XDocument.Parse(XML)
or
var xDocument = XDocuemnt.Load(FilePath)
then:
xDocument.Descendants("LicenseType")
Which will get all nodes that descend from LicenseType
To test for that BundleType element you could do something like:
nodes.Where(n=>n.Element("BundleType") == "Line").Decesendants("Features")
which will get all Features where <BundleType> of the parent is "Line"
EDIT: As per comments, to get all features:
xDocument.Desecendants("Features")
That will get all <Feature> nodes under the <Features> Element
Use following based on the xml I updated on your posting :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication70
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
var results = doc.Descendants("License").Where(x => (string)x.Element("BundleType") == "Line")
.Select(x => x.Descendants("Feature").ToList()).ToList();
}
}
}

cannot get node by using selectSingleNode method

my xml file is like below:
<?xml version="1.0"?>
<UpdateInboundim613Response xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" status="SUCCESS" message="Success" schemaRevisionDate="2016-07-19" schemaRevisionLevel="0" returnCode="0" xmlns="http://schemas.hp.com/SM/7">
<model>
<keys>
<TransactionID type="String">E-InHPSXIM1089779</TransactionID>
</keys>
<instance uniquequery="TransactionID="E-InHPSXIM1089779"" recordid="E-InHPSXIM1089779">
<TransactionDetailedTrace xsi:nil="true" />
<TransactionMessage type="Array">
<TransactionMessage type="String" />
</TransactionMessage>
<OVSCSolutionDescription type="Array">
<OVSCSolutionDescription type="String">Issue: EL-BANK OUTSIDE WAREHOUSE EGYPT IMEA[2702]Interface[[E1 0/0/0]]|Router|ELBKCE1GW /pg-h-pg1252-256675160|143.34.213.18|Down Solution: As per update from Mai Shrief that the site has been suspended on 30th June. So no need of any investigation. Resolved By: BT NOC</OVSCSolutionDescription>
</OVSCSolutionDescription>
<OVSCTicketID type="String">E-IM004004076</OVSCTicketID>
<RIMSImpact xsi:nil="true" />
<attachments />
</instance>
</model>
<messages>
<message type="String" xmlns="http://schemas.hp.com/SM/7/Common">TransactionStatusDetail in $L.file is:IM Ticket: E-IM004004076 is valid for Update Subtype: Resolve</message>
</messages>
</UpdateInboundim613Response>
but my code cannot get value of element "OVSCTicketID":
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(#"C:\zzx\Project\SM\R5.1\Harness\InBound.xml");
XmlNode sigNode = xmlDoc.SelectSingleNode("/UpdateInboundim613Response/model/instance/OVSCTicketID");
if (sigNode != null)
{
Console.WriteLine(sigNode.InnerText);
}
can you please tell me what's the problem and how to fix it?
Your Xml document uses the default namespace "http://schemas.hp.com/SM/7". You need to use the XmlNamespaceManager to select that node under this namespace.
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(#"C:\zzx\Project\SM\R5.1\Harness\InBound.xml");
var namespaceManager = new XmlNamespaceManager(xmlDoc.NameTable);
namespaceManager.AddNamespace("ns", "http://schemas.hp.com/SM/7");
XmlNode sigNode = xmlDoc.SelectSingleNode("//ns:UpdateInboundim613Response//ns:model//ns:instance//ns:OVSCTicketID",namespaceManager);
if (sigNode != null)
{
Console.WriteLine(sigNode.InnerText);
}
Above code should work fine.
Using 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
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
XNamespace defaultNs = ((XElement)doc.FirstNode).GetDefaultNamespace();
string ovsCTicketID = (string)doc.Descendants(defaultNs + "OVSCTicketID").FirstOrDefault();
}
}
}

Read an XML File and transform data into a list of DirectoryInfo elements

I'm currently trying to read an XML file of this format to transform it into a list but trying out the code in the comments gave me an error: this is how it looks like in IE. Obviously theres a close assets tag and close properties later
<Properties>
- <Assets>
- <Asset Name="" Version="">
<TestCase Name="" Version="" SubVersion="" />
<TestCase Name="" Version="" SubVersion="" />
<TestCase Name="" Version="" SubVersion="" />
<TestCase Name="" Version="" SubVersion="" />
</Asset>
So I did this:
XmlReader xReader = XmlReader.Create(new StringReader(xmlDoc));
where xml doc = #"\\visreP01\REFERENCES\default.reference.versions\default.reference.versions.properties.xml"
I'm planning to test how to iterate a name a version and so on to place them in a list iteratively. but during the reading the I got the data root level is invalid line 1 position 1.
Try this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XmlReader xReader = XmlReader.Create(FILENAME);
while(!xReader.EOF)
{
if (xReader.Name != "Asset")
{
xReader.ReadToFollowing("Asset");
}
if (!xReader.EOF)
{
XElement assets = (XElement)XElement.ReadFrom(xReader);
var results = assets.Elements("TestCase").Select(x => new
{
name = (string)x.Attribute("Name"),
version = (string)x.Attribute("Version"),
subVersion = (string)x.Attribute("SubVersion")
}).ToList();
}
}
}
}
}

reading an xmlnode using xmlDocment

how can i read an Id from the below sample XML >>> CatalogItem Id="3212" and OrganizationName
string xmlfile = #"C:\Users\easwaranp\Desktop\test.xml";
ArrayList arrResult = new ArrayList();
string sContent = File.ReadAllText(xmlfile);
StringReader DocumentReader = new StringReader(sContent);
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(DocumentReader);
XmlNodeList ReferenceNodes = xmlDoc.GetElementsByTagName("content:Topic");
foreach (XmlNode Node in ReferenceNodes)
{
string sTopicName = Node.ParentNode.ParentNode.Attributes["OrganizationName"].Value;
}
foreach (string s in arrResult)
{
Console.WriteLine(s);
}
Console.Read();
<content type="application/xml">
<CatalogItems xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="sitename.xsd">
<CatalogSource Acronym="ABC" OrganizationName="ABC Corporation" />
<CatalogItem Id="32122" CatalogUrl="urlname">
<ContentItem xmlns:content="sitename.xsd" Title="Department 1">
<content:SelectionSpec ClassList="" ElementList="" />
<content:Language Value="eng" Scheme="ISO 639-2" />
<content:Source Acronym="ABC" OrganizationName="ABC Corporation1" />
<content:Topics Scheme="ABC">
<content:Topic TopicId="1" TopicName="Marketing1" />
<content:Topic TopicId="11" TopicName="Coverage1" />
</content:Topics>
</ContentItem>
</CatalogItem>
<CatalogItem Id="3212" CatalogUrl="urlname">
<ContentItem xmlns:content="sitename.xsd" Title="Department 2">
<content:SelectionSpec ClassList="" ElementList="" />
<content:Language Value="eng" Scheme="ISO 639-2" />
<content:Source Acronym="ABC" OrganizationName="ABC Corporation2" />
<content:Topics Scheme="ABC">
<content:Topic TopicId="2" TopicName="Marketing2" />
<content:Topic TopicId="22" TopicName="Coverage2" />
</content:Topics>
</ContentItem>
</CatalogItem>
<CatalogItem Id="32132" CatalogUrl="urlname">
<ContentItem xmlns:content="sitename.xsd" Title="Department 3">
<content:SelectionSpec ClassList="" ElementList="" />
<content:Language Value="eng" Scheme="ISO 639-2" />
<content:Source Acronym="ABC" OrganizationName="ABC Corporation3" />
<content:Topics Scheme="ABC">
<content:Topic TopicId="3" TopicName="Marketing3" />
<content:Topic TopicId="33" TopicName="Coverage3" />
</content:Topics>
</ContentItem>
</CatalogItem>
</CatalogItems>
</content>
using System;
using System.IO;
using System.Xml;
class GetValue{
public static void Main(){
var xmlDoc = new XmlDocument();
xmlDoc.Load("test.xml");
var xmlRoot = xmlDoc.DocumentElement;
var nsmgr = new XmlNamespaceManager(xmlDoc.NameTable);
nsmgr.AddNamespace("content", "sitename.xsd");
var attr = xmlRoot.SelectSingleNode("descendant::content:Source/#OrganizationName[../../../#Id='3212']", nsmgr);
if(attr == null)
Console.WriteLine("not found!");
else
Console.WriteLine(attr.Value);
}
}
OUTPUT:
ABC Corporation2
XPath is your friend when it comes to tasks like this. I adapted the following code from a tutorial on codeproject.com. I don't know if it works (or will even compile), but it should get you started in the right direction. Also, I'm assuming your talking about C#, but in case I've misunderstood what language you're using, please disregard (a language tag on your question might help).
using System.Xml;
using System.Xml.XPath;
....
string fileName = "test.xml";
XPathDocument doc = new XPathDocument(fileName);
XPathNavigator nav = doc.CreateNavigator();
// Compile a standard XPath expression
XPathExpression expr;
idExpr = nav.Compile("/content/CatalogItems/CatalogItem/#id");
XPathNodeIterator iterator = nav.Select(idExpr);
// Iterate on the node set
try
{
while (iterator.MoveNext())
{
XPathNavigator nav2 = iterator.Current.Clone();
Console.WriteLine("id: " + nav2.Value);
}
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}

how to check if xml document has a certain list of attributes?

i am experimenting with C# and xml, i am trying to read a XML file i want to validate if "NumberOfDays" , "NumberOfBooks", "NumberOfExam", "CurrentDate" are existing, if missing. i want to add them with there values.
i have the following xmldocument :
<?xml version="1.0" encoding="utf-8" ?>
<MySample>
<Content>
<add key="NumberOfDays" value="31" />
<add key="NumberOfBooks" value="20" />
<add key="NumberOfExam" value="6" />
<add key="CurrentDate" value="15 - Jul - 2011" />
</Content>
</MySample>
i am writing a sample application in c# using
--------Edit--------
thank you AresAvatar for your responce.
but if the value exists i would like to update its value i.e. if let's say
<add key="NumberOfExam" value="" />
i want to change the value to 6
You can get a list of which nodes exist like this:
// Get a list of which nodes exist
XmlDocument doc = new XmlDocument();
doc.LoadXml(myXml);
List<string> existingNodes = new List<string>();
XmlNodeList bookNodes = doc.SelectNodes("/MySample/Content/add");
foreach (XmlNode nextNode in bookNodes)
{
foreach (XmlAttribute nextAttr in nextNode.Attributes)
existingNodes.Add(nextAttr.InnerText);
}
You can add missing nodes like this:
// Add nodes
XmlNode addRoot = doc.SelectSingleNode("/MySample/Content");
XmlElement addme = doc.CreateElement("add");
addme.SetAttribute("NumberOfDays", "31");
addRoot.AppendChild(addme);
You can set the value of existing nodes like this:
// Update a node
foreach (XmlNode nextNode in bookNodes)
{
foreach (XmlAttribute nextAttr in nextNode.Attributes)
{
switch (nextAttr.Name)
{
case "NumberOfDays":
((XmlElement)nextNode).SetAttribute("value", "31");
break;
// etc.
}
}
}
First of all, if you have control over the generated XML (if you make it yourself), avoid using this schema:
<?xml version="1.0" encoding="utf-8" ?>
<MySample>
<Content>
<add key="NumberOfDays" value="31" />
<add key="NumberOfBooks" value="20" />
<add key="NumberOfExam" value="6" />
<add key="CurrentDate" value="15 - Jul - 2011" />
</Content>
</MySample>
It's much easier to use with that schema:
<?xml version="1.0" encoding="utf-8" ?>
<MySample>
<Content>
<Adds>
<NumberOfDays>31<NumberOfDays/>
<NumberOfBooks>20<NumberOfBooks/>
<NumberOfExam>6<NumberOfExam/>
<CurrentDate>5 - Jul - 2011<CurrentDate/>
</Adds>
</Content>
</MySample>
And then:
XmlDocument doc = new XmlDocument();
doc.Load("YourXmlPath");
XmlNode firstNode = doc["MySample"];
if(firstNode != null)
{
XmlNode secondNode = firstNode["Content"];
if(secondNode != null)
{
XmlNode thirdNode = secondNode["Adds"];
if(thirdNode != null)
{
if(thirdNode["NumberOfDays"] == null) //The "NumberOfDays" node does not exist, we create it.
{
XmlElement newElement = doc.CreateElement("NumberOfDays");
newElement.InnerXml = 31;
thirdNode.AppendChild(newElement);
}
//Do the same for the other nodes...
}
}
}
doc.Save("YourXmlPath");
Just remember to check for null on every node, or put the whole block into a try/catch.
And to save the XML once you did your changes.
XmlDocument.Load() function loads the XML in memory, so you can check for any node without making "blind loops".

Categories