How to get special data from xml file using c# - c#

Hi all
I have a xml file:
<bookstore>
<book category="COOKING">
<title lang="en">Everyday Italian</title>
<author>Giada De Laurentiis</author>
<year>2005</year>
<price>30.00</price>
</book>
<book category="CHILDREN">
<title lang="en">Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price>30</price>
</book>
<book category="CHILDREN">
<title lang="en">abc</title>
<author>bcd</author>
<year>2006</year>
<price>29</price>
</book>
<book category="WEB">
<title lang="en">Learning XML</title>
<author>Erik T. Ray</author>
<year>2003</year>
<price>39.95</price>
</book>
</bookstore>
How to I can get price list when category = "CHILDREN"? I using C#.
example: Output is : price of Harry Potter is 30 and price of abc is 29
Thank,

You can use LINQ to XML. Following code will return collection of anonymous type instances with all data from your XML:
var xDoc = XDocument.Load("Input.txt");
var books = xDoc.Root
.Elements("book")
.Where(b => (string)b.Attribute("category") == "CHILDREN")
.Select(b => new
{
Title = (string)b.Element("title"),
Author = (string)b.Element("author"),
Year = (int)b.Element("year"),
Price = (decimal)b.Element("price")
});
You can call .First() method on books to get only one/first found item.

Related

Removing parent node from xml collections

I am trying to get rid of the parent node of a collection in xml (using linq-to-xml):
For example, the input xml:
<envelop>
<books>
<book>
<title>ABC</title>
<publishedDate>2012-12-12</publishedDate>
<authors>
<author>John Smith</author>
<author>Bob Doe</author>
</authors>
<book>
<book>
<title>XYZ</title>
<publishedDate>2013-03-06</publishedDate>
<authors>
<author>Henry Blah</author>
<author>Bob Doe</author>
</authors>
<book>
</books>
</envelop>
I would like the result to be:
<envelop>
<book>
<title>ABC</title>
<publishedDate>2012-12-12</publishedDate>
<author>John Smith</author>
<author>Bob Doe</author>
<book>
<book>
<title>XYZ</title>
<publishedDate>2013-03-06</publishedDate>
<author>Henry Blah</author>
<author>Bob Doe</author>
<book>
</envelop>
The nodes: <books> and <authors> are gone - only their children remain.
I saw the following question but with XSLT (Remove parent nodes from xml with xslt). Would like to stay away from XSLT at the moment.
var document = XDocument.Load(validXmlFilePath);
while (document.Descendants("authors").Any())
{
var x = document.Descendants("authors").First();
x.AddAfterSelf(x.Nodes());
x.Remove();
}
var result = document.Descendants("book");
Do you fill your object in code and than serialize it? If so, you can use [XmlElement("Book")] attribute above your list property in your class:
[XmlElement("Book")]
public List<Book> Books {get; set;}
In VB the code would be
Dim result As XElement = <envelop></envelop>
result.Add(xe...<book>)
For Each el As XElement In result...<author>.ToList
el.Parent.Parent.Add(New XElement(el))
Next
result...<authors>.Remove()
with xe defined as
Dim xe As XElement
'to load from a file
' xe = XElement.Load("Your Path Here")
' for testing
xe = <envelop>
<books>
<book>
<title>ABC</title>
<publishedDate>2012-12-12</publishedDate>
<authors>
<author>John Smith</author>
<author>Bob Doe</author>
</authors>
</book>
<book>
<title>XYZ</title>
<publishedDate>2013-03-06</publishedDate>
<authors>
<author>Henry Blah</author>
<author>Bob Doe</author>
</authors>
</book>
</books>
</envelop>
result looks like
<envelop>
<book>
<title>ABC</title>
<publishedDate>2012-12-12</publishedDate>
<author>John Smith</author>
<author>Bob Doe</author>
</book>
<book>
<title>XYZ</title>
<publishedDate>2013-03-06</publishedDate>
<author>Henry Blah</author>
<author>Bob Doe</author>
</book>
</envelop>

return the same XML Doc structure with specific conditions in XPath

