LINQ to XML to read Hierarchal XML Document - c#

I have an XML as an XDocument. How can I use LINQ to read an attribute x if SubMain y?
<Main>
<SubMain Name="SubMain1">
<Attribute1>Value1</Attribute1>
<Attribute2>Value2</Attribute2>
<Attributen>Valuen</Attribute2>
<SubMain>
<SubMain Name="SubMain2">
<Attribute1>Value1</Attribute1>
<Attribute2>Value2</Attribute2>
<Attributen>Valuen</Attribute2>
<SubMain>
</Main>

Quick and dirty
var xmlString = #"<Main>
<SubMain Name=""SubMain1"">
<Attribute1>Value1</Attribute1>
<Attribute2>Value2</Attribute2>
<Attributen>Valuen</Attributen>
</SubMain>
<SubMain Name=""SubMain2"">
<Attribute1>Value1</Attribute1>
<Attribute2>Value2</Attribute2>
<Attributen>Valuen</Attributen>
</SubMain>
</Main>";
var xDoc = XDocument.Parse(xmlString);
var item = (from el in xDoc.Descendants("SubMain")
where el.Attribute("Name").Value == "SubMain2"
select el);

Related

LINQ xml finding nodes returns null

I try to parse an xml file with XDocument class, with criteria that if the child node matches a given string, its parent node is selected.
<SalesQuotes xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://api.some.com/version/1">
<Pagination>
<NumberOfItems>2380</NumberOfItems>
<PageSize>200</PageSize>
<PageNumber>1</PageNumber>
<NumberOfPages>12</NumberOfPages>
</Pagination>
<SalesQuote>
<Guid>825634b9-28f5-4aa7-98e7-5e4a4ed6bc6a</Guid>
<LastModifiedOn>2018-01-09T12:23:56.6133445</LastModifiedOn>
<Comments>Please note:
installation is not included in this quote
</Comments>
</SalesQuote>
</SalesQuotes>
I tried using
var contents = File.ReadAllText(path: "test1.xml");
var doc = XDocument.Parse(contents);
var root = doc.Root;
var sq = root.Elements("SalesQuote");//return null
var theQuote = root.Elements("SalesQuote").Where(el => el.Element("Guid").Value == "825634b9-28f5-4aa7-98e7-5e4a4ed6bc6a");//return null
var theAlternativeQuote =
from el in doc.Descendants("SalesQuote").Elements("Guid")
where el.Value == "825634b9-28f5-4aa7-98e7-5e4a4ed6bc6a"
select el;//return null
I can't seem to find what's wrong.
Any help is much appreciated! Thanks.
You ignored the namespace bro.
Do remove the xmlns attribute in your XML or try this:
var contents = File.ReadAllText("XMLFile1.xml");
var doc = XDocument.Parse(contents);
var root = doc.Root;
XNamespace ns = "http://api.some.com/version/1";
var sq = root.Descendants(ns + "SalesQuotes"); //return null
var theQuote = root.Elements(ns + "SalesQuote")
.Where(el => el.Element(ns + "Guid").Value == "825634b9-28f5-4aa7-98e7-5e4a4ed6bc6a"); //return null
var theAlternativeQuote =
from el in doc.Descendants(ns + "SalesQuote").Elements(ns + "Guid")
where el.Value == "825634b9-28f5-4aa7-98e7-5e4a4ed6bc6a"
select el; //return null
If you are not too concerned about keeping your current implementation, you could consider using a Typed DataSet and load your XML into fully typed, structured objects.
Querying those objects with Linq will be more straight forward than what I see in your current implementation.
You might also find this useful:
SO Question: Deserialize XML Document to Objects
yap, you're missing the namespace that you can grab with document.Root.GetDefaultNamespace()
// Load
var document = XDocument.Parse(xml);
var xmlns = document.Root.GetDefaultNamespace();
// Find
var query = from element in document
.Descendants(xmlns + "SalesQuote")
.Elements(xmlns + "Guid")
where element.Value == "825634b9-28f5-4aa7-98e7-5e4a4ed6bc6a"
select element;

Linq to XML elements

