Extracting the particular part of an XML - c#

I have an XML in a string variable i want to check if this xml content contains
<xml>
<message display='yes'>
....
or
<xml>
<xdp:xdp>
...
is it possible?

Here is how you can check for it:
string example = #"<xml>
<message display='yes'></message>
</xml>";
XDocument doc = XDocument.Parse(example);
if (doc.Element("xml").Element("message") != null)
{
// node "message" exists within node "xml" which is located at the root of the document
}
You can use XDocument class to check for existence of any node at any location in the hierarchy of an XML document. You can load contents from string or file easily.

An example below
<Order>
<AmazonOrderID>000-1111111-2222222</AmazonOrderID>
<MerchantOrderID>111-3333333-4444444</MerchantOrderID>
<PurchaseDate>2012-03-02T13:28:53+00:00</PurchaseDate>
<LastUpdatedDate>2012-03-02T13:29:05+00:00</LastUpdatedDate>
<OrderStatus>Pending</OrderStatus>
<SalesChannel>Amazon.com</SalesChannel>
<URL>http://www.amazon.com</URL>
<FulfillmentData>
<FulfillmentChannel>Amazon</FulfillmentChannel>
<ShipServiceLevel>Standard</ShipServiceLevel>
<Address>
<City>Beverly Hills</City>
<State>CA</State>
<PostalCode>90210-1234</PostalCode>
<Country>US</Country>
</Address>
</FulfillmentData>
<OrderItem>
<ASIN>AmazonASIN </ASIN>
<SKU> Internal-SKU</SKU>
<ItemStatus>Pending</ItemStatus>
<ProductName> This is the name of the product </ProductName>
<Quantity>1</Quantity>
<ItemPrice>
<Component>
<Type>Principal</Type>
<Amount currency="USD">19.99</Amount>
</Component>
</ItemPrice>
</OrderItem>
</Order>
List<string> getNodes(string path, string nodeName) {
List<string> nodes = new List<string>();
XDocument xmlDoc = XDocument.Load(path); //Create the XML document type
foreach (var el in xmlDoc.Descendants(nodeName)) {
//for debugging
//nodes.Add(el.Name + " " + el.Value);
//for production
nodes.Add(el.Value);
}
return nodes;
} //end getNodes
List<string> skuNodes = xml.getNodes(#"AmazonSalesOrders.xml", "SKU");

Related

Unable to use InsertAfter for XmlDocument in c#

Hi below are the XML files which is master XML
<?xml version="1.0" encoding="utf-16"?>
<Verify>
<ver>
<ECU>
<values>
</values>
</ECU>
</ver>
</Verify>
I have multiple files which are of same structure as below
<?xml version="1.0" encoding="utf-16"?>
<Verify>
<ver>
<ECU>
<values>
</values>
</ECU>
</ver>
</Verify>
I want my output as
<?xml version="1.0" encoding="utf-16"?>
<Verify>
<ver>
<ECU>
<values>
</values>
</ECU>
<ECU>
<values>
</values>
</ECU>
<ECU>
<values>
</values>
</ECU>
</ver>
</Verify>
I am using below code to read first one as master xml
and other files from xmls folder. I want to add ECU node from these files under ECU node of master file.
XmlDocument xmlMaster = new XmlDocument();
xmlMaster.Load(#"C:\MasterXMLFile.xml");
XmlElement masterRoot = xmlMaster.DocumentElement;
XmlNode masterParent = masterRoot.LastChild.LastChild;
var downloadfolder = #"C:\AllXMLs\xmls\";
string[] files = Directory.GetFiles(downloadfolder);
foreach (var xx in files)
{
XmlNode masterNode = masterRoot.LastChild.LastChild;
XmlDocument xdoc = new XmlDocument();
xdoc.Load(xx);
XmlElement root = xdoc.DocumentElement;
XmlElement tempNode = (XmlElement)root.LastChild.LastChild;
masterRoot.InsertAfter(tempNode, masterRoot.SelectSingleNode("//ECU").ParentNode);
}
xmlMaster.Save(#"C:\mergeg.xml");
I am getting error at InsertAfter statement as Object reference not set to an instance of an object.
Please suggest me any solution.
Your tempNode is from xdoc document context. You should import it to xmlMaster document context:
XmlNode importedECU = xmlMaster.ImportNode(tempNode, true);
Also instead of InsertAfter it's better to use AppendChild and append new ECU nodes as children of master ver element:
var masterVer = masterRoot.SelectSingleNode("//ver");
foreach(var file in files)
{
var xdoc = new XmlDocument();
xdoc.Load(file);
var tempNode = xdoc.DocumentElement.LastChild.LastChild;
var importedECU = xmlMaster.ImportNode(tempNode, true);
masterVer.AppendChild(importedECU);
}
Your InsertAfter should be on the parentNode of the node you want to insert after, so the parent of tempNode.

C# Add nodes in xml

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);
}
}
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
}
}

