Xml decendants for a Xml node - c#

Here is a simplified mxl structure 'xml',
<store>
<book_1>
<author_1><name>Alice</name><age>30</age></author_1>
<author_2><name>Bob</name><age>31</age></author_2>
<book_1>
<author_1><name>Charley</name><age>29</age></author_1>
<author_2><name>Dory</name><age>25</age></author_2>
<book_1>
</store>
Here is what I tried;
XmlDocument submission = new XmlDocument();
submission.LoadXml(xml);
var bookNodes = submission.SelectNodes("//*[starts-with(local-name(),'book_')]");
This gives me a list of books.
foreach (XmlNode book in bookNodes)
{
//I want to do something like to find book authors for the book in context e.g. for the first book I just want nodes for Alice and Bob.
// var bookAuthors = book.SelectNodes("decendants::[starts-with(local-name(),'author_')");
}
How can I just do a starts with to check on decendent elements?
EDIT:
Seems like it's a typo...
var bookAuthors = book.SelectNodes("descendant::*[starts-with(local-name(),'MeritCriterion_')]");

You can access your descendant nodes by using the following XPath syntax:
XmlDocument submission = new XmlDocument();
submission.LoadXml(xml);
var bookNodes = submission.SelectNodes("//*[starts-with(local-name(),'book_')]");
foreach (XmlNode book in bookNodes)
{
var author = book.SelectNodes("descendant::*[starts-with(local-name(),'author_')]");
foreach (XmlNode authorInfo in author)
{
Console.WriteLine(authorInfo .InnerText);
}
}
In short, you need to access descendant::(all)[starts-with] or else you're just trying to access no descendant in your XPath. :)

Related

Fetching XML child values in c#

I have some data i need to fetch from a xml file.
<book category="cooking">
<title lang="en">Everyday Italian</title>
<author>Giada De Laurentiis</author>
<year>2005</year>
<price>30.00</price>
</book>
How would I fetch the year based of the category?
So it would be like
writeline( FetchYearFromCategory("cooking") );
and it would output 2005
Hope you can understand
You can use LINQ to Xml
// Load xml in the memory
var document = XDocument.Load(pathToXmlFile);
// Filter xml to find required data
var yearsOfCooking =
document.Descendants("book")
.Where(book => book.Attribute("category").Value == "cooking")
.Select(book => book.Element("year").Value);
// Print result
foreach (var year in yersOfCooking)
{
Console.WriteLine(year);
}
The tool you are looking for is called XPath. You can define which elements are going to match using a relatively easy syntax. W3Schools has a pretty good tutorial, if you are not already familiar with it. Here is the link.
The syntax to use it would be:
// This will fetch all "book" items in the root node
// that have the category = "cooking"
// and select their year node.
var strXPathExpression = "/book[#category='cooking']/year";
var doc = new XmlDocument();
doc.Load("YourXmlFile.xml");
var root = doc.DocumentElement;
var desiredNodes = root.SelectNodes(strXPathExpression).
foreach (var node in desiredNodes)
{
// You have your year here
var year = node.Value;
}
You can use System.Xml to access XML Files in C#.NET
public int FetchYearFromCategory(string category){
XmlDocument doc = new XmlDocument();
doc.Load("path_to_your_file");
XmlNodeList allBooks = doc.GetElementsByTagName("book");
foreach (XmlNode singleBookNode in allBooks)
{
if(singleBookNode.Attributes["category"] != null && singleBookNode.Attributes["category"].Value.Equals(category))
{
XmlNodeList childNodes = singleBookNode.ChildNodes;
foreach (XmlNode childNode in childNodes)
{
if(childNode.Name.Equals("year"))
{
return Int32.Parse(childNode.InnerText);
}
}
}
}
return -1;}
I think the above should do you the job.

get grandson text using xml document in c#

I'm using XmlDocument in C# and I would like to know how to get grandson data of the root?
<tRoot>
<One>
<a>15</a>
<b>11</b>
<c>1</c>
<d>11.35</d>
<e>0</e>
<f>289</f>
</One>
<Two>
<a>0</a>
<b>11</b>
<c>1</c>
<d>0.28</d>
<e>0</e>
<f>464</f>
</Two>
</tRoot>
and I want the ability to get a of One and also a of Two
I tried:
var doc = new XmlDocument();
doc.Load(Consts.FileConst);
var docXml = doc["One"];
if (docXml != null)
{
float valFromXml = float.Parse(docXml["a"].InnerText);
}
The issue is that docXml is null
Any assitance?
As suggested above, XDocument would be a better alternative. If, however, you still want to use XmlDocument, you can iterate through the children using
var doc = new XmlDocument();
doc.Load(Consts.FileConst);
foreach(XmlNode xmlNode in doc.DocumentElement.ChildNodes) {
//access a/b/c/d/e using:
xmlNode.ChildNodes[0].InnerText; //for a
xmlNode.ChildNodes[1].InnerText; //for b
}
Try this:
XmlDocument d = new XmlDocument();
d.LoadXml("<tRoot><One><a>15</a><b>11</b><c>1</c><d>11.35</d><e>0</e><f>289</f></One><Two><a>0</a><b>11</b><c>1</c><d>0.28</d><e>0</e><f>464</f></Two></tRoot>");
XmlNodeList itemNodes = d.SelectNodes("//*/a");

