Getting the previous node of a searched keyword in xml - c#

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.

Related

Join two children

I have this XML File:
<library>
<book ISBN="BSWE153" authors = "AC532" >
<title>Leraing XML</title>
<year>1995</year>
<publisher>W3C</publisher>
</book>
<author id="AC532">
<firstName>Hamdy</firstName>
<middleName/>
<lastName>Taha</lastName>
<nationality>Egypatian</nationality>
</author>
</library>
How to print the information of a book (with its authors information) given by its ISBN?
You can do that using XDocument, for example. You will need to
Parse your string (or load the file)
locate the book
read author Id (or ids?)
locate the author
nicely format it all together - with appropriate checks.
that is just a sketch:
const string xml = #"<?xml version=""1.0""?>
<library>
<book ISBN=""BSWE153"" authors = ""AC532"" >
<title>Leraing XML</title>
<year>1995</year>
<publisher>W3C</publisher>
</book>
<author id=""AC532"">
<firstName>Hamdy</firstName>
<middleName/>
<lastName>Taha</lastName>
<nationality>Egypatian</nationality>
</author>
</library>
";
var doc = XDocument.Parse(xml);
var book = doc.Root.Elements("book")
.FirstOrDefault(b => (string)b.Attribute("ISBN") == "BSWE153" );
var authorId = book.Attribute("authors").Value.ToString();
var author = doc.Root.Elements("author")
.FirstOrDefault(b => (string)b.Attribute("id") == authorId );
Console.WriteLine("{0} by {1} {2}",
book.Element("title").Value,
author.Element("firstName").Value,
author.Element("lastName").Value);

Create nodes from List<XElement> using linq

