XML Parsing in C# .net 4 - c#

I have following xml How can I read xml to get list of Sura nodes like this
var Suras = XMLNodes **//how to use xpath to load xmlnodes of sura**
foreach (var sura in suras)
{
var ayas = sura. **//how to use xpath to load xmlnodes of aya for this sura node**
}
XML
<?xml version="1.0" encoding="utf-8" ?>
<quran>
<sura index="1" name="الفاتحة">
<aya index="1" text="In the name of Allah, the Entirely Merciful, the Especially Merciful."/>
<aya index="2" text="[All] praise is [due] to Allah, Lord of the worlds -"/>
</sura>
<sura index="114" name="الناس">
<aya index="1" text="Say, "I seek refuge in the Lord of mankind,"/>
<aya index="2" text="The Sovereign of mankind."/>
<aya index="3" text="The God of mankind,"/>
<aya index="4" text="From the evil of the retreating whisperer -"/>
<aya index="5" text="Who whispers [evil] into the breasts of mankind -"/>
<aya index="6" text="From among the jinn and mankind.""/>
</sura>
</quran>

Do you particularly want to use XPath? I'd just use LINQ to XML:
XDocument doc = XDocument.Load("file.xml");
var suras = doc.Root.Elements("sura");
foreach (var sura in suras)
{
var ayas = suras.Elements("aya");
...
}

Related

Dynamically Creating LINQ Query to query XML Elements