I have xml document similar to xml in page http://www.w3schools.com/xml/xml_xpath.asp
<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
<book category="cooking">
<title lang="en">Everyday Italian</title>
<author>Giada De Laurentiis</author>
<year>2005</year>
<price>30.00</price>
</book>
<book category="children">
<title lang="en">Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
<book category="web">
<title lang="en">XQuery Kick Start</title>
<author>James McGovern</author>
<author>Per Bothner</author>
<author>Kurt Cagle</author>
<author>James Linn</author>
<author>Vaidyanathan Nagarajan</author>
<year>2003</year>
<price>49.99</price>
</book>
<book category="web">
<title lang="en">Learning XML</title>
<author>Erik T. Ray</author>
<year>2003</year>
<price>39.95</price>
</book>
</bookstore>
the problem is how to return this document with elements corresponding to a certain value? how to XPath or XQuery command should be written ?
for example search for title contains 'Learning' then the return xml doc should be like:
<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
<book category="web">
<title lang="en">Learning XML</title>
<author>Erik T. Ray</author>
<year>2003</year>
<price>39.95</price>
</book>
</bookstore>
how to get this result?
another question how to search with ignoring characters case, so 'learNING' should return the same result?
Using XQuery you can do as follow :
<bookstore>
{
for $d in //book[contains(lower-case(title),'learning')]
return $d
}
</bookstore>
Xpathtester Demo
Notice that there will be only one <bookstore> that wraps all matched <book> elements returned, and notice the use of lower-case() function to 'ignore' character case of the book title in the matching process.
Use 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);
List<XElement> book = doc.Descendants("book").Where(x => x.Element("title").Value.Contains("Learn")).ToList();
XDocument filteredDoc = XDocument.Parse("<?xml version=\"1.0\" encoding=\"UTF-8\"?><bookstore></bookstore>");
XElement root = (XElement)filteredDoc.FirstNode;
root.Add(book);
}
}
}​
for $d in doc('books')//book[title[contains(text(),'Beginning')]]
return <bookstore> {$d} </bookstore>
However this solution does not handle ignoring character case.

XML Parsing in windows phone

