I'm trying to import the kml xml Google earth file into an application, but i can't seem to get the xDocument syntax right in order to do what i want, i'm wondering if anyone could suggest a way to read in the kml xml file.
I understand the basics of xml import but can't get anything working with xDocument and Linq, ideally i'd like to get each Placemark as an object and add them to my Entity Framework driven db. Any suggestions as to how i should do this would be great, as i'm just starting out with Linq and could do with some pointers. The xml is laid out as below
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://earth.google.com/kml/2.2">
<Document>
<Placemark>
<name>XXX</name>
<description>XXX</description>
<styleUrl>XXX</styleUrl>
<Point>
<coordinates>XXX</coordinates>
</Point>
</Placemark>
<Placemark>
<name>XXX</name>
<description>XXX</description>
<styleUrl>XXX</styleUrl>
<Point>
<coordinates>XXX</coordinates>
</Point>
</Placemark>
</Document>
</kml>
You didn't include any code, but I would guess that you forgot to include your namespace when referencing things. Here is an example.
Basic access:
var placemarks = xdoc.Element("kml").Element("Document").Elements("Placemark");
Using namespaces:
var ns = XNamespace.Get("http://earth.google.com/kml/2.2");
var placemarks = xdoc.Element(ns + "kml").Element(ns + "Document").Elements(ns + "Placemark");
My guess is that you've forgotten to use the namespace in your LINQ to XML queries. It's easy enough to extract the data from this:
XNamespace ns = "http://earth.google.com/kml/2.2";
var doc = XDocument.Load("file.xml");
var query = doc.Root
.Element(ns + "Document")
.Elements(ns + "Placemark")
.Select(x => new PlaceMark // I assume you've already got this
{
Name = x.Element(ns + "name").Value,
Description = x.Element(ns + "description").Value,
// etc
});
If that doesn't help, please post a complete example of what you've tried, and what went wrong.
I used SharmpKml and its documentation to extract information from KML file.
using SharpKml.Dom;
using SharpKml.Engine;
using SharpKml.Dom.GX;
TextReader reader = File.OpenText(filePath);
KmlFile file = KmlFile.Load(reader);
_kml = file.Root as Kml;
sPlaceMarks[] tempPlaceMarks = new sPlaceMarks[1000];
if (_kml != null)
{
foreach (var placemark in _kml.Flatten().OfType<Placemark>())
{
tempPlaceMarks[numOfPlaceMarks].Name = placemark.Name;
tempPlaceMarks[numOfPlaceMarks].Description = placemark.Description.Text;
tempPlaceMarks[numOfPlaceMarks].StyleUrl = placemark.StyleUrl;
tempPlaceMarks[numOfPlaceMarks].point = placemark.Geometry as SharpKml.Dom.Point;
tempPlaceMarks[numOfPlaceMarks].CoordinateX = tempPlaceMarks[numOfPlaceMarks].point.Coordinate.Longitude;
tempPlaceMarks[numOfPlaceMarks].CoordinateY = tempPlaceMarks[numOfPlaceMarks].point.Coordinate.Latitude;
tempPlaceMarks[numOfPlaceMarks].CoordinateZ = tempPlaceMarks[numOfPlaceMarks].point.Coordinate.Altitude;
numOfPlaceMarks++;
}
foreach (var lookAt in _kml.Flatten().OfType<LookAt>())
{
Placemark placemark = (Placemark)lookAt.Parent;
for (int i = 0; i < numOfPlaceMarks; i++)
{
if (placemark.Name == tempPlaceMarks[i].Name)
{
tempPlaceMarks[i].Name = placemark.Name;
tempPlaceMarks[i].Description = placemark.Description.Text;
tempPlaceMarks[i].StyleUrl = placemark.StyleUrl;
tempPlaceMarks[i].altitude = lookAt.Altitude;
tempPlaceMarks[i].AltitudeMode =(SharpKml.Dom.GX.AltitudeMode)lookAt.GXAltitudeMode;
tempPlaceMarks[i].Heading = lookAt.Heading;
tempPlaceMarks[i].Latitude = lookAt.Latitude;
tempPlaceMarks[i].Longitude = lookAt.Longitude;
tempPlaceMarks[i].Range = lookAt.Range;
tempPlaceMarks[i].Tilt = lookAt.Tilt;
break;
}
}
}
var xDoc = XDocument.Load("a.xml");
XNamespace ns = "http://earth.google.com/kml/2.2";
var placemarks = xDoc.Descendants(ns+"Placemark")
.Select(p => new
{
Name = p.Element(ns+"name").Value,
Desc = p.Element(ns+"description").Value
})
.ToList();
Your kml file must contains
<kml xmlns="http://www.opengis.net/kml/2.2" ...
instead of
<kml xmlns="http://earth.google.com/kml/2.2"> ...
Related
I am trying to read XML using LINQ. Previously I use XMLDocument to read but it gives an error and someone on StackOverflow encourage me to use LINQ.
Below is the code i previously used for the XMLDocument
string soapmessage = #"<?xml version=""1.0"" encoding=""UTF - 8""?>" + "\n" + response.Content;
XmlDocument xml = new XmlDocument();
xml.LoadXml(soapmessage); //loading soap message as string
XmlNamespaceManager manager = new XmlNamespaceManager(xml.NameTable);
manager.AddNamespace("d", "http://tempuri.org/");
manager.AddNamespace("bhr", "http://52.187.127.196:5000/api/gsowebservice.asmx");
XmlNodeList xnList = xml.SelectNodes("//bhr:FourMonthsAhead1Response", manager);
int nodes = xnList.Count;
string Status = xnList[0]["FourMonthsAhead1Result"]["PlantForecastIntervals"]["PlantForecastIntervalNode"]["IntervalStartTime"].InnerText;
Console.WriteLine(Status);
Console.ReadLine();
I am trying to get the <IntervalStartTime> from the first <PlantForecastIntervalNode> into a datetime variable;
Below attaced the XML im trying read:
Below is some of the XML code. I can't paste it here because the code is 2322 lines long so I shortened the code to this.
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<s:Body>
<FourMonthsAhead1Response xmlns="http://tempuri.org/">
<FourMonthsAhead1Result xmlns="LSS.solar.webservice">
<PlantDescription xmlns="http://base.datacontract">*PlantName*</PlantDescription>
<PlantForecastIntervalsCount xmlns="http://base.datacontract">2976</PlantForecastIntervalsCount>
<ForecastStartDate xmlns="http://base.datacontract">2021-10-08T13:35:55.912612</ForecastStartDate>
<ForecastEndDate xmlns="http://base.datacontract">2021-10-08T13:35:55.9126123</ForecastEndDate>
<PlantForecastIntervals xmlns="http://base.datacontract">
<PlantForecastIntervalNode>
<IntervalStartTime>2021-10-01T00:00:00</IntervalStartTime>
<IntervalEndTime>2021-10-01T00:15:00</IntervalEndTime>
<IntervalLength>15</IntervalLength>
<ForecastResultParameter>FourMonthsAhead1</ForecastResultParameter>
<ForecastValue>0</ForecastValue>
<ValueUnit>MW</ValueUnit>
</PlantForecastIntervalNode>
<PlantForecastIntervalNode>
<IntervalStartTime>2021-10-01T00:15:00</IntervalStartTime>
<IntervalEndTime>2021-10-01T00:30:00</IntervalEndTime>
<IntervalLength>15</IntervalLength>
<ForecastResultParameter>FourMonthsAhead1</ForecastResultParameter>
<ForecastValue>0</ForecastValue>
<ValueUnit>MW</ValueUnit>
</PlantForecastIntervalNode>
</PlantForecastIntervals>
</FourMonthsAhead1Result>
</FourMonthsAhead1Response>
</s:Body>
</s:Envelope>
Update
After exploring other threads on StackOverflow I come up with this line below but receive another error of System.UriFormatException: 'Invalid URI: The Uri string is too long.':
XDocument xdoc = XDocument.Load(soapmessage);
var ids = xdoc.Element("FourMonthsAhead1Result")
.Elements("PlantForecastIntervals")
.Elements("<PlantForecastIntervalNode>")
.Select(item => item.Element("IntervalStartTime").Value);
Console.WriteLine(ids);
Try this using LINQ
var response = File.ReadAllText("XMLFile1.xml");
var xe = XElement.Parse(response);
XNamespace ns = "http://base.datacontract";
var obj = xe.Descendants(ns + "PlantForecastIntervals")
.Descendants(ns + "PlantForecastIntervalNode")
.Select(x => x.Element(ns + "IntervalStartTime").Value);
Console.WriteLine(obj);
Look at below solution,
var xmlRead = File.ReadAllText(#"XMLFile1.xml"); /// Add your xml file path
var xElement = XElement.Parse(xmlRead);
XNamespace xNamespace = "http://base.datacontract";
var obj = xElement.Descendants(xNamespace + "PlantForecastIntervals")
.Descendants(xNamespace + "PlantForecastIntervalNode")
.Select(x => x.Element(xNamespace + "IntervalStartTime").Value);
string[] dateTime = obj.ToArray();
foreach (string x in dateTime)
{
Console.WriteLine(x.ToString()); /// it will print time from all IntervalStartTime tags
}
i have this structure of data:
<?xml version="1.0" encoding="windows-1250"?>
<?xml-stylesheet type="text/xsl" href="usb71105.xsl"?>
<manas:usb xmlns:manas="http://www.manas.info/">
<manas:qr00>
<manas:verzemanas>26052708</manas:verzemanas>
<manas:verzexml>2016.03.29a</manas:verzexml>
<manas:druhtisku>U_Tisk2P/2159405/TRUE</manas:druhtisku>
</manas:qr00>
<manas:qr00>
<manas:verzemanas>26052710</manas:verzemanas>
<manas:verzexml>2016.03.30a</manas:verzexml>
<manas:druhtisku>U_Tisk2P/FALSE</manas:druhtisku>
</manas:qr00>
</manas:usb>
I need to save values of: manas:verzemanas ; manas:verzexml ;
I have this code:
XmlDocument doc = new XmlDocument();
doc.Load("d:\\83116623.XML");
foreach (XmlNode node in doc.DocumentElement)
{
string name = node.Attributes[0].ToString();
}
Have you any ideas please?
You're probably better off with XDocument. Also you need to use the namespace prefix. E.g.:
XNamespace ns = "http://www.manas.info/";
var xdoc = XDocument.Load(#"c:\temp\a\a.xml");
var verze = xdoc.Root.Elements(ns + "qr00")
.Elements(ns + "verzemanas")
.Select(e => e.Value);
verze.ToList().ForEach(v => Console.WriteLine(v));
prints
26052708
26052710
This is the result of an online xml :
<prices targetNamespace="http://api.saxo.com/v1/prices/">
<price>
<id>28924741-0-0-1-0-1-0</id>
<quantity type="integer">1</quantity>
<normalprice type="decimal">49,95</normalprice>
<price type="decimal">49,95</price>
<vatpercent type="decimal">25,00</vatpercent>
<fixedprice>false</fixedprice>
<discount type="decimal">0,00</discount>
<allowdiscount type="integer">1</allowdiscount>
<productid>28924741</productid>
<entries>
<entry>
<id>1</id>
<type type="PriceEntryType">Standard</type>
<quantity type="integer">1</quantity>
<vatpercent type="decimal">25,00</vatpercent>
<vatamount type="decimal">9,99</vatamount>
<priceunitexvat type="decimal">39,96</priceunitexvat>
<priceunitinclvat type="decimal">49,95</priceunitinclvat>
<pricetotalexvat type="decimal">39,96</pricetotalexvat>
<pricetotalinclvat type="decimal">49,95</pricetotalinclvat>
<discountpercent type="decimal">0,00</discountpercent>
<discountamountexvat type="decimal">0,00</discountamountexvat>
<discountamountinclvat type="decimal">0,00</discountamountinclvat>
</entry>
<entry>
<id>2</id>
<type type="PriceEntryType">Context</type>
<quantity type="integer">1</quantity>
<vatpercent type="decimal">25,00</vatpercent>
<vatamount type="decimal">9,99</vatamount>
<priceunitexvat type="decimal">39,96</priceunitexvat>
<priceunitinclvat type="decimal">49,95</priceunitinclvat>
<pricetotalexvat type="decimal">39,96</pricetotalexvat>
<pricetotalinclvat type="decimal">49,95</pricetotalinclvat>
<discountpercent type="decimal">0,00</discountpercent>
<discountamountexvat type="decimal">0,00</discountamountexvat>
<discountamountinclvat type="decimal">0,00</discountamountinclvat>
</entry>
<entry>
<id>3</id>
<type type="PriceEntryType">Subscription</type>
<quantity type="integer">1</quantity>
<vatpercent type="decimal">25,00</vatpercent>
<vatamount type="decimal">6,99</vatamount>
<priceunitexvat type="decimal">27,96</priceunitexvat>
<priceunitinclvat type="decimal">34,95</priceunitinclvat>
<pricetotalexvat type="decimal">27,96</pricetotalexvat>
<pricetotalinclvat type="decimal">34,95</pricetotalinclvat>
<discountpercent type="decimal">30,03</discountpercent>
<discountamountexvat type="decimal">12,00</discountamountexvat>
<discountamountinclvat type="decimal">15,00</discountamountinclvat>
</entry>
</entries>
</price>
</prices>
I tried many ways to get value of "normalprice" and "pricetotalinclvat" of last entry . but i got null or exception .
Can you guide me that how i can get those two values by using linq ?
Looks like a possible duplication of this
The short version is:
XElement element = XElement.Parse(YourString);
var prices = element.Elements("price")
.Select(item => item.Element("normalprice").Value);
These values can be extracted using Descendant in combination with Last:
var xml = XElement.Parse(xmlStr);
var normalPrice = xml
.Descendants("normalprice")
.Last()
.Value;
var pricetotalinclvat = xml
.Descendants("pricetotalinclvat")
.Last()
.Value;
If approach does not matter, loading the contents into an XDocument and accessing via XPath would seem to make more sense in this situation:
You will want to be using the System.Xml.XPath namespace with this...
System.Xml.Linq.XDocument xdoc = System.Xml.Linq.XDocument.Parse(xmlString);
decimal priceNormal = 0;
decimal.TryParse(xdoc.XPathSelectElement(#"/prices/price/normalprice").Value, out priceNormal);
decimal priceTotalInclvat = 0;
decimal.TryParse(xdoc.XPathSelectElement(#"/prices/price/entry[last()]/pricetotalinclvat").Value, out priceTotalInclvat);
You can try this:
XDocument doc = XDocument.Load(path);
var query = from price in doc.Descendants("price")
select new
{
NormalPrice = price.Element("normalprice").Value,
PriceTotalInclVat = price.Descendants("entry").Last().Element("pricetotalinclvat").Value
};
To avoid a null exception in case you don't have entries you can also do this:
var query = from price in doc.Descendants("price")
select new
{
NormalPrice = price.Element("normalprice").Value,
PriceTotalInclVat = price.Descendants("entry").Any()?price.Descendants("entry").Last().Element("pricetotalinclvat").Value:"0"
};
Or:
var query = from price in doc.Descendants("price")
let entries = price.Descendants("entry")
select new
{
NormalPrice = price.Element("normalprice").Value,
PriceTotalInclVat = entries!=null ? entries.Last().Element("pricetotalinclvat").Value : "0"
};
I tried all of the solutions in this page but i did not get any result . it is so weird .this is what i did , but it is not a good way :
var document = XDocument.Load(url);
var root = document.Root;
if (root == null)
return;
var ns = root.GetDefaultNamespace();
var mainNode = document.Element(ns + "prices");
if (mainNode == null)
return;
var priceNode = mainNode.Elements(ns + "price").FirstOrDefault().Elements();
var lastEntry = mainNode.Elements(ns + "price").FirstOrDefault().Elements().Last().Elements().Last().Elements();
foreach (var element in lastEntry.Where(element => element.Name.LocalName == "pricetotalinclvat"))
{
plusPrice = element.Value;
}
foreach (var element in priceNode.Where(xElement => xElement.Name.LocalName == "price"))
{
price = element.Value;
}
Any Suggestion to make it better ?
I have a xml structure like this. Can anyone help with a simple linq function to read this xml structure.The itemEntry node repeats according to data. I tried to read the xml using the method below,but i am getting no records in the list. Is this method here correct way to get the details...
List<CX_ITEMLIST> sList =
(from e in XDocument.Load(param.FileName).Root.Elements("itemEntry")
select new CX_ITEMLIST
{
TITLE = (string)e.Element("title"),
YEAR = (string)e.Element("year"),
ITEMNAME = (string)e.Element("itemname"),
CATRYLIST =
(
from p in e.Elements("categorylist").Elements("categories")
select new CATLIST
{
IDTYPE = (string)p.Element("categoryid"),
IDNUMBER = (string)p.Element("categoryName")
}).ToList()
}).ToList();
<itemslist>
<itemInformation>
<itemdate>01/23/2014</itemdate>
<itemcount>57</itemcount>
</itemInformation>
<itemEntry>
<title>Title1</title>
<year>2013</title>
<itemname>testname</itemname>
<categorylist>
<categories>
<categoryid>Category1</categoryid>
<categoryName>Category2</categoryName>
</categories>
<categories>
<categoryid>Category1</categoryid>
<categoryName>Category2</categoryName>
</categories>
</categorylist>
</itemEntry>
<itemEntry>
<title>Title1</title>
<year>2013</title>
<itemname>testname</itemname>
<categorylist>
<categories>
<categoryid>Category1</categoryid>
<categoryName>Category2</categoryName>
</categories>
<categories>
<categoryid>Category1</categoryid>
<categoryName>Category2</categoryName>
</categories>
</categorylist>
</itemEntry>
</itemslist>
You should try with XDocument.
XDocument xdoc = XDocument.Load("file.xml");
The System.Xml.XLinq namespace contains some awesome objects to make this easy.
var xDoc = XDocument.Parse(xml); // load your xml string, or use XDocument.Load() to load an xml file
var itemEntries = xDoc
.Root // refers to itemEntries node
.Descendants("itemEntry"); // gets all itemEntry nodes in an IEnumerable object
This gets you an IEnumerable<XNode> of all the itemEntry nodes.
From there you can do what you need, save the values to a business object, etc.
The above method works properly, i found the issue, my xml tag was having namespace attribute. i tried to get the namespace and append it with Elements while reading
XNamespace ns = xDocument.Root.Attribute("xmlns").Value;
List<CX_ITEMLIST> sList =
(from e in XDocument.Load(param.FileName).Root.Elements(ns + "itemEntry")
select new CX_ITEMLIST
{
TITLE = (string)e.Element(ns + "title"),
YEAR = (string)e.Element(ns + "year"),
ITEMNAME = (string)e.Element(ns + "itemname"),
CATRYLIST =
(
from p in e.Elements(ns + "categorylist").Elements(ns + "categories")
select new CATLIST
{
IDTYPE = (string)p.Element(ns + "categoryid"),
IDNUMBER = (string)p.Element(ns + "categoryName")
}).ToList()
}).ToList();
I am coding for WP7. I am expecting this code below to read the XML below:
_xml = XElement.Parse(e.Result);
results.Items.Clear();
foreach (XElement value in _xml
.Descendants("ResourceSets").Descendants("ResourceSet")
.Descendants("Resources").Descendants("Location"))
{
Results _item = new Results();
_item.Place = value.Element("Name").Value;
_item.Lat = value.Element("Point").Element("Latitude").Value;
_item.Long = value.Element("Point").Element("Longitude").Value;
results.Items.Add(_item);
}
But the foreach loop wont read it and place it in the _items.
<?xml version="1.0" encoding="utf-8" ?>
<Response xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.microsoft.com/search/local/ws/rest/v1">
<Copyright>Copyright © 2011 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>703e7f1427dd425185ded546ba8a0d2c|LTSM001154|02.00.126.3000|LTSMSNVM002008, LTSMSNVM001854, LTSMSNVM001853</TraceId>
<ResourceSets>
<ResourceSet>
<EstimatedTotal>4</EstimatedTotal>
<Resources>
<Location>
<Name>Ashford, Kent, United Kingdom</Name>
<Point>
<Latitude>51.146636679768562</Latitude>
<Longitude>0.87603025138378143</Longitude>
</Point>
<BoundingBox>
<SouthLatitude>51.076602190732956</SouthLatitude>
<WestLongitude>0.72853825986385345</WestLongitude>
<NorthLatitude>51.21656522154808</NorthLatitude>
<EastLongitude>1.0235222429037094</EastLongitude>
</BoundingBox>
<EntityType>PopulatedPlace</EntityType>
<Address>
<AdminDistrict>England</AdminDistrict>
<AdminDistrict2>Kent</AdminDistrict2>
<CountryRegion>United Kingdom</CountryRegion>
<FormattedAddress>Ashford, Kent, United Kingdom</FormattedAddress>
<Locality>Ashford</Locality>
</Address>
<Confidence>High</Confidence>
</Location>
</Resources>
</ResourceSet>
</ResourceSets>
</Response>
It looks like you're missing the namespace on each of your element names. Try this:
XNamespace xns = "http://schemas.microsoft.com/search/local/ws/rest/v1";
_xml = XElement.Parse(e.Result);
results.Items.Clear();
foreach (XElement value in _xml
.Descendants(xns + "ResourceSets").Descendants(xns + "ResourceSet")
.Descendants(xns + "Resources").Descendants(xns + "Location"))
{
Results _item = new Results();
_item.Place = value.Element(xns + "Name").Value;
_item.Lat = value.Element(xns + "Point").Element(xns + "Latitude").Value;
_item.Long = value.Element(xns + "Point").Element(xns + "Longitude").Value;
results.Items.Add(_item);
}
Is there a particular reason why you're using Descendants?
You could just do:
XmlDocument doc = new XmlDocument();
doc.Load(YourXMLPath);
XmlNode locationNode = doc["ResourceSets"]["ResourceSet"]["Resources"]["Location"];
foreach(XmlElement value in locationNode.Children)
{
Results _item = new Results();
_item.Place = value.Element("Name").Value;
_item.Lat = value.Element("Point").Element("Latitude").Value;
_item.Long = value.Element("Point").Element("Longitude").Value;
results.Items.Add(_item);
}
I don't have VS right now, but that should be close to it.
Of course a good behavior would be to check if nodes are null before getting the next one.
public ObservableCollection<Results> result = new ObservableCollection<Results>();
XDocument xmldoc = XDocument.Parse(e.Result.ToString());
var data = from c in xmldoc.Descendants("ResourceSets").Descendants("ResourceSet").Descendants("Resources").Descendants("Location")
select new Results{
Place = c.Element("Name").Value;
Lat = c.Element("Point").Element("Latitude").Value;
Long = c.Element("Point").Element("Longitude").Value;
};
foreach (Results obj in data)
{
result.Add(obj);
}
Have not tried, but this is how I do it.