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
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" />
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?
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
}
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();
<?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;