I have to parse XML,for that have used some code that's working but problem is not we have nested XML this code is unable to parse all data.So please suggest me how to part this.
XML
<Author>
<Book id="101" name="Computer" subcategories="2">
<Book id="600" name="java" subcategories="0" contents="10 books"/>
<Book id="601" name="php" subcategories="0" contents="5 books"/>
</Book>
<Book id="201" name="Language" subcategories="2">
<Book id="700" name="Hindi" subcategories="0" contents="6 books"/>
<Book id="701" name="English" subcategories="0" contents="4 books"/>
</Book>
<Book id="301" name="Music" subcategories="2">
<Book id="800" name="life" subcategories="0" contents="10 books"/>
<Book id="801" name="Wild" subcategories="0" contents="5 books"/>
</Book>
<Book id="401" name="Story" subcategories="2">
<Book id="900" name="My Life" subcategories="0" contents="1 books"/>
<Book id="901" name="One Day" subcategories="0" contents="1 books"/>
</Book>
</Author>
Parser method:
public void parser()
{
XElement nodes = XElement.Load("file.xml");
var node = from nd in nodes.DescendantNodes() select nd;
foreach (XElement nds in node)
{
string name = nds.Attribute("name").Value;
int id=Convert.ToInt32(nds.Attribute("id").Value);
MessageBox.Show("" + name);
MessageBox.Show("" + id);
if (nds.HasElements)
{
getChild(nds.DescendantNodes(),id);
}
}
public void getChild(IEnumerable<XNode> node,int id)
{
foreach (XElement nds in node)
{
IEnumerable<XNode> nd=from list in nds.DescendantNodes() select list;
int temp = Convert.ToInt32(ids);
foreach (XElement ss in nd)
{
string name = ss.Attribute("name").Value;
MessageBox.Show("" + name);
}
if (nds.HasElements)
{
getChild(nds.DescendantNodes(),id);
}
}
}
I have above XML and have used above code for parse.
Perhaps you're looking for this:
XElement doc = XElement.Parse(#"<Author>
<Book id=""101"" name=""Computer"" subcategories=""2"">
<Book id=""600"" name=""java"" subcategories=""0"" contents=""10 books""/>
<Book id=""601"" name=""php"" subcategories=""0"" contents=""5 books""/>
</Book>
<Book id=""201"" name=""Language"" subcategories=""2"">
<Book id=""700"" name=""Hindi"" subcategories=""0"" contents=""6 books""/>
<Book id=""701"" name=""English"" subcategories=""0"" contents=""4 books""/>
</Book>
<Book id=""301"" name=""Music"" subcategories=""2"">
<Book id=""800"" name=""life"" subcategories=""0"" contents=""10 books""/>
<Book id=""801"" name=""Wild"" subcategories=""0"" contents=""5 books""/>
</Book>
<Book id=""401"" name=""Story"" subcategories=""2"">
<Book id=""900"" name=""My Life"" subcategories=""0"" contents=""1 books""/>
<Book id=""901"" name=""One Day"" subcategories=""0"" contents=""1 books""/>
</Book>
</Author>");
var query = doc.Descendants();
foreach(XElement ele in query){
Console.WriteLine(string.Format("Name: {0}\nValue: {1}\n",ele.Name.LocalName.ToString(),ele));
if (ele.HasAttributes){
var query1 = ele.Attributes();
foreach (XAttribute att in query1)
{
Console.WriteLine(string.Format("Attribute: {0}\nValue: {1}\n", att.Name.LocalName.ToString(), att.Value));
};
};
};

Getting the previous node of a searched keyword in xml

I have an xml document like the following:
<bookstore>
<book>
<title>The Autobiography of Benjamin Franklin</title>
<author>
<first-name>Benjamin</first-name>
<last-name>Franklin</last-name>
</author>
<price>8.99</price>
</book>
<book>
<title>Zen and the Art of Motorcycle Maintenance</title>
<author>
<first-name>Robert</first-name>
<last-name>Pirsig</last-name>
</author>
<price>5.99</price>
</book>
<book>
<title>Other Cities</title>
<author>
<first-name>Benjamin</first-name>
<last-name>Rosenbaum</last-name>
</author>
<price>9.99</price>
</book>
</bookstore>
Of course, the bookstore has more than one book, so I I want to search for an author and then get returned an XElement for the book node that contains the searched author name.
var document = XDocument.Parse(xml);
var bookElements = document.Descendants("book")
.Where(arg => arg.Element("author").Element("first-name").Value == "Benjamin")
.ToList();
or
var bookElements = document.Descendants("first-name")
.Where(arg => arg.Value == "Benjamin")
.Select(arg => arg.Parent.Parent)
.ToList();
[Edit] As you keep editing the question, I will edit the answer :).
To find the first book that meets the criteria:
var foundBookElement = document.Descendants("book")
.Where(arg => arg.Element("author").Element("first-name").Value == "Benjamin")
.FirstOrDefault();
foundBookElement will be null if none of the books match the criteria.

C# How to extract complete xml node set

<?xml version="1.0" encoding="ISO-8859-1"?>
<bookstore>
<book category="COOKING">
<title lang="en">Everyday Italian</title>
<author>Giada De Laurentiis</author>
<year>2005</year>
<price>30.00</price>
</book>
<book category="CHILDREN">
<title lang="en">Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
<book category="WEB">
<title lang="en">XQuery Kick Start</title>
<author>James McGovern</author>
<author>Per Bothner</author>
<author>Kurt Cagle</author>
<author>James Linn</author>
<author>Vaidyanathan Nagarajan</author>
<year>2003</year>
<price>49.99</price>
</book>
<book category="WEB">
<title lang="en">Learning XML</title>
<author>Erik T. Ray</author>
<year>2003</year>
<price>39.95</price>
</book>
</bookstore>
Is their any way using XPath to select the complete first node set, for example from
<book category="COOKING">
to
</book>,
so that, that chunk of xml can be stored for later use.
Bob.
Let's say this XML is stored in an XmlDocument called doc.
XmlElement docRoot = doc.DocumentElement;
XmlNode cookingNode = docRoot.SelectSingleNode("./book[#category='COOKING']");
I tested this and added this line to verify:
Console.WriteLine(cookingNode.OuterXml);
Here was the output:
<book category="COOKING"><title lang="en">Everyday Italian</title><author>Giada
De Laurentiis</author><year>2005</year><price>30.00</price></book>
This query will select that node. Are you trying to get a set of nodes or just the single one? You might have to put the bookstore node back yourself if you only want th subset of nodes.
/bookstore/book[#category='COOKING']
as XmlDocument ...
var x = new XmlDocument();
x.Load("XmlFile1.xml");
var ns = x.SelectSingleNode("/bookstore/book[#category='COOKING']");
var res = ns.OuterXml;
as XDocument ...
var x = XDocument.Load("XmlFile1.xml");
var root = new XElement("bookstore",
from book in x.Element("bookstore").Elements("book")
where book.Attribute("category").Value == "COOKING"
select book
);
if you just want the book node you can do this instead of the root version above
var book = x.Element("bookstore")
.Elements("book")
.Where(n => n.Attribute("category").Value == "COOKING")
.First();
suppose I want to extract only the data wherethe xml file is as follows ..
<book category="COOKING">
<title lang="en">Everyday Italian</title>
<author auth="up">Giada De Laurentiis</author>
<year>2005</year>
<price>30.00</price>
</book>
the final result on the list view should look like this
lang auth
en up
I have coded as follows ..
XmlNodeList elemList = doc.GetElementsByTagName("book");
for (int j = 0; j < elemList.Count; j++)
{
if (elemList[j].Attributes["category"].Value == "COOKING")
{
XmlNodeList elemList1 = doc.GetElementsByTagName("author");
for (int i = 0; i < elemList1.Count; i++)
{
string attrVal = elemList1[i].Attributes["lang"].Value;
string attrVal1 = elemList1[i].Attributes["auth"].Value;
ListViewItem lvi = new ListViewItem();
lvi.SubItems.Add(attrVal1);
lvi.SubItems.Add(attrVal1);
}
listView1.Items.Add(lvi);
}
}
}
Adding to Matthew's response:
XmlDocument xDoc = new XmlDocument();
// (Put code to populate xDoc here)
XmlNodeList xNode = xDoc.SelectNodes(#"/bookstore/book[#category='COOKING']");
xNode now equals Book of type COOKING.

Categories

Resources