从CSV文件中提取数据(融合表和kml解决方法)

本文关键字:kml 解决 方法 融合 文件 CSV 提取 数据 | 更新日期: 2023-09-27 17:59:20

在Xamarin谷歌地图Android版中,使用C#,您可以根据本教程创建这样的多边形:

    public void OnMapReady(GoogleMap googleMap)
    {
        mMap = googleMap;
        PolylineOptions geometry = new PolylineOptions()
        .Add(new LatLng(37.35, -37.0123))
        .Add(new LatLng(37.35, -37.0123))
        .Add(new LatLng(37.35, -37.0123));

        Polyline polyline = mMap.AddPolyline(geometry);
    }

然而,我已经从谷歌地图的Fusion Table Layer下载了一个CSV文件,因为我认为这可能是处理多边形/多段线数据的最简单选项。输出如下:

    description,name,label,geometry
    ,Highland,61,"<Polygon><outerBoundaryIs><LinearRing><coordinates>-5.657018,57.3352 -5.656396,57.334463 -5.655076,57.334556 -5.653439,57.334477 -5.652366,57.334724 -5.650064,57.334477 -5.648096,57.335082 -5.646846,57.335388 -5.644733,57.335539 -5.643309,57.335428 -5.641981,57.335448 -5.640451,57.33578 -5.633217,57.339118 -5.627278,57.338921 -5.617161,57.337649 -5.607948,57.341015 -5.595812,57.343583 -5.586043,57.345373 -5.583581,57.350648 -5.576851,57.353609 -5.570088,57.354017 -5.560732,57.354102 -5.555254,57.354033 -5.549713,57.353146 -5.547766,57.352275 -5.538932,57.352255 -5.525891,57.356217 -5.514888,57.361865 -5.504272,57.366027 -5.494515,57.374515 -5.469829,57.383765 -5.458661,57.389781 -5.453695,57.395033 -5.454057,57.402943 -5.449189,57.40731 -5.440583,57.411447 -5.436133,57.414616 -5.438312,57.415474 -5.438628,57.417955 -5.440956,57.417909 -5.444013,57.414976 -5.450778,57.421362 -5.455035,57.422333 -5.462081,57.420719 -5.468775,57.416975 -5.475205,57.41135 -5.475976,57.409117 -5.47705,57.407092 -5.478101,57.406056 -5.478901,57.40536 -5.479489,57.404534 -5.480051,57.403782 -5.481036,57.403107 -5.484538,57.402102 -5.485647,57.401856 -5.487358,57.401287 -5.488709,57.400962 -5.490175,57.400616 -5.491116,57.400176 -5.493832,57.399318 -5.495279,57.399134 -5.496726,57.39771 -5.498724,57.396836 -5.49974,57.396314 -5.501317,57.39627 -5.502869,57.395426</coordinates></LinearRing></innerBoundaryIs></Polygon>"
    ,Strathclyde,63,"<Polygon><outerBoundaryIs><LinearRing><coordinates>-5.603129,56.313564 -5.603163,56.312536 -5.603643,56.311794 -5.601467,56.311875 -5.601038,56.312481 -5.600697,56.313489 -5.60071,56.31535 -5.60159,56.316107 -5.600729,56.316598 -5.598625,56.316058 -5.596203,56.317477 -5.597024,56.318119 -5.596095,56.318739 -5.595432,56.320116 -5.589343,56.322469 -5.584888,56.325178 -5.582907,56.327169 -5.581414,56.327472 -5.581435,56.326663 -5.582355,56.325602 -5.581515,56.323891 -5.576993,56.331062 -5.57886,56.331475 -5.57676,56.334449 -5.572748,56.335689 -5.569012,56.338143 -5.564802,56.342113 -5.555237,56.346668 -5.551214,56.347448 -5.547651,56.346391 -5.54444,56.344945 -5.541247,56.345945 -5.539099,56.349674 -5.533874,56.34763 -5.525195,56.342888 -5.523518,56.345066 -5.52345,56.346605 -5.526417,56.354361 -5.535455,56.353681 -5.537463,56.35508 -5.536035,56.356271 -5.538923,56.357205 -5.53891,56.359336 -5.539952,56.361491 -5.538102,56.36372 -5.535934,56.36567 -5.53392,56.367705 -5.531369,56.369729 -5.529853,56.371022 -5.532371,56.371274 -5.534177,56.371708 -5.532846,56.373256 -5.529845,56.37496 -5.527675,56.375327 -5.528531,56.375995 -5.526732,56.376343 -5.525442,56.377809 -5.524739,56.379843 -5.526069,56.380561</coordinates></LinearRing></innerBoundaryIs></Polygon>"