Get name of tag in xml

I have a problem with parse xml file to retrieve a names of tags. I have a following xml file:
<city version="1.2" last_updated="Thu, 28 Aug 2014 12:10:38 +0300">
<city id="8750">
<name>Лондон</name>
<name_en>London</name_en>
<region/>
<country>Великобритания</country>
<country_id>826</country_id>
</city>
<city id="110254">
<name>Лондон</name>
<name_en>London</name_en>
<region/>
<country>Канада</country>
<country_id>124</country_id>
</city>
<city id="58690">
<name>Лондон</name>
<name_en>London</name_en>
<region>Arkansas</region>
<country>Соединенные Штаты Америки</country>
<country_id>840</country_id>
</city>
<city id="65450">
<name>Лондон</name>
<name_en>London</name_en>
<region>Kentucky</region>
<country>Соединенные Штаты Америки</country>
<country_id>840</country_id>
</city>
<city id="76284">
<name>Лондон</name>
<name_en>London</name_en>
<region>Ohio</region>
<country>Соединенные Штаты Америки</country>
<country_id>840</country_id>
</city>
<city id="131">
<name>Макеевка</name>
<name_en>Makiivka</name_en>
<region>Донецкая область</region>
<country>Украина</country>
<country_id>804</country_id>
</city>
</city>
I want to do array or select list with all name of tag for example country. I have following code:
string filePath = String.Format("http://xml.weather.co.ua/1.2/city/?search={0}", name);
var xmlDocument = new XmlDocument();
xmlDocument.Load(filePath);
if (xmlDocument.DocumentElement != null)
foreach (XmlNode xmlNode in xmlDocument.GetElementsByTagName("city"))
yield return new SelectListItem
{
Text = xmlNode.Value,
Value = xmlNode.ToString()
};
}
How to solve this problem? Any idea?
Here is my idea but you have to create list "names" before. Try this LINQ to xml:
XDocument xDoc = XDocument.Load("your xml file");
foreach (var elem in xDoc.Document.Descendants("country"))
{
names.Add(elem.Name);
}
If you can modify an xml to for me more clear form like that:
<city id="8750" name="Лондон" name_en="London" region="" country="Великобритания" country_en="826"/>
What for create that number of tags with only names?
Than u can do that:
XDocument xDoc = XDocument.Load("your xml file");
foreach (var elem in xDoc.Document.Descendants("city"))
{
names.Add(elem.Attribute("name").Value);
name_en.Add(elem.Attribute("name_en").Value);
(...)
}
"I want to do array or select list with all name of tag for example country."
"I want get all value with tag country and I do not know how"
You can try using XDocument to get array of country names :
string url = "http://xml.weather.co.ua/1.2/city/?search=%D0%BB%D0%BE%D0%BD%D0%B4%D0%BE%D0%BD";
XDocument doc = XDocument.Load(url);
var countries = doc.Descendants("city")
.Elements("country")
.Select(o => (string)o)
.ToArray();

Looping through nodes with XPathNavigator