I have an XML similar to below,
<?xml version="1.0" encoding="utf-8"?>
<body>
<Result>
<Students>
<Student>
<Firstname Value="Max" />
<LastName Value="Dean" />
</Student>
<Student>
<Firstname Value="Driz" />
<LastName Value="Jay" />
</Student>
</Students>
</Result>
</body>
I'm trying to figure out if its possible to write some code to dynamically build a Linq query from something like,
string pathToElements = "Result.Students.Student";
var individualItems = pathToElements.Split(".");
to something like,
XElement document = XElement.Parse(xml);
var evaluatedResult = document.Elements("Result")
.Elements("Students")
.Elements("Student")
.ToList();
basically the individualItems has 3 items "Result", "Students" and "Student". I'm exploring possible ways to create a dynamic query to accomplish something like,
document.Elements("Result")
.Elements("Students")
.Elements("Student")
.ToList();
For n number of Items I would just need to keep appending .Elements("") to the query.
Any advice on how to achieve this, my first instinct was to use a string builder and have the query as a string. I was able to do this but was not able to find out how a LINQ query which is in the form of a string can be executed.
Thanks in advance
You can query XML using XPath (it's a string so you can create it dynamically) then you can deserialize the item
https://learn.microsoft.com/en-us/troubleshoot/developer/dotnet/framework/general/query-xpathdocument-xpath-csharp
The output of this code
using System;
using System.Xml.XPath;
using System.IO;
public class Program
{
public static void Main()
{
var xml = #"<?xml version=""1.0"" encoding=""utf-8""?>
<body>
<Result>
<Students>
<Student>
<Firstname Value=""Max"" />
<LastName Value=""Dean"" />
</Student>
<Student>
<Firstname Value=""Driz"" />
<LastName Value=""Jay"" />
</Student>
</Students>
</Result>
</body>";
using (TextReader tr = new StringReader(xml))
{
var xdoc = new XPathDocument(tr);
var nav = xdoc.CreateNavigator();
var nodeIter = nav.Select("/body/Result/Students/Student");
while (nodeIter.MoveNext())
{
Console.WriteLine("Student: {0}", nodeIter.Current.InnerXml);
};
}
}
}
is
Student: <Firstname Value="Max" />
<LastName Value="Dean" />
Student: <Firstname Value="Driz" />
<LastName Value="Jay" />

Parsing XML file with LINQ getting wrong information

Im trying to parse an XML file from my program and I'm basing my code off this answer.
However the XML I'm using now is a bit more complex where I need to fill several nested lists with classes. Here are my two classes
public class Picture
{
private int mPicNumber;
private int mPicDuration;
private List<string> mToSay = new List<string>();
public Picture(int picNumber, int picDuration, List<string> toSay){...}
}
public class Sequence
{
string mName;
int mNumber;
List<Picture> mPictures = new List<Picture>();
public Sequence(string name, int number, List<Picture> pictures){...}
}
The XML looks like this
<sequences>
<sequence>
<name>Seq 2</name>
<number>1</number>
<picture>
<number>1</number>
<duration>5</duration>
<rows>
<text>text1</text>
<text>text2</text>
<text>text3</text>
</rows>
</picture>
<picture>
<number>2</number>
<duration>5</duration>
<rows>
<text>text1</text>
<text>text2</text>
<text>text3</text>
</rows>
</picture>
<picture>
<number>3</number>
<duration>5</duration>
<rows>
<text>text1</text>
<text>text2</text>
<text>text3</text>
</rows>
</picture>
</sequence>
<sequence>
<name>Seq 2</name>
<number>1</number>
<picture>
<number>1</number>
<duration>5</duration>
<rows>
<text>text1</text>
<text>text2</text>
<text>text3</text>
</rows>
</picture>
<picture>
<number>2</number>
<duration>5</duration>
<rows>
<text>text1</text>
<text>text2</text>
<text>text3</text>
</rows>
</picture>
<picture>
<number>3</number>
<duration>5</duration>
<rows>
<text>text1</text>
<text>text2</text>
<text>text3</text>
</rows>
</picture>
</sequence>
</sequences>
Here is the code for parsing the XML
XDocument xmlDoc = XDocument.Load("Sequences.xml");
List<Picture> pictures;
List<string> toSay;
mSequences = xmlDoc.Descendants("sequence").
Select(be => new Sequence(
(string)be.Element("name"),
(int)be.Element("number"),
pictures = xmlDoc.Descendants("picture").
Select(bf => new Picture(
(int)bf.Element("number"),
(int)bf.Element("duration"),
toSay = xmlDoc.Descendants("rows").
Select(bg =>
(String)bg.Element("text")).ToList())).ToList())).ToList();
After I run this I get a list with 2 Sequences (which is correct) and the name and number is correct. However Each sequence contain all 6 pictures from the XML file and those pictures doesn't contain anything from within the rows tag. I tried changing Descendants to Elements on the two inner lists but then I got 0 pictures in all sequences instead. I will admit I'm not very good at LINQ and this is very confusing to me.
The problem with your code is here pictures = xmlDoc.Descendants("picture"). & toSay = xmlDoc.Descendants("rows").. You are again querying the XML from the top rather you should be querying the already filtered data. You should use the instance variable be & bf respectively.
This will give you the expected output:-
var res = xdoc.Root.Elements("sequence")
.Select(be => new Sequence(
(string)be.Element("name"),
(int)be.Element("number"),
pictures = be.Elements("picture")
.Select(bf => new Picture(
(int)bf.Element("number"),
(int)bf.Element("duration"),
toSay = bf.Element("rows").Elements("text")
Select(bg =>
(String)bg).ToList()))
.ToList()))
.ToList();
Also, note how I have replaced Descendants with Elements. If you XML contains some inner node with same tag then you will get unexpected output.
pictures = xmlDoc.Descendants("picture")
It looks like you get the Pics from the whole document xmlDoc.Decendants,
but instead you need to get it for each be object I think. I can`t check it right now but i guess be.Decentans should be okay?

Extract a node from xml response

Below is my response generated from a webservice.
I want to do such that I want only PresentationElements node from this response.
Any help how can I achieve this query?
<?xml version="1.0"?>
<GetContentResponse xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<ExtensionData />
<GetContentResult>
<ExtensionData />
<Code>0</Code>
<Value>Success</Value>
</GetContentResult>
<PresentationElements>
<PresentationElement>
<ExtensionData />
<ContentReference>Product View Pack</ContentReference>
<ID>SHOPPING_ELEMENT:10400044</ID>
<Name>View Pack PE</Name>
<PresentationContents>
<PresentationContent>
<ExtensionData />
<Content>View Pack</Content>
<ContentType>TEXT</ContentType>
<Language>ENGLISH</Language>
<Medium>COMPUTER_BROWSER</Medium>
<Name>Name</Name>
</PresentationContent>
<PresentationContent>
<ExtensionData />
<Content>Have more control of your home's security and lighting with View Pack from XFINITY Home.</Content>
<ContentType>TEXT</ContentType>
<Language>ENGLISH</Language>
<Medium>COMPUTER_BROWSER</Medium>
<Name>Description</Name>
</PresentationContent>
<PresentationContent>
<ExtensionData />
<Content>/images/shopping/devices/xh/view-pack-2.jpg</Content>
<ContentType>TEXT</ContentType>
<Language>ENGLISH</Language>
<Medium>COMPUTER_BROWSER</Medium>
<Name>Image</Name>
</PresentationContent>
<PresentationContent>
<ExtensionData />
<Content>The View Pack includes:
2 Lighting / Appliance Controllers
2 Indoor / Outdoor Cameras</Content>
<ContentType>TEXT</ContentType>
<Language>ENGLISH</Language>
<Medium>COMPUTER_BROWSER</Medium>
<Name>Feature1</Name>
</PresentationContent>
</PresentationContents>
</PresentationElement>
</PresentationElements>
</GetContentResponse>
You can use XPath extensions
var xdoc = XDocument.Parse(response);
XElement presentations = xdoc.XPathSelectElement("//PresentationElements");
You may use the System.Xml.Linq.XDocument:
//Initialize the XDocument
XDocument doc = XDocument.Parse(yourString);
//your query
var desiredNodes = doc.Descendants("PresentationElements");
Pretty easy, have you tried:
XDocument xml = XDocument.Load("... xml");
var nodes = (from n in xml.Descendants("PresentationElements")
select n).ToList();
You could also project each individual node to an anonymous type using something like:
select new
{
ContentReference = (string)n.Element("ContentReference").Value,
.... etc
}

How to read data from xml file using linq to xml?

Trying to read this xml using Linq to XML
<Root>
<shelves>
<bookNumber>12</bookNumber>
<coverType unit="H">soft</coverType>
<pages>100</pages>
<Weight units="lb">1.2</Weight>
<chapter sample="1">example 1</<chapter>
<chapter sample="2">example 2</<chapter>
<chapter sample="3">example 3</<chapter>
<chapter sample="4">example 4</<chapter>
<chapter sample="5">example 5</<chapter>
<chapter sample="6">example 6</<chapter>
<chapter sample="7">example 7</<chapter>
<chapter .................</chapter>
<chapter .................</chapter>
<chapter .................</chapter>
<chapter .................</chapter>
<chapter .................</chapter>
..............
</shelves>
</Root>
Thats the code i am trying with:-. But How will read values all the elements 'Chapter'?
var book = from b in xml.Root.Elements("shelves")
select b;
foreach (var s in book)
{
booknumber = s.Element("bookNumber").Value,
covertype = s.Element("bookNumber").Value,
coverTypeUnit = s.Element("bookNumber").Attribute("unit").Value,
...........
chapter = s.Element("bookNumber").Value ????
}
You may find these links usefull:
linq-to-read-xml
101 LINQ Samples
var values = s.Elements("chapter").Select(n => n.Value).ToArray();
Furthermore, you're reading from the same element (booknumber) over and over. You might want to check your code.
EDIT: to also yield the attribute:
s.Elements("chapter").
Select(n => new {Topic = n.Attribute("topic").Value, Value = n.Value}).
ToArray();

How to extract a part of xml code from an xml file using c# code

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<eRecon xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:noNamespaceSchemaLocation="eRecon.xsd">
<Header>
<Company Code="" />
<CommonCarrierCode />
<InputFileName InputIDPk="">F:\ReconNew\TmesysRec20100111.rec</InputFileName>
<BatchNumber>000152</BatchNumber>
<InputStartDateTime>2010-02-26 11:47:00</InputStartDateTime>
<InputFinishDateTime>2010-02-26 11:47:05</InputFinishDateTime>
<RecordCount>8</RecordCount>
</Header>
<Detail>
<CarrierStatusDate>2010-01-11</CarrierStatusDate>
<ClaimNum>YDF02892 C</ClaimNum>
<InvoiceNum>0108013775</InvoiceNum>
<LineItemNum>001</LineItemNum>
<NABP>10600211</NABP>
<RxNumber>4695045</RxNumber>
<RxDate>2008-07-21</RxDate>
<CheckNum />
<PaymentStatus>PENDING</PaymentStatus>
<RejectDescription />
<InvoiceChargeAmount>152.15</InvoiceChargeAmount>
<InvoicePaidAmount>131.00</InvoicePaidAmount>
</Detail>
</eRecon>
How can I extract the portion
<Header>
<Company Code="" />
<CommonCarrierCode />
<InputFileName InputIDPk="">F:\ReconNew\TmesysRec20100111.rec</InputFileName>
<BatchNumber>000152</BatchNumber>
<InputStartDateTime>2010-02-26 11:47:00</InputStartDateTime>
<InputFinishDateTime>2010-02-26 11:47:05</InputFinishDateTime>
<RecordCount>8</RecordCount>
</Header>
from the above xml file.
I need the c# code to extract a part of xml tag from an xml file.
If the file isn't too big (smaller than a few MB), you can load it into an XmlDocument:
XmlDocument doc = new XmlDocument();
doc.Load(#"C:\yourfile.xml");
and then you can parse for the <Header> element using an XPath expression:
XmlNode headerNode = doc.SelectSingleNode("/eRecon/Header");
if(headerNode != null)
{
string headerNodeXml = headerNode.OuterXml;
}
You can use XPath like in this tutorial:
http://www.codeproject.com/KB/cpp/myXPath.aspx
Use Linq-to-xml:
XDocument xmlDoc = XDocument.Load(#"c:\sample.xml");
var header = xmlDoc.Descendants("Header").FirstOrDefault();
Linq version
string fileName=#"d:\xml.xml";
var descendants = from i in XDocument.Load(fileName).Descendants("Header")
select i;

Categories

Resources