我上传了一个KML文件到Google Maps Fusion Table Layer,然后它创建了地图。然后我去File>Download>CSV,它给了我上面的例子。

我已经将这个csv文件添加到了我的xamarin android谷歌地图应用程序的资产文件夹中,我的问题是,因为LatLng需要两倍的输入,有没有办法将csv文件中的上述数据输入到这个方法中?如果有,如何输入?

不知道如何read the above csv,然后提取<coordinates>,然后在上面的示例代码中添加这些坐标作为新的LatLng

然而,如果您注意到坐标被拆分为lat和lng,然后下一个latlng空间-5.657018,57.3352 -5.656396,57.334463分隔。

Sudo代码(这可能需要也可能不需要xamarin或android经验,可能只需要C#/Linq)

Read CSV var sr = new StreamReader(Read csv from Asset folder);
Remove description,name,label,geometry
Foreach line in CSV
  Extract Item that contains double qoutes
     Foreach Item Remove Qoutes and <Polygon><outerBoundaryIs><LinearRing><coordinates> from start and end
         Foreach item seperated by a space Extract coordinates
       (This will now leave a long list of 37.35,-37.0123 coordinates for each line)
        Place in something like this maybe?:
    public class Row
    {
        public double Lat { get; set; }
        public double Lng { get; set; }
        public Row(string str)
        {
            string[] separator = { "," };
            var arr = str.Split(separator, StringSplitOptions.None);
            Lat = Convert.ToDouble(arr[0]);
            Lng = Convert.ToDouble(arr[1]);
        }
    }

    private void OnMapReady()
    var rows = new List<Row>();
      Foreach name/new line
         PolylineOptions geometry = new PolylineOptions()
           ForEach (item in rows) //not sure how polyline options will take a foreach
            .Add(New LatLng(item.Lat, item.Lng))
         Polyline polyline = mMap.AddPolyline(geometry);

由于无法在Xamarin Android中使用Fusion Table Layers和Google Maps API v2,这可能会为那些需要将地图拆分为区域的人提供一种快速而简单的解决方法。

从CSV文件中提取数据(融合表和kml解决方法)

如果我理解正确,问题是如何解析上面的CSV文件。

每一行(除了第一个带标题的行)都可以用以下类表示:

class MapEntry
{
    public string Description { get; set; }
    public string Name { get; set; }
    public string Label { get; set; }
    public IEnumerable<LatLng> InnerCoordinates { get; set; }
    public IEnumerable<LatLng> OuterCoordinates { get; set; }
}

注意InnerOuter坐标。它们在XML中由outerBoundaryIs(必需)和innerBoundaryIs(可选)元素表示。

附带说明:您文章中的Highland行是不正确的——您似乎修剪了部分行,导致了不正确的XML(<outerBoundaryIs>...</innerBoundaryIs>)。

以下是进行解析的代码:

static IEnumerable<MapEntry> ParseMap(string csvFile)
{
    return from line in File.ReadLines(csvFile).Skip(1)
           let tokens = line.Split(new[] { ',' }, 4)
           let xmlToken = tokens[3]
           let xmlText = xmlToken.Substring(1, xmlToken.Length - 2)
           let xmlRoot = XElement.Parse(xmlText)
           select new MapEntry
           {
               Description = tokens[0],
               Name = tokens[1],
               Label = tokens[2],
               InnerCoordinates = GetCoordinates(xmlRoot.Element("innerBoundaryIs")),
               OuterCoordinates = GetCoordinates(xmlRoot.Element("outerBoundaryIs")),
           };
}
static IEnumerable<LatLng> GetCoordinates(XElement node)
{
    if (node == null) return Enumerable.Empty<LatLng>();
    var element = node.Element("LinearRing").Element("coordinates");
    return from token in element.Value.Split(' ')
           let values = token.Split(',')
           select new LatLng(XmlConvert.ToDouble(values[0]), XmlConvert.ToDouble(values[1]));
}

我认为代码是不言自明的。唯一需要提及的细节是:

let tokens = line.Split(new[] { ',' }, 4)

在这里,我们使用string.Split重载,它允许指定返回的最大子字符串数,从而避免了处理XML令牌中逗号的陷阱。

和:

let xmlText = xmlToken.Substring(1, xmlToken.Length - 2)

其从XML令牌中去除引号。

最后,为您的案例提供一个示例用法:

foreach (var entry in ParseMap(csv_file_full_path))
{
    PolylineOptions geometry = new PolylineOptions()
    foreach (var item in entry.OuterCoordinates)
        geometry.Add(item)
    Polyline polyline = mMap.AddPolyline(geometry);
}

更新:要让Xamarin高兴(如注释中所述),请将File.ReadLines调用替换为对以下助手的调用:

static IEnumerable<string> ReadLines(string path)
{
    var sr = new StreamReader(Assets.Open(path));
    try
    {
        string line;
        while ((line = sr.ReadLine()) != null)
            yield return line; 
    }
    finally { sr.Dispose(); }
}

我不确定是否理解您的问题,但我认为这会有所帮助:

您必须逐行读取csv文件,foreach行提取第三个参数,删除引号,并使用XMLReader读取结果,以提取所需的行(坐标)。在空白处分割结果后,您会得到LatLng的列表,并在","上分割每个LatLng,然后您就得到了所需的所有信息。

System.IO.StreamReader file = new System.IO.StreamReader(@"file.csv");
string line = file.ReadLine(); //escape the first line
while((line = file.ReadLine()) != null)
{
    var xmlString = line.Split({","})[2]; // or 3
    **Update**
    xmlString = xmlString.Replace("'"","")
    using (XmlReader reader = XmlReader.Create(new StringReader(xmlString)))
    {
        reader.ReadToFollowing("coordinate");
        string coordinate = reader.Value;
        PolylineOptions geometry = new PolylineOptions();
        var latLngs = coordinate.Split({' '});
        foreach (var latLng in latLngs)
        {
            double lat = 0;
            double lng = 0;
            var arr = latLng.Split({','});
            double.TryParse(arr[0], out lat);
            double.TryParse(arr[1], out lng);
            geometry.Add(new LatLng(lat, lng));
        }
        Polyline polyline = mMap.AddPolyline(geometry);
        // Do something with your polyline
    }
}
file.Close();
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Xml.Linq;
namespace ConsoleApplication35
{
    public class LatLng
    {
        public LatLng(double lat, double lng)
        {
        }
    }
    class Program
    {
        private static IEnumerable<LatLng> GetCoordinates(string polygon)
        {
            var xElement = XElement.Parse(polygon);
            //var innerBoundaryCoordinates = xElement.Elements("innerBoundaryIs").FirstOrDefault()?.Value ?? "";
            var outerBoundaryCoordinates = xElement.Elements("outerBoundaryIs").Single()?.Value ?? "";
            return outerBoundaryCoordinates
                .Split(' ')
                .Select(latLng =>
                {
                    var splits = latLng.Split(',');
                    var lat = double.Parse(splits[0], CultureInfo.InvariantCulture);
                    var lng = double.Parse(splits[1], CultureInfo.InvariantCulture);
                    return new LatLng(lat, lng);
                });
        }
        static void Main()
        {
            const string header = "description,name,label,geometry";
            var latLngs = File.ReadLines("file.csv")
                              .SelectMany(x => x.Split(new[] { header }, StringSplitOptions.RemoveEmptyEntries)) //all geometry`s in one array
                              .Select(x => x.Split('"'))
                              .SelectMany(x => GetCoordinates(x[1]))
                              .ToArray();
        }
    }
}