Hi below is a sample of the xml i am using. I been through allsorts of options I can think of to be able to start at the personData node and iterate the results, and nothing i seem to try works unless I navigate manually through each child node from the root down. Can anyone advise on how I can do this without starting at the root
My code currently is
using (var r = File.OpenText(#"C:\S\sp.xml"))
{
XPathDocument document = new XPathDocument(XmlReader.Create(r));
XPathNavigator xPathNav = document.CreateNavigator();
XmlNamespaceManager nsmgr = new XmlNamespaceManager(xPathNav.NameTable);
nsmgr.AddNamespace("g2", "http://person.transferobject.com/xsd");
XPathNodeIterator xni = xPathNav.Select("/g2:companys/g2:company/g2:person/g2:personData", nsmgr);
foreach (XPathNavigator nav in xni)
Console.WriteLine(nav.Name);
}
Xml
<?xml version="1.0" encoding="UTF-8"?>
<Header xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<dataSource xmlns="http://person.transferobject.com/xsd">IG2</dataSource>
<dateTime xmlns="http://person.transferobject.com/xsd">Thu Mar 21 15:56:42 GMT 2013</dateTime>
<formatVersion xmlns="http://person.transferobject.com/xsd">2.0</formatVersion>
<companys xmlns="http://person.transferobject.com/xsd">
<company>
<errorMessages xsi:nil="true"/>
<person>
<personData>
<address>
<address1 xmlns="http://transferobject.com/xsd">37 Smith St</address1>
<county xmlns="http://transferobject.com/xsd">COUNTY-37</county>
<postcode xmlns="http://transferobject.com/xsd">Po12 123</postcode>
</address>
<basicDetails>
<currentFirstName xmlns="http://transferobject.com/xsd">Fred</currentFirstName>
<currentLastName xmlns="http://transferobject.com/xsd">Bloggs</currentLastName >
<currentStage xmlns="http://transferobject.com/xsd">H1</currentStage>
<currentGroup xmlns="http://transferobject.com/xsd">3</currentGroup>
<dob xmlns="http://transferobject.com/xsd">2000-04-25</dob>
<email xmlns="http://transferobject.com/xsd">AN#AN.AOM</email>
<entryDate xmlns="http://transferobject.com/xsd">2003-09-03</entryDate>
</basicDetails>
</personData>
<personData>
<address>
<address1 xmlns="http://transferobject.com/xsd">37 Smith St</address1>
<county xmlns="http://transferobject.com/xsd">COUNTY-37</county>
<postcode xmlns="http://transferobject.com/xsd">Po12 123</postcode>
</address>
<basicDetails>
<currentFirstName xmlns="http://transferobject.com/xsd">John</currentFirstName>
<currentLastName xmlns="http://transferobject.com/xsd">Bloggs</currentLastName >
<currentStage xmlns="http://transferobject.com/xsd">H1</currentStage>
<currentGroup xmlns="http://transferobject.com/xsd">3</currentGroup>
<dob xmlns="http://transferobject.com/xsd">1999-04-25</dob>
<email xmlns="http://transferobject.com/xsd">AN#AN.AOM</email>
<entryDate xmlns="http://transferobject.com/xsd">2003-09-03</entryDate>
</basicDetails>
</personData>
</person>
</company>
</companys>
</header>
I know you're using XPath, but as you have an answer with XPath I'll give one using Linq
using System;
using System.Linq;
using System.Xml.Linq;
namespace xmlTest
{
class Program
{
static void Main()
{
XDocument doc = XDocument.Load("C:\\Users\\me\\Desktop\\so.xml");
var personDataDetails = (from p in doc.Descendants().Elements()
where p.Name.LocalName == "personData"
select p);
foreach (var item in personDataDetails)
{
Console.WriteLine(item.ToString());
}
Console.ReadKey();
}
}
}
Are you just asking how you can iterate through the personData nodes without listing the full path? If that's what you want to do, you can just do this:
XPathNodeIterator xni = xPathNav.Select("//g2:personData", nsmgr);

Insert the data of richtextbox into existing xml in c# linq

I have a xml like this:
<?xml version="1.0" encoding="utf-8"?>
<assessment xmlns="http://xml.thinkcentral.com/pub/xml/hsp/assessment" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:tia="http://xml.thinkcentral.com/pub/xml/hsp/tia" xmlns:tibase="http://xml.thinkcentral.com/pub/xml/hsp/tibase" xsi:schemaLocation="http://xml.thinkcentral.com/pub/xml/hsp/assessment http://xml.thinkcentral.com/pub/xml1_2_6/hsp_assessment.xsd" isbn="9780547660455" buid="NA12_AG_G01CH01A" title="Chapter 1 Test Form A" num_questions="24" num_sections="1" type="Basal" intervenable="true" duration="P5Y" pausable="false" scramble="false">
<test_section id="1" name="Chapter 1 Test Form A" index="1">
<aaa testitem_id="NA12_AG_G01CH01A_01" template="hsp_testitem_mc1.xslt" id="1" bankable="true">
<tia:multipleChoiceTestItem total-points="1" questionType="Multiple Choice" sample="false" version_label="1.0">
<tia:directions>
<tia:tiDirectionLine>
<tia:textBody></tia:textBody>
</tia:tiDirectionLine>
<tia:address>Richtextbox Data</tia:address>
</tia:directions>
</tia:multipleChoiceTestItem>
</aaa>
<aaa testitem_id="NA12_AG_G01CH01A_02" template="hsp_testitem_mc1.xslt" id="2" bankable="true">
<tia:multipleChoiceTestItem total-points="1" questionType="Multiple Choice" sample="false" version_label="1.0">
<tia:directions>
<tia:tiDirectionLine>
<tia:textBody></tia:textBody>
</tia:tiDirectionLine>
<tia:address>Richtextbox Data</tia:address>
</tia:directions>
</tia:multipleChoiceTestItem>
</aaa>
</test_section>
</assessment>
I have to insert the the data according to the id of the aaa element.
<aaa testitem_id="NA12_AG_G01CH01A_01" template="hsp_testitem_mc1.xslt" id="1" bankable="true">
<aaa testitem_id="NA12_AG_G01CH01A_02" template="hsp_testitem_mc1.xslt" id="2"bankable="true">
if id="1" then data of ritchtextbox will be insert into tia:address node.
i am using the following code.
private void button2_Click(object sender, EventArgs e)
{
XDocument doc = XDocument.Load(#"d:\file.xml");
XNamespace ns = XNamespace.Get("http://tia.com");
var result= (from ele in doc.Descendants("aaa")
where ((string)ele.Attribute("id")) == "1"
select ele.Element(ns+"address")).FirstOrDefault();
if (result != null)
{
result.Value = richTextBox1.Text;
doc.Save(#"d:\file.xml");
}
MessageBox.Show("done");
}
its not working. how i do that?
First of al, the XML markup you have posted is not valid. I think the easiest way to read/write an XML document is Linq-XML. You have to import System.Xml.Linq namespace to use XDocument class and its method. Take a look at MSDN article.
XDocument doc = XDocument.Load(#"c:\file.xml");
var result = (from ele in doc.Descendants("aaa")
where ((string)ele.Attribute("id")) == "1"
select ele.Element("address")).FirstOrDefault();
if (result != null)
{
result.Value = richTextBox1.Text;
doc.Save(#"c:\file.xml");
}
XML document should be:
<?xml version="1.0" encoding="utf-8"?>
<root>
<aaa id="1">
<address>Hello World</address>
</aaa>
<aaa id="2">
<address>
write text of ritchtextbox here</address>
</aaa>
</root>
EDIT:
In OP, XML markup has some issues and I've fixes the markup (added namespace).
<?xml version="1.0" encoding="utf-8"?>
<aaa testitem_id="chapter1" template="hsp_testitem_mc1.xslt" id="1" bankable="true" xmlns:tia="http://tia.com">
<tia:multipleChoiceTestItem total-points="1" questionType="Multiple Choice" sample="false" version_label="1.0">
<tia:directions>
<tia:tiDirectionLine>
<tia:textBody />
</tia:tiDirectionLine>
<tia:address>I have to edited here.(Richtextbox data)</tia:address>
</tia:directions>
</tia:multipleChoiceTestItem>
</aaa>
Code to find <tia:address> and replace its value.
XDocument doc = XDocument.Load(file);
XNamespace ns = XNamespace.Get("http://tia.com");
var result = (from ele in doc.Descendants(ns + "address")
select ele).SingleOrDefault();
if (result != null)
{
result.Value = richTextBox1.Text;
doc.Save(file);
}
EDIT : After changes made by OP in opening post.
XDocument doc = XDocument.Load(file);
//Change the namespace
XNamespace ns = XNamespace.Get("http://xml.thinkcentral.com/pub/xml/hsp/tia");
var result = (
from ele in doc.Descendants(ns + "multipleChoiceTestItem")
where ele.Parent.Attribute("id").Value == "1"
select
ele.Descendants(ns+"address").FirstOrDefault()
).FirstOrDefault();
if (result != null)
{
result.Value = "World";
doc.Save(file);
}

Categories

Resources