I have a trouble reading from XML file using LINQ.
Here is my XML file
<?xml version="1.0" encoding="utf-8"?>
<Employees>
<Employee>
<Name Type="First">Jack</Name>
<Name Type="Last">Black</Name>
</Employee>
<Employee>
<Name Type="First">John</Name>
<Name Type="Last">Blue</Name>
</Employee>
<Employee>
<Name Type="First">Dan</Name>
<Name Type="Last">Red</Name>
</Employee>
<Employee>
<Name Type="First">Patrick</Name>
<Name Type="Last">Green</Name>
</Employee>
</Employees>
The code I am using is following
XElement doc = XElement.Load("xmldoc.xml");
var query = from x in doc.Elements("Employee") where x.Element("Name").Attribute("Type").Value == "First" select x;
foreach (XElement item in query)
{
Console.WriteLine(item.Element("Name").Value);
}
This code returns me all first names but when i change attribute value from first to last it comes blank.
When i switch name nodes it retuns last names. For me it looks like for each employe query returns values from first name node and ignoring the second one. Could you please help me fix this?
The problem is that the x.Element("Name") call will return the first Name element. You actually need to query all the Name elements and filter for the one with the Last attribute value.
Try this instead:
var query = from x in doc.Elements("Employee").Elements("Name")
where x.Attribute("Type").Value == "Last"
select x;
foreach (XElement item in query)
{
Console.WriteLine(item.Value);
}
Related
I have the following problem, I want to select the book with the author "Johnny Dapp33", which unfortunately does not work.
XML Code:
<employees xmlns:bar="http://www.bar.org">
<employee id="Test1">
<name>Johnny Dapp</name>
<author>Al Pacino</author>
</employee>
<employee id="Test2">
<name>Johnny Dapp33</name>
<author>Al Pacino</author>
</employee>
</employees>
I would have tried it via ".SelectSingleNode", unfortunately I always fail with the XPath.
Thank you for your help!
Let's say we have a file called Employees.xml in our project directory.
We can load the xml file in our memory by using this assignment:
XmlDocument doc = new XmlDocument();
doc.Load("Employees.xml");
Second we try to find a single node (presuambly) by its id in a structure employees/employee (this is our path), no we have to add the search param (id in this case) like this:
XmlNode singleNode = doc.SelectSingleNode("/employees/employee[#id='Test1']");
Console.WriteLine(singleNode.OuterXml);
However if we only know the name we are looking for we can also search for that specific value like this. We search in the employee node for the node value of name with the value of Johnny Dapp33:
XmlNode singleNode = doc.SelectSingleNode("descendant::employee[name='Johnny Dapp33']");
Console.WriteLine(singleNode.OuterXml);
While dealing with XMl, it is better to use LINQ to XML API.
It is available in the .Net Framework since 2007.
c#
void Main()
{
const string filePath = #"e:\Temp\WizardZZ.xml";
XDocument xdoc = XDocument.Load(filePath);
var employee = xdoc.Descendants("employee")
.Where(d => d.Elements("name").FirstOrDefault().Value.Equals("Johnny Dapp33"));
Console.WriteLine(employee);
}
Output
<employee id="Test2">
<name>Johnny Dapp33</name>
<author>Al Pacino</author>
</employee>
If you need to use XPath (and there must be a very strong reason for it), you can use it with XElement:
var xml = """
<employees xmlns:bar="http://www.bar.org">
<employee id="Test1">
<name>Johnny Dapp</name>
<author>Al Pacino</author>
</employee>
<employee id="Test2">
<name>Johnny Dapp33</name>
<author>Al Pacino</author>
</employee>
</employees>
""";
var x = XElement.Parse(xml);
var employees = x.XPathSelectElements("/employee[name='Johnny Dapp33']");
if (employees is not null)
{
foreach (var employee in employees)
{
WriteLine((string)employee.Element("name") ?? "[name] not found");
}
}
else
{
WriteLine("did not find any employees");
}
This question already has an answer here:
How to sort XML in LINQ C# by an attribute value? Also MVC
(1 answer)
Closed 7 years ago.
I have the following xml file.(sample) .. I need to sort the 'invoice' nodes by the attribute 'InvcDate'. Is this even possible in Linq? Any help would be much appreciated.
I have been trying for some time however I don't have much experience with xml and and am a relative newcomer to programming, so I would be very grateful for any help at all.
<?xml version="1.0" encoding="utf-8"?>
<Server>
<Name>AlignServer</Name>
<Params>
<marketNo>MT</marketNo>
<dateFrom>2015-01-06</dateFrom>
<dateTo>2015-01-09</dateTo>
<Sales>
<invoices>
<invoice>
<header>
<InvoiceNum>22947</InvoiceNum>
<InvcDate>2015/01/07-110104</InvcDate>
</header>
<item>
<SKU>6595456987453</SKU>
<Qty>-1</Qty>
</item>
</invoice>
<invoice>
<header>
<InvoiceNum>23056</InvoiceNum>
<InvcDate>2015/01/08-020627</InvcDate>
</header>
<item>
<SKU>9845256242255</SKU>
<Qty>-1</Qty>
</item>
</invoice>
<invoice>
<header>
<InvoiceNum>22899</InvoiceNum>
<InvcDate>2015/01/06-094505</InvcDate>
</header>
<item>
<SKU>5454256565452</SKU>
<Qty>-1</Qty>
</item>
<item>
<SKU>11111165454130</SKU>
<Qty>4</Qty>
</item>
</invoice>
</invoices>
</Sales>
</Params>
</Server>
I have tried
XElement root = XElement.Load("C:\\xmlsort\\test.xml");
XElement[] sortedTables = root.Elements("invoices").OrderBy(t => (Datetime)t.Element("invdate")).ToArray();
root.ReplaceAll(sortedTables);
root.Save("C:\\xmlsort\\test.xml");
What I have done so far - with suggestion from #ec8or and seems to work but still open to suggestions:
XElement root = XElement.Load("C:\\xmlsort\\test.xml");
var invoices = from p in root.Descendants("invoice")
orderby DateTime.ParseExact(p.Element("header").Element("InvcDate").Value, "yyyy/MM/dd-hhmmss", CultureInfo.InvariantCulture)
select p;
XElement[] sortedTables = invoices.ToArray();
root.ReplaceAll(sortedTables);
root.Save("C:\\xmlsort\\output.xml");
Read you XML in a XElement:
XElement element = XElement.Load("doc.xml");
Query you XML data:
var invoices = from p in element.Descendants ("invoice")
orderby DateTime.ParseExact(p.Element("header").Element("InvcDate").Value, "yyyy/MM/dd-hhmmss", CultureInfo.InvariantCulture)
select p;
Print it to the console:
foreach (var invoice in invoices) {
Console.WriteLine (invoice.ToString ());
}
EDIT
Answer to your question in comments.
XDocument doc = XDocument.Load ("data.xml");
Select all parent node:
var baseElement = doc.XPathSelectElement ("/Server/Params/Sales/invoices");
sort the inner nodes:
var sortedElements = baseElement.Elements ()
.OrderBy (e => (DateTime)e.XPathSelectElement("header/InvoiceNum"))
.ToList ();
replace the current content with the sortet content:
baseElement.ReplaceAll (sortedElements);
doc.Save ("out.xml");
I have an xml with the following structure
<student>
<name fname="oliver">
</name>
<name fname="de">
</name>
<name fname="johnson">
</name>
</student>
my code is like this:
//after loading into an xmldocument called xmlrecord
XmlNode row = xmlRecord.SelectSingleNode("/student");
student.fname = row.SelectSingleNode("name[fname]");
But its not returning anything. Pls what is the best way to select the fname='johnson' node?
You want the fname attribute of the first <name> element, so you should write:
student.fname = row.SelectSingleNode("name/#fname");
I have a xml document like this and I need to access the "employees", "employee" elements so I am trying to use linq's XDocument class to get the employee elements but it always returns empty value.
Sample xml:
<organization>
<metadata>
</metadata>
<main>
<otherInfo>
</otherInfo>
<employeeInfo>
<employees>
<employee>
<id>1</id>
<name>ABC</name>
</employee>
<employee>
<id>2</id>
<name>ASE</name>
</employee>
<employee>
<id>3</id>
<name>XYZ</name>
</employee>
</employees>
</employeeInfo>
</main>
</organization>
C# code:
XDocument xDoc = XDocument.Parse(xmlString);
var allEmployees = from d in xDoc.Descendants("employeeInfo")
from ms in d.Elements("employees")
from m in ms.Elements("employee")
select m;
It kind of depends on what information you need. Your select returns an IEnumerable list.
This code will print out each employee
string xmlString = #"<organization>
<metadata>
</metadata>
<main>
<otherInfo>
</otherInfo>
<employeeInfo>
<employees>
<employee>
<id>1</id>
<name>ABC</name>
</employee>
<employee>
<id>2</id>
<name>ASE</name>
</employee>
<employee>
<id>3</id>
<name>XYZ</name>
</employee>
</employees>
</employeeInfo>
</main>
</organization>";
XDocument xDoc = XDocument.Parse(xmlString);
var allEmployees = from d in xDoc.Descendants("employeeInfo")
from ms in d.Elements("employees")
from m in ms.Elements("employee")
select m;
foreach (var emp in allEmployees) {
Console.WriteLine(emp);
}
Console.Read();
XDocument xDoc = XDocument.Parse(xmlString);
var allEmployees = (from r in xDoc.Descendants("employee")
select new
{
Id = r.Element("id").Value,
Name = r.Element("name").Value
}).ToList();
foreach (var r in allEmployees)
{
Console.WriteLine(r.Id + " " + r.Name);
}
Just use Descendants("Employee");
XDocument xDoc = XDocument.Parse(xmlString);
var allEmployees = xDoc.Descendants("employee").ToList();
I need to delete specific employee node and also its child node based on the value of id.
For example, here I need to delete employee tag with id="2".
<company>
<employee>
<id>1</id>
<name>sa</name>
</employee>
<employee>
<id>2</id>
<name>ssa</name>
</employee>
</company>
Assuming you have loaded that into an XmlDocument named doc:
XmlElement el = (XmlElement)doc.SelectSingleNode("/company/employee[id=2]");
if(el != null) { el.ParentNode.RemoveChild(el); }
Try this one
XmlDocument xmlDoc = new XmlDocument();
XmlNode nodeToDelete = xmlDoc.SelectSingleNode("/root/XMLFileName[#ID="+nodeId+"]");
if (nodeToDelete != null)
{
nodeToDelete.ParentNode.RemoveChild(nodeToDelete);
}
xmlDoc.Save("XMLFileName.xml")