I want to create the following the xml
<BookStore>
<Book>
<Name></Name>
<Author></Author>
<Price></Price>
</Book>
<Book>
<Name></Name>
<Author></Author>
<Price></Price>
</Book>
</BookStore>
From
List<XElement> Book= xdoc.XPathSelectElements("s0:Name| s0:Author| s0:Price", namespaceManager).ToList();
I am struck in the following place :
XNamespace s0 = "urn:service.Bookstore.com";
XElement root=new XElement(s0 + "BookStore",
new XElement("Book",Book,
);
XDocument result = new XDocument(root);
But this gives the xml structure to be
<BookStore>
<Book>
<Name></Name>
<Author></Author>
<Price></Price>
<Name></Name>
<Author></Author>
<Price></Price>
</Book>
</BookStore>
Please help me in getting the expected output.Since the base xml structure looks like this
<BookStore>
<Book>
<Name></Name>
<Author></Author>
<Price></Price>
<Name></Name>
<Author></Author>
<Price></Price>
</Book>
</BookStore>
But I want it as two separate instances of
It sounds like you basically need to take the list of elements and group them into groups of 3 elements, putting each group in a Book element:
// The name/author/price elements you're already getting
var elements = ...;
var groups = elements.Select((value, index) => new { value, index })
.GroupBy(pair => pair.index / 3, pair => pair.value);
XNamespace s0 = "urn:service.Bookstore.com";
XDocument result = new XDocument(new XElement(s0 + "BookStore",
groups.Select(g => new XElement("Book", g))));
Try It:
XElement xElement = new XElement("BookStore", new XElement("Book", new XElement("Name", "value"), new XElement("Author", "value"), new XElement("Price", "value")));
xElement.Save("Location.xml");

How to get special data from xml file using 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.

How can i get the parent of node text value in c#?

I have the following xml:
<?xml version="1.0"?>
<catalog>
<book id="bk101">
<author>Gambardella, Matthew</author>
<title>XML Developer's Guide</title>
<genre>Computer</genre>
<price>44.95</price>
<publish_date>2000-10-01</publish_date>
<description>An in-depth look at creating applications
with XML.</description>
</book>
<book id="bk102">
<author>Ralls, Kim</author>
<title>Midnight Rain</title>
<genre>Fantasy</genre>
<price>5.95</price>
<publish_date>2000-12-16</publish_date>
<description>A former architect battles corporate zombies,
an evil sorceress, and her own childhood to become queen
of the world.</description>
</book>
</catalog>
I found the title named "Midnight Rain". Now i want to know who is his parent so that i can use the <author> text node. I tried something like:
var xpath = "../*[local-name() != 'title']";
xml.Load(xmlalltext);
var xl1 = xml.SelectNodes(xpath);
MessageBox.Show(xl1.Item(0).InnerText.ToString());
If you've already found the title node and you're looking for the parent node, you can just select the parent node of the current node.
var parentNode = titleNode.SelectSingleNode("..");
If you're looking for the author node:
var authorNode = titleNode.SelectSingleNode("../author");
Alternatively, you may look for preceding or following siblings:
var authorNode = titleNode.SelectSingleNode("following-sibling::author") ?? titleNode.SelectSingleNode("preceding-sibling::author");
Edit: To answer your comment, if you only have the string of the title, then you may use the following to get the author:
string xml = #"xml...";
var doc = XDocument.Parse(xml);
string author = doc
.Descendants("book")
.Where(x => x.Element("title").Value == "Midnight Rain")
.Select(x => x.Element("author").Value)
.FirstOrDefault();
using XLinq
sample.xml(in below snipped) contains xml data
XElement root = XElement.Parse(File.ReadAllText("sample.xml"));
var matchingBooks = root.Descendants().Where(i=>String.Equals(i.Value,"Midnight Rain")).Select(i=>i.Parent) ;
var authors = matchingBooks.Elements("author");
Output in LinqPad
matchingBooks.Dump();
authors.Dump();
<book id="bk102">
<author>Ralls, Kim</author>
<title>Midnight Rain</title>
<genre>Fantasy</genre>
<price>5.95</price>
<publish_date>2000-12-16</publish_date>
<description>A former architect battles corporate zombies,
an evil sorceress, and her own childhood to become queen
of the world.</description>
</book>
<author>Ralls, Kim</author>
You can use this xpath expession to get author node
"/catalog/book[title='Midnight Rain']/author"
or this to get parent node
"/catalog/book[title='Midnight Rain']"
eg.
var result = xml.SelectNodes(string.Format("/catalog/book[title='{0}']/author", "Midnight Rain"))

Reading XML file in C# with XpathNavigator

I am trying to read the book.xml file provided as an example on the MSDN website.
<?xml version="1.0" encoding="utf-8" ?>
<bookstore>
<book genre="autobiography" publicationdate="1981-03-22" ISBN="1-861003-11-0">
<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 genre="novel" publicationdate="1967-11-17" ISBN="0-201-63361-2">
<title>The Confidence Man</title>
<author>
<first-name>Herman</first-name>
<last-name>Melville</last-name>
</author>
<price>11.99</price>
</book>
<book genre="philosophy" publicationdate="1991-02-15" ISBN="1-861001-57-6">
<title>The Gorgias</title>
<author>
<name>Plato</name>
</author>
<price>9.99</price>
</book>
</bookstore>
I have the following code until now:
static void Main()
{
XmlDocument document = new XmlDocument();
document.Load(#"c:\books.xml");
XPathNavigator navigator = document.CreateNavigator();
XPathNodeIterator nodes = navigator.Select("/bookstore/book");
while (nodes.MoveNext())
{
Console.WriteLine(nodes.Current.HasAttributes);
}
}
It seems this code is reading everything, but from here on if I want to display, say, just the titles of all book etc., how do I access them?
You can iterate over the titles if you change the XPath expression to select all title nodes:
XPathDocument document = new XPathDocument(#"c:\tmp\smpl5.xml");
XPathNavigator navigator = document.CreateNavigator();
XPathNodeIterator nodes = navigator.Select("/bookstore/book/title");
foreach (XPathNavigator item in nodes)
{
Console.WriteLine(item.Value);
}
Note that you don't need to create an XmlDocument if you don't plan to modify the document. Using an XPathDocument is usually more light-weight.
you can also use this "//title" instead of "/bookstore/book"

Categories

Resources