Linq to XML Querying Data in C# - c#

XML
<?xml version="1.0" encoding="utf-8" ?>
<Employees>
<Employee>
<EmpId>1</EmpId>
<Name>Sam</Name>
<Sex>Male</Sex>
<Salary>40000</Salary>
<Phone Type="Home">423-555-0124</Phone>
<Phone Type="Work">424-555-0545</Phone>
<Address>
<Street>7A Cox Street</Street>
<City>Acampo</City>
<State>CA</State>
<Zip>95220</Zip>
<Country>USA</Country>
</Address>
</Employee>
<Employee>
<EmpId>2</EmpId>
<Name>Lucy</Name>
<Sex>Female</Sex>
<Salary>20000</Salary>
<Phone Type="Home">143-555-0763</Phone>
<Phone Type="Work">434-555-0567</Phone>
<Address>
<Street>Jess Bay</Street>
<City>Alta</City>
<State>CA</State>
<Zip>95701</Zip>
<Country>USA</Country>
</Address>
</Employee>
LINQ expression c#
var Pro = from u in doc.Descendants("Employee") select u;
foreach (var x in Pro)
{
Response.Write(string.Format("EMP ID: {0}, Emp Name: {1}", x.Element("EmpId"), x.Element("Name")));
}
I'm able to query the fields like EmpID, Name, Salary, etc.
But How to query the Address fields like Street, City, State, Zip, Country?
Thanks in advance.

Use
x.Descendants("Address").First().Element("Street")

I would also do what Reniuz suggested and deserialize to an object but here is an example of how you currently do it:
foreach (var x in Pro)
{
Response.Write("EMP ID: {0}, Emp Name: {1}\r\n", x.Element("EmpId"), x.Element("Name"));
var adrs = x.Descendants("Address");
foreach (var a in adrs)
{
Response.Write("\tAddress Street: {0}, City: {1}\r\n", a.Element("Street"), a.Element("City"));
}
}

Take XML into the Variable and Use Like
XDocument doc = XDocument.Parse(XMLVariableString);
var FirstPart = from node in doc.Descendants("items") select node; //Select Data from doc using
List<ListName> valuesNodes = new List<ListName>(); //create any with i.e <==
Create One List with the Same Name as in XML and Created Sub List for Address Containing the all the fields of Address
Use the Same Query you have used but select from FirstPart.
Now you can easily handle data from var FirstPart

The Address elements you are trying to look for can be accessed by first selecting all the Address elements by using x.Elements("Address"). Each nested Address element can then be selected using the .Element() function.
So the parameters for Response.Write() should look something like:
x.Elements("Address").Element("Street");

Related

Linq 2 XML not returning element based in attribute value

I have the following XML...
<?xml version="1.0" encoding="utf-8"?>
<Employees>
<Employee>
<EmpId>1</EmpId>
<Name>Sam</Name>
<Sex>Male</Sex>
<Phone Type="Home">423-555-0124</Phone>
<Phone Type="Work">424-555-0545</Phone>
<Address>
<Street>7A Cox Street</Street>
<City>Acampo</City>
<State>CA</State>
<Zip>95220</Zip>
<Country>USA</Country>
</Address>
<Employee>
<EmpId>5</EmpId>
<Name>Kenneth Lowrey</Name>
<Sex>Male</Sex>
<Phone Type="Home">555-555-3477</Phone>
<Phone Type="Work">444-123-2557</Phone>
<Address>
<Street>6026 Amberwoods Drive</Street>
<City>Boca Raton</City>
<State>FL</State>
<Zip>33433</Zip>
<Country>USA</Country>
</Address>
</Employee>
</Employee>
</Employees>
I have the following Console Application code...
using System;
using System.Xml.Linq;
using System.Linq;
class Program
{
public static void Main(String[] args)
{
String strPath = #"C:\XMLExample\Employees.xml";
XElement xEle = XElement.Load(strPath);
var empquery = from e in xEle.Descendants("Employee")
select new
{
name = e.Element("Name").Value,
homephone = (string)e.Element("Phone").Attribute("Type").Value=="Home" ? e.Element("Phone").Value : "",
workphone = (string)e.Element("Phone").Attribute("Type").Value=="Work" ? e.Element("Phone").Value : "",
};
foreach (var e in empquery)
{
Console.WriteLine("{0}'s home phone is {1} work phone is {2}", e.name, e.homephone, e.workphone);
}
Console.WriteLine("Press <enter> to continue");
Console.ReadLine();
}
}
I'm trying to separate the home and work phone numbers in my query expressions.
However I'm only able to get the home phone number..
What am I doing wrong?
Element() method returns only the first element matching the specified name. So for each Employee you will only gets the first phone (Home).
A better approach is use Elements() method to gets ALL elements matching the specified name and then filters by attribute Type value:
var empquery = from e in xEle.Descendants("Employee")
select new
{
name = e.Element("Name").Value,
homephone = (string)e.Elements("Phone").Where(x => x.Attribute("Type").Value == "Home").FirstOrDefault().Value,
workphone = (string)e.Elements("Phone").Where(x => x.Attribute("Type").Value == "Work").FirstOrDefault().Value
};

