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();
Related
I have the following XML file and want to find an element with a specific Attribute. What I wan tot find is looking for an attribute with "Type" == "Billing".
<?xml version="1.0"?>
<PurchaseOrder PurchaseOrderNumber="99503" OrderDate="1999-10-20">
<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 Type="Shipping">
<Name>Ellen Adams</Name>
</Address>
<Address Type="transporting">
<Name>Tai Yee</Name>
<Street>8 Oak Avenue</Street>
</Address>
</Address>
</PurchaseOrder>
The problem is that here second Address node has some other inner nodes that would not be related to what I really wan to have. I mean attributes with the Shipping and transporting should not be in the out put. If I think of have only the following output what code would be desired?
<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>
and the code which I have is:
XElement root = XElement.Load("PurchaseOrder.xml");
IEnumerable<XElement> address =
from el in root.Elements("Address")
where (string)el.Attribute("Type") == "Billing"
select el;
foreach (XElement el in address)
Console.WriteLine(el);
Everything between opening and closing tags are part of an element. To get the desired output, you need to either 1. reconstruct the element to include only the needed information :
foreach (XElement el in address)
{
var newElement = new XElement(
el.Name.LocalName,
el.Attributes(),
el.Elements().Where(o => o.Name.LocalName != "Address")
);
Console.WriteLine(newElement.ToString());
}
or 2. remove all unnecessary information i.e Address elements :
foreach (XElement el in address)
{
el.Elements("Address").Remove();
Console.WriteLine(el.ToString());
}
Here is how I would do it
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication87
{
namespace Linq
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
List<string> acceptableElements = new List<string>(){"Name", "Street", "City", "State", "Zip", "Country"};
XDocument doc = XDocument.Load(FILENAME);
List<XElement> addresses = doc.Descendants("Address").ToList();
XElement billing = addresses.Where(x => x.Attribute("Type").Value == "Billing").FirstOrDefault();
addresses.Remove();
XElement po = (XElement)doc.FirstNode;
po.Add(billing);
}
}
}
}
I want to read below XMLfile with C# LINQ.
I have tried this code in C#. But not able to get address element data.
CODE:
XNamespace ns = "http://www.w3.org/2001/XMLSchema";
XNamespace nsa = "http://www.w3.org/2001/XMLSchema-instance";
var Address = from r in XDocumentdata.Descendants(ns + "Address")
select new
{
Locality = r.Element(nsa + "Locality").Value,
CountryRegion = r.Element(nsa + "CountryRegion").Value
};
foreach (var r in Address)
{
string CountryRegion = r.CountryRegion;
string Locality = r.Locality;
}
XML:
<Response xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.microsoft.com/search/local/ws/rest/v1">
<Copyright>Copyright © 2015 Microsoft and its suppliers. All rights reserved. This API cannot be accessed and the content and any results may not be used, reproduced or transmitted in any manner without express written permission from Microsoft Corporation.</Copyright>
<BrandLogoUri>http://dev.virtualearth.net/Branding/logo_powered_by.png</BrandLogoUri>
<StatusCode>200</StatusCode>
<StatusDescription>OK</StatusDescription>
<AuthenticationResultCode>ValidCredentials</AuthenticationResultCode>
<TraceId>1cf1896a29234bc583b75487b57e343f|HK20271655|02.00.163.1200|HK2SCH010280821, i-d219511f.ap-southeast-1b</TraceId>
<ResourceSets>
<ResourceSet>
<EstimatedTotal>5</EstimatedTotal>
<Resources>
<Location>
<Name>Panjagutta, Hyderabad 500082, India</Name>
<Point>
<Latitude>17.4176132</Latitude>
<Longitude>78.449595</Longitude>
</Point>
<BoundingBox>
<SouthLatitude>17.41759</SouthLatitude>
<WestLongitude>78.44907</WestLongitude>
<NorthLatitude>17.41764</NorthLatitude>
<EastLongitude>78.4502</EastLongitude>
</BoundingBox>
<EntityType>Address</EntityType>
<Address>
<AddressLine>Panjagutta</AddressLine>
<AdminDistrict>TS</AdminDistrict>
<AdminDistrict2>Hyderabad</AdminDistrict2>
<CountryRegion>India</CountryRegion>
<FormattedAddress>Panjagutta, Hyderabad 500082, India</FormattedAddress>
<Locality>Hyderabad</Locality>
<PostalCode>500082</PostalCode>
</Address>
<Confidence>Medium</Confidence>
<MatchCode>Good</MatchCode>
<GeocodePoint>
<Latitude>17.4176132</Latitude>
<Longitude>78.449595</Longitude>
<CalculationMethod>Interpolation</CalculationMethod>
<UsageType>Display</UsageType>
<UsageType>Route</UsageType>
</GeocodePoint>
</Location>
</Resources>
</ResourceSet>
</ResourceSets>
</Response>
You are using the wrong namespace. The root namespace for the document, denoted by an unaliased xmlns attribute for the XML document is http://schemas.microsoft.com/search/local/ws/rest/v1.
Use that rather than the current value of nsa.
Create a class / model that matches the structure of XML and
deserializes XML into an object or collection.
Use Linq to work with collection if you need.
And look at https://msdn.microsoft.com/en-us/library/tz8csy73(v=vs.110).aspx
Can you give this a try:
var xmlDoc = new XmlDocument();
xmlDoc.Load("your xml path");
var address = xmlDoc.GetElementsByTagName("Address");
I can access the elements inside the Address element Now.
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");
I have an xml file whose structure goes as under(partial)
<?xml version="1.0" encoding="UTF-8"?>
<TestRun id="ee3838c9-a7e2-4ddf-acb1-58589e39422d" xmlns="http://microsoft.com/schemas/VisualStudio/TeamTest/2010">
<TestSettings name="LocalSettings" id="e445106a-c672-4959-94d3-ec8cef9ac7e4">
<Results>
<UnitTestResult executionId="0e790a10-105f-44b1-a8f7-f72709651c17" testId="ae349466-4276-cfa9-908c-026a8589473b" testName="ValidateEmailAddressAndCompanyCode7" computerName="ACCUREVDEV" duration="00:00:41.4297842" startTime="2013-02-27T23:18:52.0238567-08:00" endTime="2013-02-27T23:19:34.0057439-08:00" testType="13cdc9d9-ddb5-4fa4-a97d-d965ccfc6d4b" outcome="Passed" testListId="8c84fa94-04c1-424b-9868-57a2d4851a1d" relativeResultsDirectory="0e790a10-105f-44b1-a8f7-f72709651c17">
</UnitTestResult>
<UnitTestResult executionId="e9e7679d-fc39-43b7-a096-819f054a3795" testId="1a808be5-21a5-37c4-5892-2969707ae42f" testName="AccountExtensionSubscriptionWithOneMachineAndThreeSubscriptionsTest_withExpiredMachines" computerName="ACCUREVDEV" duration="00:00:56.1243356" startTime="2013-02-27T23:19:34.0174655-08:00" endTime="2013-02-27T23:20:30.8418287-08:00" testType="13cdc9d9-ddb5-4fa4-a97d-d965ccfc6d4b" outcome="Passed" testListId="8c84fa94-04c1-424b-9868-57a2d4851a1d" relativeResultsDirectory="e9e7679d-fc39-43b7-a096-819f054a3795">
</UnitTestResult> .............................
...............................
As can be make out that, there is a namespace involved
xmlns="http://microsoft.com/schemas/VisualStudio/TeamTest/2010"
Now if I do
string source = #"D:\23_18_43.trx";
XDocument xDoc = XDocument.Load(source);
var xxxx = (from data in xDoc.Descendants("Results")
select data).Descendants("UnitTestResult").ToList();
There is no value coming.
Whereas , if I omit the namespace and do my processing, it works.
How can I proceed without removing the namespace explicitly from the source file? Can it be done programatically?
Thanks
To find a node in XML with a default namespace, you need to still search for that node using the namespace.
Eg.
XNamespace defaultNs = "http://microsoft.com/schemas/VisualStudio/TeamTest/2010";
and then in your "query";
var xxxx = (from data in xDoc.Descendants(defaultNs + "Results")
select data).Descendants(defaultNs +"UnitTestResult").ToList();
I have a problem using Linq To Xml.
A simple code. I have this XML:
<?xml version="1.0" encoding="utf-8" ?>
<data xmlns="http://www.example.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.example.com/directory file.xsd">
<contact>
<name>aaa</name>
<email>email#email.ext</email>
<birthdate>2002-09-22</birthdate>
<telephone>000:000000</telephone>
<description>Description for this contact</description>
</contact>
<contact>
<name>sss</name>
<email>email#email.ext</email>
<birthdate>2002-09-22</birthdate>
<telephone>000:000000</telephone>
<description>Description for this contact</description>
</contact>
<contact>
<name>bbb</name>
<email>email#email.ext</email>
<birthdate>2002-09-22</birthdate>
<telephone>000:000000</telephone>
<description>Description for this contact</description>
</contact>
<contact>
<name>ccc</name>
<email>email#email.ext</email>
<birthdate>2002-09-22</birthdate>
<telephone>000:000000</telephone>
<description>Description for this contact</description>
</contact>
I want to get every contact mapping it on an object Contact. To do this I use this fragment of code:
XDocument XDoc = XDocument.Load(System.Web.HttpRuntime.AppDomainAppPath + this.filesource);
XElement XRoot = XDoc.Root;
//XElement XEl = XElement.Load(this.filesource);
var results = from e in XRoot.Elements("contact")
select new Contact((string)e.Element("name"), (string)e.Element("email"), "1-1-1", null, null);
List<Contact> cntcts = new List<Contact>();
foreach (Contact cntct in results) {
cntcts.Add(cntct);
}
Contact[] c = cntcts.ToArray();
// Encapsulating element
Elements<Contact> final = new Elements<Contact>(c);
Ok just don't mind that all: focus on this:
When I get the root node, it is all right, I get it correctly.
When I use the select directive I try to get every node saying: from e in
XRoot.Elements("contact")
OK here's the problem: if I use: from e in XRoot.Elements() I get all contact nodes, but if I use: from e in XRoot.Elements("contact") I GET NOTHING: Empty SET.
OK you tell me: Use the other one: OK I DO SO, let's use:
from e in XRoot.Elements(), I get all nodes anyway, THAT's RIGHT BUT HERE COMES THE OTHER PROBLEM:
When Saying: select new Contact((string)e.Element("name"), (string)e.Element("email"), "1-1-1", null, null); I Try to access <name>, <email>... I HAVE TO USE .Element("name") AND IT DOES NOT WORK TOO!!!!!!!!WHAT THE HELL IS THIS????????????? IT SEEMS THAT I DOES NOT MATCH THE NAME I PASS But how is it possible. I know that Elements() function takes, overloaded, one argument that is an XName which is mapped onto a string. Please consider that the code I wrote come from an example, It should work.
Pretty easy: there's a XML namespace in play, which you're ignoring:
<data xmlns="http://www.example.com"
**************************
You need to add that to your Linq-to-XML queries!
Something like:
XNamespace ns = "http://www.example.com";
and then
XRoot.Elements(ns + "contact")
and of course, also use the XML namespace when accessing the child elements:
var results = from e in XRoot.Elements("contact")
select new Contact(e.Element(ns + "name").Value,
e.Element(ns + "email").Value,
"1-1-1", null, null);
That should help. See the MSDN docs on Working with XML Namespaces for more details.
For me I solved it like that because I didn't had a namespace in my XML:
xmldoc.Root.Elements("contact");
I forgot to use the "Root" method.