Selecting value from first xml child node

I have an XML file that contains multiple URLs for different image file sizes, and I'm trying to get a single url to load into a picture box. My issue is that the child nodes are named similarly, and the parent nodes are named similarly as well. For example, I want to pull the first medium image (ending in SL160_.jpg). See below for XML code
<Items>
<SmallImage>
<URL>http://ecx.images-amazon.com/images/I/51TAL%2Bn7AqL._SL75_.jpg</URL>
</SmallImage>
<MediumImage>
<URL>http://ecx.images-amazon.com/images/I/51TAL%2Bn7AqL._SL160_.jpg</URL>
</MediumImage>
<LargeImage>
<URL>http://ecx.images-amazon.com/images/I/51TAL%2Bn7AqL.jpg</URL>
</LargeImage>
<MediumImage>
<URL>http://ecx.images-amazon.com/images/I/51TAL%2Bn7AqL._SL162_.jpg</URL>
</MediumImage>
<LargeImage>
<URL>http://ecx.images-amazon.com/images/I/51TAL%2Bn7AqL.jpg</URL>
</LargeImage>
</Items>
I've tried using GetElementsByTag, as well as trying to call something like doc.SelectSingleNode("LargeImage").SelectSingleNode("URL").InnerText, and GetElementByID. All of these have given me an Object set to null reference exception.
What can I do to specify that I want the url from the first found MediumImage node?
Use LinqToXMLïĵŒIt is rather simple
string xml = #"<Items>
<SmallImage>
<URL>http://ecx.images-amazon.com/images/I/51TAL%2Bn7AqL._SL75_.jpg</URL>
</SmallImage>
<MediumImage>
<URL>http://ecx.images-amazon.com/images/I/51TAL%2Bn7AqL.01_SL160_.jpg</URL>
</MediumImage>
<LargeImage>
<URL>http://ecx.images-amazon.com/images/I/51TAL%2Bn7AqL.jpg</URL>
</LargeImage>
<MediumImage>
<URL>http://ecx.images-amazon.com/images/I/51TAL%2Bn7AqL.02_SL162_.jpg</URL>
</MediumImage>
<LargeImage>
<URL>http://ecx.images-amazon.com/images/I/51TAL%2Bn7AqL.jpg</URL>
</LargeImage>
</Items>";
XElement root = XElement.Parse(xml);
var ele = root.Elements("MediumImage").Where(e => e.Element("URL").Value.EndsWith("SL160_.jpg")).FirstOrDefault();
Console.WriteLine(ele);
In addition to Sky Fang's answer, I think the OP wants this:
var firstMedImg = root.Elements("MediumImage").First();
var imgUrl = firstMedImg.Element("URL").Value;
XmlDocument doc = new XmlDocument();
// PATH TO YOUR DOCUMENT
doc.Load("daco.xml");
// Select LIST ALL ELEMENTS SmallImage,MediumImage,LargeImage
XmlNodeList listOfAllImageElements = doc.SelectNodes("/Items/*");
foreach (XmlNode imageElement in listOfAllImageElements)
{
// Select URL ELEMENT
XmlNode urlElement= node.SelectSingleNode("URL");
System.Console.WriteLine(urlElement.InnerText);
}
Console.ReadLine();
If you want to select multiple url's
XmlDocument doc = new XmlDocument();
// PATH TO YOUR DOCUMENT
doc.Load("daco.xml");
// Select LIST ALL ELEMENTS SmallImage,MediumImage,LargeImage
XmlNodeList listOfAllImageElements = doc.SelectNodes("/Items/*");
foreach (XmlNode imageElement in listOfAllImageElements)
{
// Select URL's ELEMENTs
XmlNodeList listOfAllUrlElements = imageElement.SelectNodes("URL");
foreach (XmlNode urlElement in listOfAllUrlElements)
{
System.Console.WriteLine(urlElement.InnerText);
}
}
Console.ReadLine();
if you have specific namespace in your xml file
XmlDocument doc = new XmlDocument();
doc.Load("doc.xml");
XmlNamespaceManager man = new XmlNamespaceManager(doc.NameTable);
// reaplace http://schemas.microsoft.com/vs/2009/dgml with your namespace
man.AddNamespace("x", "http://schemas.microsoft.com/vs/2009/dgml");
// next you have to use x: in your path like this
XmlNodeList node = doc.SelectNodes("/x:Items/x:*, man);

Adding info to a xml file

I have a XML file which contains about 850 XML nodes. Like this:
<NameValueItem>
<Text>Test</Text>
<Code>Test</Code>
</NameValueItem>
........ 849 more
And I want to add a new Childnode inside each and every Node. So I end up like this:
<NameValueItem>
<Text>Test</Text>
<Code>Test</Code>
<Description>TestDescription</Description>
</NameValueItem>
........ 849 more
I've tried the following:
XmlDocument doc = new XmlDocument();
doc.Load(xmlPath);
XmlNodeList nodes = doc.GetElementsByTagName("NameValueItem");
Which gives me all of the nodes, but from here am stuck(guess I need to iterate over all of the nodes and append to each and every) Any examples?
You need something along the lines of this example below. On each of your nodes, you need to create a new element to add to it. I assume you will be getting different values for the InnerText property, but I just used your example.
foreach (var rootNode in nodes)
{
XmlElement element = doc.CreateElement("Description");
element.InnerText = "TestDescription";
root.AppendChild(element);
}
You should just be able to use a foreach loop over your XmlNodeList and insert the node into each XmlNode:
foreach(XmlNode node in nodes)
{
node.AppendChild(new XmlNode()
{
Name = "Description",
Value = [value to insert]
});
}
This can also be done with XDocument using LINQ to XML as such:
XDocument doc = XDocument.Load(xmlDoc);
var updated = doc.Elements("NameValueItem").Select(n => n.Add(new XElement() { Name = "Description", Value = [newvalue]}));
doc.ReplaceWith(updated);
If you don't want to parse XML using proper classes (i.e. XDocument), you can use Regex to find a place to insert your tag and insert it:
string s = #"<NameValueItem>
<Text>Test</Text>
<Code>Test</Code>
</NameValueItem>";
string newTag = "<Description>TestDescription</Description>";
string result = Regex.Replace(s, #"(?<=</Code>)", Environment.NewLine + newTag);
but the best solution is Linq2XML (it's much better, than simple XmlDocument, that is deprecated at now).
string s = #"<root>
<NameValueItem>
<Text>Test</Text>
<Code>Test</Code>
</NameValueItem>
<NameValueItem>
<Text>Test2</Text>
<Code>Test2</Code>
</NameValueItem>
</root>";
var doc = XDocument.Load(new StringReader(s));
var elms = doc.Descendants("NameValueItem");
foreach (var element in elms)
{
element.Add(new XElement("Description", "TestDescription"));
}
var text = new StringWriter();
doc.Save(text);
Console.WriteLine(text);

Get Child Nodes from an XML File

I have an XML File like below
<Attachment>
<FileName>Perimeter SRS.docx</FileName>
<FileSize>15572</FileSize>
<ActivityName>ActivityNamePerimeter SRS.docx</ActivityName>
<UserAlias>JameelM</UserAlias>
<DocumentTransferId>7123eb83-d768-4a58-be46-0dfaf1297b97</DocumentTransferId>
<EngagementName>EAuditEngagementNameNew</EngagementName>
<Sender>JameelM#orioninc.com</Sender>
</Attachment>
I read these xml file like below
var doc = new XmlDocument();
doc.Load(files);
foreach (XmlElement pointCoord in doc.SelectNodes("/Attachment"))
{
}
I need to get each child node value inside the Attachment node. How can i get these xml elements from the xml node list?
I need to get each child node value inside the Attachment node.
Your question is very unclear, but it looks like it's as simple as:
foreach (XmlNode node in doc.DocumentElement.ChildNodes)
{
}
After all, in the document you've shown us, the Attachment is the document element. No XPath is required.
As an aside, if you're using .NET 3.5 or higher, LINQ to XML is a much nicer XML API than the old DOM (XmlDocument etc) API.
try this
var data = from item in doc.Descendants("Attachment")
select new
{
FileName= item.Element("FileName").Value,
FileSize= item.Element("FileSize").Value,
Sender= item.Element("Sender").Value
};
foreach (var p in data)
Console.WriteLine(p.ToString());
var doc = new XmlDocument();
doc.Load(files);
foreach (XmlElement pointCoord in doc.SelectNodes("/Attachment"))
{
if(pointCoord!=null)
{
var valueOfElement=pointCoord.InnerText;
}
}
if you want to run conditional logic against the element names (UserAlias, etc) then use the Name property of the XmlElement.

Categories

Resources