LINQ XML search failed with default attribue path

I used the follwoing code to search the number of elements and search the search is succeeded only if there is no default path:
The code to search:
XElement root = XElement.Load(#"c:\b.txt", LoadOptions.PreserveWhitespace);
IEnumerable<XElement> address =
from el in root.Elements("Address")
select el;
int c = address.Count();
And the value for c is 2 with the following data:
<?xml version="1.0" encoding="UTF-8"?>
<presence xmlns:a="urn:ietf:params:xml:ns:pidf"
xmlns:dm="urn:ietf:params:xml:ns:pidf:data-model"
xmlns:oma="urn:xml:prs:pidf:oma-pres"
entity="sip:john#police.city.gov">
<Address Type="Shipping">
<Name>Ellen Adams</Name>
<Street>123 Maple Street</Street>
<City>Mill Valley</City>
<State>CA</State>
<Zip>10999</Zip>
<Country>USA</Country>
</Address>
<Address Type="Billing">
<Name>Tai Yee</Name>
<Street>8 Oak Avenue</Street>
<City>Old Town</City>
<State>PA</State>
<Zip>95819</Zip>
<Country>USA</Country>
</Address>
</presence>
But if I change the XML by exchanging the second line to be (xmlns instead of xmlns:a):
<presence xmlns="urn:ietf:params:xml:ns:pidf"
I got value 0 which is incorrect.
Any suggestion?
Thanks
xmlns="urn:ietf:params:xml:ns:pidf" means, that you set default namespace for all elements in xml, that don't have any namespace specified.
As result, you should also add namespace declaration to your LINQ to XML query, like so:
XElement root = XElement.Load(#"c:\b.txt", LoadOptions.PreserveWhitespace);
XNamespace xmlns = "urn:ietf:params:xml:ns:pidf";
IEnumerable<XElement> address = root.Elements(xmlns + "Address");
Console.WriteLine(address.Count()); //prints 2
or you can use namespace agnostic approach, which will work regardless of what default namespace is specified:
var address = root.Elements()
.Where(node => node.Name.LocalName == "Address");
//address will contain the same nodes, as in previous example
Also note, that extension method syntax is much cleaner in such case.
By setting xmlns="urn:ietf:params:xml:ns:pidf" you've set the default namespace for all elements. Therefore, the "Address" element no longer exists. It's called "urn:ietf:params:xml:ns:pidf:Address" now.
What you need to do is declare an XNamespace and add that to the element name:
XNamespace defaultNamespace = "urn:ietf:params:xml:ns:pidf";
XElement root = XElement.Load(#"c:\b.txt", LoadOptions.PreserveWhitespace);
IEnumerable<XElement> address =
from el in root.Elements(defaultNamespace + "Address")
select el;
int c = address.Count();

LINQ to XML Select Nodes by duplicate child node attributes

Need to pull out the Employees who have a pager.
<Employees>
<Employee>
<Name>Michael</Name>
<Phone Type="Home">423-555-0124</Phone>
<Phone Type="Work">800-555-0545</Phone>
<Phone Type="Mobile">424-555-0546</Phone>
<Phone Type="Cell">424-555-0547</Phone>
<Phone Type="Pager">424-555-0548</Phone>
</Employee>
<Employee>
<Name>Jannet</Name>
<Phone Type="Home">423-555-0091</Phone>
<Phone Type="Work">800-555-0545</Phone>
</Employee>
</Employees>
I've got LINQ to get all the Phone nodes that have a pager and I can get all the employees. I can't wrap my head aroud drilling down to the phone node but still selecting the employee node?
var data = XElement.Load(#"employee.XML" );
var whoHasPager = from teamMember in data.Elements("Employee")
where (string)teamMember.Element("Phone").Attribute("Type") == "Pager"
select teamMember;
How about this:
var whoHasPager = from teamMember in data.Elements("Employee")
where teamMember.Elements("Phone").Any(
p => p.Attribute("Type").Value == "Pager")
select teamMember;
The problem is that .Element will return the first element and not all of them of type Phone.
Try this:
var whoHasPager = from teamMember in data.Elements("Employee")
where teamMember.Elements("Phone").Any(x => x.Attribute("Type").Value == "Pager")
select teamMember;
You should see it as an SQL Statement maybe
SELECT employee from Employees where Phone Type='Pager'
therefore, the from statement should be Employees...
Note: I'm not really good in LINQ, but I think the idea is the same...
You could try using an XPath expression:
var data = XElement.Load(#"employee.XML" );
var whoHasPager =
from teamMember in data.Elements("Employee")
where teamMember.XPathSelectElement("Phone[#Type='Pager']") != null
select teamMember;
var whoHasPager = doc.XPathSelectElements(
"//Employee/Phone[#Type = 'Pager']/.."
);

linq to xml navigate through xml c#

I have some XML and need to be able to read the data within.
A sample of the XML is
<?xml version="1.0" ?>
<ConsumeLeadRequest xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<LeadType>Mortgage</LeadType>
<LeadXml>
<ns1:LeadAssigned xmlns:ns1="http://YaddaYadda" xmlns:ns0="http://YaddaYadda" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ns0:Lead>
<Reference>1234</Reference>
<Product>
<Mnemonic>Mortgage</Mnemonic>
<Description>Mortgage Leads</Description>
<SubType>Other</SubType>
</Product>
<ExtendedInfo>
<Mortgage>
<MortgageValue>75000</MortgageValue>
<MortgageValueLowerBound>1</MortgageValueLowerBound>
<MortgageValueUpperBound>500</MortgageValueUpperBound>
<PropertyValue>100000</PropertyValue>
<PropertyValueLowerBound>1</PropertyValueLowerBound>
<PropertyValueUpperBound>500</PropertyValueUpperBound>
<Adverse>false</Adverse>
<FirstTime>false</FirstTime>
</Mortgage>
</ExtendedInfo>
<Applicants>
<Applicant1>
<Title>Mr</Title>
<Forename>SampleForename</Forename>
<Surname>SampleSurname</Surname>
<DateOfBirth>1903-02-01</DateOfBirth>
<Smoker>false</Smoker>
<TelephoneNumbers>
<TelephoneNumber>
<Number>01244123456</Number>
<Type>Mobile</Type>
</TelephoneNumber>
</TelephoneNumbers>
<EmailAddresses>
<EmailAddress>
<Email>test#moneysupermarket.com</Email>
<Type>Business</Type>
</EmailAddress>
</EmailAddresses>
<Addresses>
<Address>
<Street>Sample Street</Street>
<District>Sample District</District>
<Town>Sample Town</Town>
<County>Sample County</County>
<Postcode>CH53UZ</Postcode>
<Type>Home</Type>
</Address>
</Addresses>
</Applicant1>
</Applicants>
</ns0:Lead>
<Assignment>
<Price>20</Price>
<AssignmentDateTime>2010-02-01T00:00:00</AssignmentDateTime>
<Subscription>
<Reference>1234</Reference>
<Subscriber>
<Title>Mr</Title>
<Forename>SampleForename</Forename>
<Surname>SampleSurname</Surname>
</Subscriber>
</Subscription>
<Account>
<Reference>1234</Reference>
<CompanyName>Sample Company</CompanyName>
</Account>
<LeadType>SampleLeadType</LeadType>
<TerritoryName>UNITED KINGDOM</TerritoryName>
</Assignment>
</ns1:LeadAssigned>
</LeadXml>
<AuthenticationUsername>Username</AuthenticationUsername>
<AuthenticationPassword>Password</AuthenticationPassword>
</ConsumeLeadRequest>
Using Linq to XML how do i navigate to the items?
Thanks
Sp
I have tried a few things like
XDocument Leads = XDocument.Load(#"C:\Users\Steven.Pentleton\AppData\Local\Temporary Projects\PAALeadImport\PAAExmple.xml");
var Lead = (from L in Leads.Descendants("Lead")
select new { LeadType = (string)L.Element("Reference") }).ToList();
var S = Lead.First();
string T = S.LeadType;
Are you looking for XDcoument or XElement in linq
Namespace: using System.Xml.Linq;
I guess you are looking for a Linq To Xml guide

how to get root node attribute value using linq

I have the following XML. How to read the root node attribite value and it's decendents using LINQ? I am trying to read "dId" and "dTime" from root node, "id" from Customer element and Order number.
<?xml version="1.0" encoding="utf-8" ?>
<Customers dId="wqwx" dTime="10-9-09 11:23">
<Customer id="1">
<Orders>
<Order number="22" status="ok">
</Orders>
</Customer>
</Customers>
I tried the following code but it doesn't work.
XDocument doc= XDocument.Load(#"C:\Customers.xml");
var q = from c in doc.Descendants("Customers")
select new
{
dID = c.Attribute("dId"),
dTime = c.Attribute("dTime");
}
first, fix your xml (<Order .... />)
then, your linq should look like this....
// .Elements(...) selects all elements of type "Customer"
var q = from c in xDoc.Elements("Customers")
select new
{
dID = c.Attribute("dId"),
dTime = c.Attribute("dTime")
};
you should dl LinqPad... it lets you do Linq queries on the fly, even agains SQL databases. Then, once you get the results you want, copy and past your linq into your source code.
You have to end the order tag with: />
xDoc.Descendants("Customers") should work as well as xDoc.Elements("Customers").
Chris, is there a specific advantage to using .Elements?
You can't use LINQ to access the root tag.
The code below does what you want (I included a well formed xml file as well):
using System;
using System.Linq;
using System.Xml.Linq;
namespace ReadXmlSpike
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Reading file...");
XDocument doc = XDocument.Load("Customers.xml");
var customers =
new
{
DID = (string) doc.Element("Customers").Attribute("did"),
DTime = (DateTime) doc.Element("Customers").Attribute("dTime"),
Customers = from customerxml in doc.Descendants("Customer")
select
new
{
ID = (string)customerxml.Attribute("id"),
Orders = from orderxml in customerxml.Descendants("Order")
select
new
{
Number =(string) orderxml.Attribute("number")
}
}
};
Console.WriteLine("Customersfile with id: {0} and time {1}",customers.DID,customers.DTime);
foreach (var customer in customers.Customers)
{
Console.WriteLine("Customer with id {0} has the following orders:",customer.ID);
foreach (var order in customer.Orders)
{
Console.WriteLine("Order with number {0}",order.Number);
}
}
Console.ReadLine();
}
}
}
and the xml file:
<?xml version="1.0" encoding="utf-8" ?>
<Customers did="www" dTime="10-09-09 11:23">
<Customer id="1">
<Orders>
<Order number="22" status="ok"/>
<Order number="23" status="bad"/>
</Orders>
</Customer>
<Customer id="2">
<Orders>
<Order number="24" status="ok"/>
<Order number="25" status="bad"/>
</Orders>
</Customer>
</Customers>
XDocument d = XDocument.Parse(#"<?xml version='1.0' encoding='utf-8' ?>
<Customers dId='wqwx' dTime='10-9-09 11:23'>
<Customer id='1'>
<Orders>
<Order number='22' status='ok'/>
</Orders>
</Customer>
</Customers>");
var cu = d.Root.Elements().Where(n => n.Name == "Customer");
var c = from cc in cu
select new
{
dId = cc.Document.Root.Attribute("dId").Value,
dTime = cc.Document.Root.Attribute("dTime").Value,
ID = cc.Attribute("id").Value,
number = cc.Element("Orders").Element("Order").Attribute("number").Value
};
foreach (var v in c)
{
Console.WriteLine("dId \t\t= {0}", v.dId);
Console.WriteLine("dTime \t\t= {0}", v.dTime);
Console.WriteLine("CustomerID \t= {0}", v.ID);
Console.WriteLine("OrderCount \t= {0}", v.number);
}
Console Output:
================================
dId = wqwx
dTime = 10-9-09 11:23
CustomerID = 1
OrderCount = 22
请按任意键继续. . .
It does not work the way you wrote it: while printing the above code would complain about anonymous type.
However, with this simple modified version d.Document.Root.Attribute("dId").Value; you can assign it to a string.

Categories

Resources