I need to read the woeid from the xml doc below. I need to read and store the data into a string variable so I can query the yahoo weather service.
XML returned by query:
<query yahoo:count="1"
yahoo:created="2009-12-22T08:30:31Z"
yahoo:lang="en-US"
yahoo:updated="2009-12-22T08:30:31Z"
yahoo:uri="http://query.yahooapis.com/v1/yql?q=select+woeid+from+geo.places+where+text%3D%22farnborough%2C+greater+london%2Cuk%22">
−
<diagnostics>
<publiclyCallable>true</publiclyCallable>
−
<url execution-time="32">
http://where.yahooapis.com/v1/places.q(farnborough%2C%20greater%20london%2Cuk);start=0;count=10
</url>
<user-time>33</user-time>
<service-time>32</service-time>
<build-version>4265</build-version>
</diagnostics>
−
<results>
−
<place>
<woeid>19941</woeid>
</place>
</results>
</query>
Can someone show me how to do this through linq?
----------EDIT ------------------------------------------------------------------------------------------
I've just realised i linq is not supported by .net 2.0...doh
So please could some suggest an alternative way using references available with .net 2.0? -maybe repost and tag?
Many Thanks,
You can do it like this:
XDocument doc = XDocument.Parse(xml);
string s = doc.Descendants()
.Where(element => element.Name == "woeid")
.FirstOrDefault().Value;
You can use something similar to this Linq query to get the results back from the XML document
XDocument feeds = XDocument.Parse(xml);
var result = feeds.Descendants("diagnostics")
.Select(f => new
{
UserTime = f.Element("uset-time").Value,
ServiceTime = f.Element("service-time").Value,
//... etc
}.First();
Here is a way to extract values from an xml file using Linq and xPath.
Hope this helps some.
Related
This question already has answers here:
Read from xml files with or without a namespace using XmlDocument
(4 answers)
Closed 4 years ago.
I extracted body data from soapResponse which is given by webservice. but am not able to extract from tags which contains colon between and below data is the body response.
XML Sample Data:
<?xml encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://abc/envelope/">
<soapenv:Header xmlns:view="http://abc/ViewCusReq" />
<soapenv:Body xmlns:view="http://abc/ViewCusReq">
<ns3:Cus_Res xmlns:ns3="http://abc/ViewCusResp">
<ns3:ReqID>123</ns3:ReqID>
<ns3:FName>ab</ns3:FName>
</ns3:Cus_Res>
<ns3:Cus_Res xmlns:ns3="http://test.com/ViewCusResp">
<ns3:ReqID>123</ns3:ReqID>
<ns3:FName>ab</ns3:FName>
</ns3:Cus_Res>
</soapenv:Body>
</soapenv:Header>
</soapenv:Envelope>
used below c# code for about to get list of values of ReqID and AbhiFNameav, but it returns empty/null.
var responseEle = from lst in xDoc.Descendants((XNamespace)"http://test.com/ViewCusResp" + "ReqID") select lst;
I know, something i querying wrongly format, Can anyone help me out from this,. Thank you in advance.
It is difficult to make an answer without knowing if your xml is just a basic sample or if it is (once corrected) a true example of what you are working with in production.
Will there be many Cus_Res nodes?
To answer your exact question see the code below that selects the nodes and gets the values. However, if your production xml is more complicated then you have more work to do looping over collections of Cus_Res, for example.
string xml = #"<?xml version=""1.0"" encoding=""UTF - 8""?>
<ns3:Cus_Res xmlns:ns3=""http://test.com/customerResponse"">
<ns3:ReqID> 123456789 </ns3:ReqID>
<ns3:FName> Abhinav </ns3:FName>
</ns3:Cus_Res>";
XNamespace xn = "http://test.com/customerResponse";
var xDoc = XDocument.Parse(xml);
var reqid = xDoc.Descendants(xn + "ReqID").First();
var fname = xDoc.Descendants(xn + "FName").First();
Console.WriteLine(reqid.Value);
Console.WriteLine(fname.Value);
Update
If you had many Cus_Res nodes within a root element you would select all Cus_Res nodes then loop over them, accessing it's direct children.
Again, it would not take much modification to your xml to break this and you should also do null checking which I do not demonstrate:
string xml = #"<?xml version=""1.0"" encoding=""UTF - 8""?>
<root>
<ns3:Cus_Res xmlns:ns3=""http://test.com/customerResponse"">
<ns3:ReqID> 123456789 </ns3:ReqID>
<ns3:FName> Abhinav </ns3:FName>
</ns3:Cus_Res>
<ns3:Cus_Res xmlns:ns3=""http://test.com/customerResponse"">
<ns3:ReqID> 3456 </ns3:ReqID>
<ns3:FName> Wayne </ns3:FName>
</ns3:Cus_Res>
<ns3:Cus_Res xmlns:ns3=""http://test.com/customerResponse"">
<ns3:ReqID> 78952</ns3:ReqID>
<ns3:FName>Garth</ns3:FName>
</ns3:Cus_Res>
</root>";
XNamespace xn = "http://test.com/customerResponse";
var xDoc = XDocument.Parse(xml);
var CurResList = xDoc.Descendants(xn + "Cus_Res");
foreach (XElement element in CurResList)
{
Console.WriteLine(element.Element(xn + "ReqID").Value);
Console.WriteLine(element.Element(xn + "FName").Value);
}
How to select Multiple XML Tags as XElement, filtering based on same attribute.
I have Below code i want to select tags with are having action=true
<root>
<first action="true">
<path>E:\Myfolder</path>
</first>
<second>
<path>C:\Users\</path>
</second>
<third action="true">
<name>Mytasks</name>
</third>
</root>
and Output shout be like this
<first action="true">
<path>E:\Myfolder</path>
</first>
<third action="true">
<name>Mytasks</name>
</third>
anybody please help me. I used FirstorDefault() But i am getting only one record among all
Try This .
$(path).find('root').find('[action="true"]')
Try This
xd = XDocument.Load("XML FILE PATH");
xe = xd.Root;
IEnumerable<XElement> oColl = from x in xe.Descendants() where ((string)x.Attribute("action")).equals("true") select x;
Here is the xml structure.
I am trying to delete each Status node where State contains the word failed.
What is the best way to remove these?
<Stats>
<Status>
<Desc>something here</Desc>
<State>pending - ok</State>
</Status>
<Status>
<Desc>something here</Desc>
<State>failed</State>
</Status>
</Stats>
void Main()
{
XDocument xml = XDocument.Parse(#"<Stats>
<Status>
<Desc>something here</Desc>
<State>pending - ok</State>
</Status>
<Status>
<Desc>something here</Desc>
<State>failed</State>
</Status>
</Stats>");
xml.Descendants("State").Where (x => x.Value.Contains("fail")).Ancestors("Status").Remove();
Console.WriteLine(xml.ToString());
}
Parse will load the xml in-memory, Load is used for loading it from a stream or via I/O means.
#Gregory Pilar's answer heavily influenced this answer; I believe he wrote that from memory, the snippet I provided was testing via LinqPad and returns expected results.
You can use Linq to XMl, to do the job
var xdoc = XDocument.Load(path_to_xml);
xdoc.Descendants("Status")
.Where(os => (int)os.Attribute("State") == "failed")
.Remove();
xdoc.Save(path_to_xml);
xDoc.Descendants("Status").Where(status => status.Element("State").Value.ToLower().Contains("fail")).Remove();
I have a REST web service that creates a XMLDocument I am a bit confused on how access the inner text in FormattedPrice using XMLNode. I can grad offers but that will give me all the inner text.
<Offers>
<Offer>
<OfferListing>
<Price>
<Amount>1067</Amount>
<CurrencyCode>USD</CurrencyCode>
<FormattedPrice>$10.67</FormattedPrice>
</Price>
</OfferListing>
</Offer>
</Offers>
A quick walk-through of XPath will help immensely if you're using the Xml DOM.
This should meet your immediate need:
XmlNode n = doc.DocumentElement.SelectSingleNode("Offer/OfferListing/Price/FormattedPrice");
That will get you the first Offer's Formatted price (and assumes that your Offers node is the root). Other mechanisms exist in XPath that are a bit less brittle and that's where a tutorial would help you.
You are probably be best off using XPath.
XmlDocument doc = ...;
XmlNode fPrice;
XmlElement root = doc.DocumentElement;
fPrice= root.SelectSingleNode("/Price/FormattedPrice");
return fPrice.InnerText;
Here's a good example: http://www.codeproject.com/KB/cpp/myXPath.aspx
Use XElement to parse it:
string tmp = #"
<Offers>
<Offer>
<Price>
<Amount>1067</Amount>
<CurrencyCode>USD</CurrencyCode>
<FormattedPrice>$10.67</FormattedPrice>
</Price>
</Offer>
</Offers>";
XElement xml = XElement.Parse(tmp);
string formatedPrice = (string)xml.XPathSelectElement("/Offer/Price/FormattedPrice");
This should grab the $ amount:
var price = doc.SelectSingleNode(#"//Offer/Price/FormattedPrice");
string priceText = price.InnerText;
Load what you want into a XmlNodeList and then pull one explicitly or loop through them...
XmlNodeList pricesList = xmlDoc.GetElementsByTagName("FormattedPrice");
string firstPrice = pricesList[0].InnerText;
First off, your XML is invalid....you are missing the starting OfferListing tag.
Here is yet another option to grab the node text.
var xmlString = "<Offers><Offer><OfferListing><Price><Amount>1067</Amount<CurrencyCode>USD</CurrencyCode><FormattedPrice>$10.67</FormattedPrice></Price></OfferListing></Offer></Offers>";
var xDoc = new XmlDocument();
xDoc.LoadXml(xmlString);
var formattedPrice = xDoc.GetElementsByTagName("FormattedPrice")[0].InnerText;
Is there a way to search an XDocument without knowing the namespace? I have a process that logs all SOAP requests and encrypts the sensitive data. I want to find any elements based on name. Something like, give me all elements where the name is CreditCard. I don't care what the namespace is.
My problem seems to be with LINQ and requiring a xml namespace.
I have other processes that retrieve values from XML, but I know the namespace for these other process.
XDocument xDocument = XDocument.Load(#"C:\temp\Packet.xml");
XNamespace xNamespace = "http://CompanyName.AppName.Service.Contracts";
var elements = xDocument.Root
.DescendantsAndSelf()
.Elements()
.Where(d => d.Name == xNamespace + "CreditCardNumber");
I really want to have the ability to search xml without knowing about namespaces, something like this:
XDocument xDocument = XDocument.Load(#"C:\temp\Packet.xml");
var elements = xDocument.Root
.DescendantsAndSelf()
.Elements()
.Where(d => d.Name == "CreditCardNumber")
This will not work because I don't know the namespace beforehand at compile time.
How can this be done?
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Request xmlns="http://CompanyName.AppName.Service.ContractA">
<Person>
<CreditCardNumber>83838</CreditCardNumber>
<FirstName>Tom</FirstName>
<LastName>Jackson</LastName>
</Person>
<Person>
<CreditCardNumber>789875</CreditCardNumber>
<FirstName>Chris</FirstName>
<LastName>Smith</LastName>
</Person>
...
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Request xmlns="http://CompanyName.AppName.Service.ContractsB">
<Transaction>
<CreditCardNumber>83838</CreditCardNumber>
<TransactionID>64588</FirstName>
</Transaction>
...
As Adam precises in the comment, XName are convertible to a string, but that string requires the namespace when there is one. That's why the comparison of .Name to a string fails, or why you can't pass "Person" as a parameter to the XLinq Method to filter on their name.
XName consists of a prefix (the Namespace) and a LocalName. The local name is what you want to query on if you are ignoring namespaces.
Thank you Adam :)
You can't put the Name of the node as a parameter of the .Descendants() method, but you can query that way :
var doc= XElement.Parse(
#"<s:Envelope xmlns:s=""http://schemas.xmlsoap.org/soap/envelope/"">
<s:Body xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"">
<Request xmlns=""http://CompanyName.AppName.Service.ContractA"">
<Person>
<CreditCardNumber>83838</CreditCardNumber>
<FirstName>Tom</FirstName>
<LastName>Jackson</LastName>
</Person>
<Person>
<CreditCardNumber>789875</CreditCardNumber>
<FirstName>Chris</FirstName>
<LastName>Smith</LastName>
</Person>
</Request>
</s:Body>
</s:Envelope>");
EDIT : bad copy/past from my test :)
var persons = from p in doc.Descendants()
where p.Name.LocalName == "Person"
select p;
foreach (var p in persons)
{
Console.WriteLine(p);
}
That works for me...
You could take the namespace from the root-element:
XDocument xDocument = XDocument.Load(#"C:\temp\Packet.xml");
var ns = xDocument.Root.Name.Namespace;
Now you can get all desired elements easily using the plus-operator:
root.Elements(ns + "CreditCardNumber")
I think I found what I was looking for. You can see in the following code I do the evaluation Element.Name.LocalName == "CreditCardNumber". This seemed to work in my tests. I'm not sure if it's a best practice, but I'm going to use it.
XDocument xDocument = XDocument.Load(#"C:\temp\Packet.xml");
var elements = xDocument.Root.DescendantsAndSelf().Elements().Where(d => d.Name.LocalName == "CreditCardNumber");
Now I have elements where I can encrypt the values.
If anyone has a better solution, please provide it. Thanks.
There's a couple answers with extension methods that have been deleted. Not sure why. Here's my version that works for my needs.
public static class XElementExtensions
{
public static XElement ElementByLocalName(this XElement element, string localName)
{
return element.Descendants().FirstOrDefault(e => e.Name.LocalName == localName && !e.IsEmpty);
}
}
The IsEmpty is to filter out nodes with x:nil="true"
There may be additional subtleties - so use with caution.
If your XML documents always defines the namespace in the same node (Request node in the two examples given), you can determine it by making a query and seeing what namespace the result has:
XDocument xDoc = XDocument.Load("filename.xml");
//Initial query to get namespace:
var reqNodes = from el in xDoc.Root.Descendants()
where el.Name.LocalName == "Request"
select el;
foreach(var reqNode in reqNodes)
{
XNamespace xns = reqNode.Name.Namespace;
//Queries making use of namespace:
var person = from el in reqNode.Elements(xns + "Person")
select el;
}
I a suffering from a major case of "I know that is the solution, but I am disappointed that that is the solution"... I recently wrote a query like the one below (which I will shortly replace, but it has educational value):
var result = xdoc.Descendants("{urn:schemas-microsoft-com:rowset}data")
.FirstOrDefault()?
.Descendants("{#RowsetSchema}row");
If I remove the namespaces from the XML, I can write the same query like this:
var result = xdoc.Descendants("data")
.FirstOrDefault()?
.Descendants("row");
I plan to write my own extension methods that should allow me to leave the namespaces alone and search for nodes like this:
var result = xdoc.Descendants("rs:data")
.FirstOrDefault()?
.Descendants("z:row");
//'rs:' {refers to urn:schemas-microsoft-com:rowset}
//'z:' {refers to xmlns:z=#RowsetSchema}
My comments just below the code point to how I would like to hide the ugliness of the solution in an Extension Methods library. Again, I'm aware of the solutions posted earlier - but I wish the API itself handled this more fluently. (See what I did there?)
Just use the Descendents method:
XDocument doc = XDocument.Load(filename);
String[] creditCards = (from creditCardNode in doc.Root.Descendents("CreditCardNumber")
select creditCardNode.Value).ToArray<string>();