Hi I try to read an xml file with LINQ.
The name of the file is:categorizedBooks.xml
and the content of the file looks like this:
<category name=".NET">
<books>
<book>CLR via C#</book>
<book>Essential .NET</book>
</books>
</category>
The code for reading the file looks like this:
XElement rootss = XElement.Load(#"D:/categorizedBooks.xml");
XElement dotNetCategoryss = rootss.Element("category");
XAttribute namehallo = dotNetCategoryss.Attribute("name");
XElement booksss = dotNetCategoryss.Element("books");
IEnumerable<XElement> bookElements = booksss.Elements("book");
Console.WriteLine((string)dotNetCategoryss);
foreach (XElement bookElement in bookElements)
{
Console.WriteLine(" - " + (string)bookElement);
}
But i get null on this line:
XAttribute namehallo = dotNetCategoryss.Attribute("name");
So how to fix this , so that it not will be null?
Thank you
Your doc root is the category element - try:
XAttribute namehallo = rootss.Attribute("name");
Console.WriteLine(namehallo.Value);
You'll have to change your other XElement references similarly
instead of XElement.Load use XDocument.Load or XDocument.Parse
var xml = #"
<category name='.NET'>
<books>
<book>CLR via C#</book>
<book>Essential .NET</book>
</books>
</category>";
var document = XDocument.Parse(xml);
// returns: .NET
var category = document
.Element("category")
.Attributes("name")
.Select(p => p.Value);
// returns: CLR via C#, Essential .NET
var books = document
.Descendants("book")
.Select(p => p.Value);

Select Node Type From XML document

Hi i have a scenario where i want to search the node in xml file and identify the type of file.
XDocument xDococumnetObj = XDocument.Load(filePath);
XElement presentationElement=
xDococumnetObj.Descendants()
.Where(x => x.Name.LocalName.Equals("collegge"))
.FirstOrDefault();
I have written query which returns me collegge node. But i just want to identify the type of document it is. I want to identify the document whether it contains {"Collegge","University","Company","Banking"} in single query and return its Type only.
string[] docTypes = {"Collegge", "University", "Company", "Banking"};
XDocument xdoc = XDocument.Load(filePath);
var docType = docTypes.FirstOrDefault(type =>
xdoc.Descendants().Any(n => n.Name.LocalName == type.ToLower()));
UPDATE: If all elements declared in same namespace, you can use following code to avoid traversing all elements from files
string[] docTypes = {"Collegge", "University", "Company", "Banking"};
XDocument xdoc = XDocument.Load(filePath);
XNamespace ns = "http://www.foo.org/2013/bar";
var docType = docTypes.FirstOrDefault(type => xdoc.Descendants(ns + type).Any());

Adding an element to this xml structure

<root>
<element1>innertext</element1>
<element2>innertext</element2>
<element3>
<child1>innertext</child1>
</element3>
</root>
I have an xml structure shown above.
I would like to "append" the xml file (it is already created) to add another "child" inside element3>, so that it will look like this:
<root>
<element1>innertext</element1>
<element2>innertext</element2>
<element3>
<child1>innertext</child1>
<child2>innertext</child2>
</element3>
</root>
Linq to xml and/or Xpath would be great
EDIT:
I have tried doing this:
XElement doc = XElement.Load(mainDirectory);
XElement newElem = doc.Elements("element3").First();
newElem.Add(new XElement("child2", "child2innertext"));
doc.Add(newElem);
doc.Save(mainDirectory);
XmlDocument xDoc = new XmlDocument();
xDoc.Load("filename.xml");
foreach (XmlNode xNode in xDoc.SelectNodes("/root/element3"))
{
XmlElement newElement = xDoc.CreateElement("Child2");
xNode.AppendChild(newElement);
xNode.InnerText = "myInnerText";
}
With XDocument you can achieve this as:
string xml = "<root><element1>innertext</element1><element2>innertext</element2><element3><child1>innertext</child1></element3></root>";
var doc = XDocument.Parse(xml); //use XDocument.Load("filepath"); in case if your xml is in a file.
var el3 = doc.Descendants("element3").FirstOrDefault();
el3.Add(new XElement("child2", "innertext"));
Please, try this LINQPAD example
void Main()
{
var xml =
#"<root>
<element1>innertext</element1>
<element2>innertext</element2>
<element3>
<child1>innertext</child1>
</element3>
</root>";
var doc = XDocument.Parse(xml);
doc.Root.Element("element3")
.Add(new XElement("child2", "innertext"));
doc.Dump();
}

what's wrong in this LINQ query

I have the following XML
<School Version="30">
<Math>
<Lesson1 Type="Active">Introduction</Reset_mode>
<Lesson2 Type="Active">Fundamentals</Reset_mode>
</Math>
</School>
I want to get the subelements lesson1, lesson2
I load the XML in XDocument
I have to question - what's wrong in this query
var nodes = from C in document.Element("School").Elements()
where document.Element("School").Elements().Contains(t => t.Name == "Math")
select C ; //shortcutsXMLDocument.SelectNodes(Query);
and it raise and error.
Also can I use XPath with XDocument?
You are looking for a ShortcutList element :
Element("ShortcutList")
Which does not exists.
You should write this to get subLessons :
var items = document.Element("School").Element("Math").Elements();
foreach(var item in items)
{
DoSomething(item);
}
LINQ to XML:
from subject in XDocument.Load(xml).Element("School").Elemens()
where subject.Name == "Math"
select subject.Elements();
XPath using XmlDocument:
var doc = new XmlDocument();
doc.LoadXml(xml);
var nodes = doc.SelectNodes("School/Math/Lesson1 or School/Math/Lesson2");
document.Decendants("Math");
yields you a IEnumrable with your two elements.
it's equal to the xpath //Math
Xpath case used on XElement/XDocument from this namespace System.Xml.XPath.
here is your query for path...
var nodes = from C in document.XPathSelectElements("./Math")
select C; //shortcutsXMLDocument.SelectNodes(Query);

Categories