How to convert xml string to an object using c# - c#

I am using WebRequest and WebReponse classes to get a response from a web api. The response I get is an xml of the following format
<?xml version="1.0" encoding="UTF-8"?>
<ROOT>
<A></A>
<B></B>
<C></C>
<D>
<E NAME="aaa" EMAIL="a#a.com"/>
<E NAME="bbb" EMAIL="b#b.com"/>
</D>
</ROOT>
I want to get all the E elements as a List<E> or something.
Can some one guide me on this pls.

if you want to avoid serialization, as you only want a very specific part of the xml, you can do this with one LINQ statement:
var items = XDocument.Parse(xml)
.Descendants("E")
.Select(e => new
{
Name = e.Attribute("NAME").Value,
Email = e.Attribute("EMAIL").Value
})
.ToList();

Working example:
var doc = XDocument.Parse(#"<?xml version='1.0' encoding='UTF-8'?>
<ROOT>
<A></A>
<B></B>
<C></C>
<D>
<E NAME='aaa' EMAIL='a#a.com'/>
<E NAME='bbb' EMAIL='b#b.com'/>
</D>
</ROOT>");
var elements = from el in doc.Elements()
from el2 in el.Elements()
from el3 in el2.Elements()
where el3.Name == "E"
select el3;
foreach (var e in elements)
{
Console.WriteLine(e);
}

Related

Unable to parse xml string using Xdocument and Linq

I would like to parse the below xml using XDocument in Linq.
<?xml version="1.0" encoding="UTF-8"?>
<string xmlns="http://tempuri.org/">
<Sources>
<Item>
<Id>1</Id>
<Name>John</Name>
</Item>
<Item>
<Id>2</Id>
<Name>Max</Name>
</Item>
<Item>
<Id>3</Id>
<Name>Ricky</Name>
</Item>
</Sources>
</string>
My parsing code is :
var xDoc = XDocument.Parse(xmlString);
var xElements = xDoc.Element("Sources")?.Elements("Item");
if (xElements != null)
foreach (var source in xElements)
{
Console.Write(source);
}
xElements is always null. I tried using namespace as well, it did not work. How can I resolve this issue?
Try below code:
string stringXml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><string xmlns=\"http://tempuri.org/\"><Sources><Item><Id>1</Id><Name>John</Name></Item><Item><Id>2</Id><Name>Max</Name></Item><Item><Id>3</Id><Name>Ricky</Name></Item></Sources></string>";
XDocument xDoc = XDocument.Parse(stringXml);
var items = xDoc.Descendants("{http://tempuri.org/}Sources")?.Descendants("{http://tempuri.org/}Item").ToList();
I tested it and it correctly shows that items has 3 lements :) Maybe you used namespaces differently (it's enough to inspect xDoc objct in object browser and see its namespace).
You need to concatenate the namespace and can directly use Descendants method to fetch all Item nodes like:
XNamespace ns ="http://tempuri.org/";
var xDoc = XDocument.Parse(xmlString);
var xElements = xDoc.Descendants(ns + "Item");
foreach (var source in xElements)
{
Console.Write(source);
}
This prints on Console:
<Item xmlns="http://tempuri.org/">
<Id>1</Id>
<Name>John</Name>
</Item><Item xmlns="http://tempuri.org/">
<Id>2</Id>
<Name>Max</Name>
</Item><Item xmlns="http://tempuri.org/">
<Id>3</Id>
<Name>Ricky</Name>
</Item>
See the working DEMO Fiddle

How to get enclosure url with XElement C# Console

I read multiple feed from many sources with C# Console, and i have this code where i load XML From sources:
XmlDocument doc = new XmlDocument();
doc.Load(sourceURLX);
XElement xdoc = XElement.Load(sourceURLX);
How to get enclosure url and show as variable?
If I understand your question correctly (I'm making a big assumption here) - you want to select an attribute from the root (or 'enclosing') tag, named 'url'?
You can make use of XPath queries here. Consider the following XML:
<?xml version="1.0" encoding="utf-8"?>
<root url='google.com'>
<inner />
</root>
You could use the following code to retrieve 'google.com':
String query = "/root[1]/#url";
XmlDocument doc = new XmlDocument();
doc.Load(sourceURLX);
String value = doc.SelectSingleNode(query).InnerText;
Further information about XPath syntax can be found here.
Edit: As you stated in your comment, you are working with the following XML:
<item>
<description>
</description>
<enclosure url="blablabla.com/img.jpg" />
</item>
Therefore, you can retrieve the url using the following XPath query:
/item[1]/enclosure[1]/#url
With xml like below
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
<channel>
<title>title</title>
<link>https://www.link.com</link>
<description>description</description>
<item>
<title>RSS</title>
<link>https://www.link.com/xml/xml_rss.asp</link>
<description>description</description>
<enclosure url="https://www.link.com/media/test.wmv"
length="10000"
type="video/wmv"/>
</item>
</channel>
</rss>
You will get url by reading attribute
var document = XDocument.Load(sourceURLX);
var url = document.Root
.Element("channel")
.Element("item")
.Element("enclosure")
.Attribute("url")
.Value;
To get multiple urls
var urls = document.Descendants("item")
.Select(item => item.Element("enclosure").Attribute("url").Value)
.ToList();
Using foreach loop
foreach (var item in document.Descendants("item"))
{
var title = item.Element("title").Value;
var link = item.Element("link").Value;
var description = item.Element("description").Value;
var url = item.Element("enclosure").Attribute("url").Value;
// save values to database
}

How to read in some XML then split out various nodes/elements in .NET?

I have some xml (in a file, but can be a string) which I need to parse, e.g.:
var xmlDocument = new XmlDocument();
xmlDocument.LoadXml(xmlText);
Given the following XML:
<foo>
<cat>...</cat>
<cat>...</cat>
<dog>...</dog>
<cat>...</cat>
<dog>...</dog>
</foo>
I'm not sure how I can extract all the cat and dog elements and put them into the following output :-
<foo>
<cat>...</cat>
<cat>...</cat>
....
</foo>
and the same with dogs.
What's the trick to extract those nodes and put them into separate XMLDocuments.
Use Linq to XML as it has a much nicer API.
var doc = XElement.Parse(
#"<foo>
<cat>...</cat>
<cat>...</cat>
<dog>...</dog>
<cat>...</cat>
<dog>...</dog>
</foo>");
doc.Descendants("dog").Remove();
doc now contains this:
<foo>
<cat>...</cat>
<cat>...</cat>
<cat>...</cat>
</foo>
Edit:
While Linq to XML itself provides a nice API to work with XML, the power of Linq and its projection capabilities enables you to shape your data as you see fit.
Consider this, for example. Here the descendant elements are grouped by name and projected into a new root element which is then wrapped into a XDocument. Note that this creates an enumerable of XDocument.
var docs=
from d in doc.Descendants()
group d by d.Name into g
select new XDocument(
new XElement("root", g)
);
docs now contains:
<root>
<cat>...</cat>
<cat>...</cat>
<cat>...</cat>
</root>
---
<root>
<dog>...</dog>
<dog>...</dog>
</root>
Oh, by the way. The Descendants method goes through all descendant elements, use Elements if you only want the immediate child elements.
Here are the Linq to XML docs on MSDN
The easiest way will be to use XSLT and apply it on you XMLDocument in such way you won't modify your source and have as much outputs as you need.
The code for applying transform is
XslCompiledTransform xslTransform = new XslCompiledTransform();
StringWriter writer = new StringWriter();
xslTransform.Load("cat.xslt");
xslTransform.Transform(doc.CreateNavigator(),null, writer);
return writer.ToString();
And the simple cat.xslt is
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="foo">
<xsl:copy>
<xsl:copy-of select = "cat" />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Since you are using XmlDocument: Load it twice from the same file and remove the unwanted nodes. Here is a link that shows you how: Removing nodes from an XmlDocument.
var xmlDocument = new XmlDocument();
xmlDocument.LoadXml(xmlText);
XmlNode root = doc.DocumentElement;
nodeList = root.SelectNodes("//cat");
foreach (XmlNode node on nodeList)
{
root.RemoveChild(node);
}

How do I read all XML nodes of a specific name and put them into an array (or list)?

I have an XML:
<?xml version="1.0" encoding="UTF-8"?>
<ticket>
<comments type="array">
<comment>
<attachments type="array">
<attachment>
<url>I NEED WHATEVER IS IN HERE</url>
</attachment>
</attachments>
</comment>
<comment>
<attachments type="array">
<attachment>
<url>I NEED WHATEVER IS IN HERE</url>
</attachment>
</attachments>
<comment>
</comments>
</ticket>
How would I go about getting whatever is inside the URL tag and add it to a <List>? I'm using C#.
Use:
var result = XDocument.Parse(inputXml)
.DescendantNodes().OfType<XText>().Select(e => e.Value).ToList();
Or using XPath:
var result = ((IEnumerable)XDocument.Parse(input).XPathEvaluate("//text()"))
.Cast<XText>().ToList();
To retrieve text only from url element use:
var result = XDocument.Parse(inputXml)
.Descendants("url").Select(e => e.Value).ToList();
or change above XPath: //url/text()
using (StringReader sr = new StringReader(xml_content))
{
XDocument xdoc = XDocument.Load(sr);
IList<string> values = xdoc.XPathSelectElements("ticket/comments/attachments/url").Select(e => e.Value).ToList();
}
Or, based on your use case in your comment:
var doc = new XmlDocument();
doc.LoadXml(xml_content);
IList<string> values = doc.SelectNodes("ticket/comments/attachments/url")
.Cast<XmlElement>().Select(e => e.InnerText).ToList();
Or you can use var values = xdoc.SelectSingleNode("ticket/comments/attachments/url").InnerXml;

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