【问题标题】:How to parse XML-Response in C# from Nokia-HERE Geocoding REST API如何从 Nokia-HERE Geocoding REST API 解析 C# 中的 XML-Response
【发布时间】:2014-12-15 10:43:44
【问题描述】:

简介

我正在用 C# 编写一个 WinForm 应用程序,我在其中请求给定地址的地图位置(纬度/经度)。

我利用诺基亚 HERE 地理编码 REST API 并请求一个 XML,然后我尝试对其进行解析。以下 API 调用来自诺基亚文档:

REST API 调用

http://geocoder.cit.api.here.com/6.2/geocode.xml?app_id=DemoAppId01082013GAL&app_code=AJKnXv84fjrb0KIHawS0Tg&gen=8&searchtext=425+W+Randolph+Chicago

此 API 调用返回一个 XML 流,如下所示(缩写):

XML 响应

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:Search xmlns:ns2="http://www.navteq.com/lbsp/Search-Search/4">
    <Response>
        <MetaInfo>
            <Timestamp>2014-12-15T10:11:29.197Z</Timestamp>
        </MetaInfo>
        <View xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ns2:SearchResultsViewType">
            <ViewId>0</ViewId>
            <Result>
                <Relevance>1.0</Relevance>
                <MatchLevel>houseNumber</MatchLevel>
                <MatchQuality>
                    <City>1.0</City>
                    <Street>0.9</Street>
                    <HouseNumber>1.0</HouseNumber>
                </MatchQuality>
                <MatchType>pointAddress</MatchType>
                <Location>
                    <LocationId>NT_krOz+rwboyk4Jvih55MwPB_425</LocationId>
                    <LocationType>address</LocationType>
                    <DisplayPosition>
                        <Latitude>41.8838692</Latitude>
                        <Longitude>-87.6389008</Longitude>
                    </DisplayPosition>
                    <NavigationPosition>
                        <Latitude>41.8844719</Latitude>
                        <Longitude>-87.6387711</Longitude>
                    </NavigationPosition>
                </Location>
            </Result>
        </View>
    </Response>
</ns2:Search>

由于我只对提取 &lt;NavigationPosition&gt; 节点中的内容真正感兴趣,我想我可以编写如下代码:

用于检索 XML 的 C# 代码片段

var req = (HttpWebRequest)WebRequest.Create("http://geocoder.cit.api.here.com/6.2/geocode.xml?app_id=DemoAppId01082013GAL&app_code=AJKnXv84fjrb0KIHawS0Tg&gen=8&searchtext=425+W+Randolph+Chicago");
req.Method = "GET";

req.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0) Gecko/20100101 Firefox/4.0";
req.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
req.ContentType = "application/x-www-form-urlencoded";

req.Timeout = 5000;
var resp = (HttpWebResponse)req.GetResponse();

var ms = new MemoryStream();
var rs = resp.GetResponseStream();
if (rs != null)
{
    var buf = new byte[4096];
    int len = 0;
    while ((len = rs.Read(buf, 0, buf.Length)) > 0)
    {
        ms.Write(buf, 0, len);
    }
    rs.Close();
}

var xml = new XmlDocument();
xml.LoadXml(Encoding.UTF8.GetString(ms.ToArray()));

var status = xml.SelectNodes("/ns2:Search/Response/View/Result[1]/Location/NavigationPosition");
if (status.Count == 1)
{

    var lat = xml.SelectNodes("/ns2:Search/Response/View/Result[1]/Location/NavigationPosition/Latitude");
    var lng = xml.SelectNodes("/ns2:Search/Response/View/Result[1]/Location/NavigationPosition/Longitude");
}

我必须知道我不能以这种方式解析这个特定的 XML,因为它包含命名空间前缀 (ns2)。所以我添加了命名空间管理器:

添加的命名空间管理器

XmlNamespaceManager nsmanager = new XmlNamespaceManager(xml.NameTable);
nsmanager.AddNamespace("ns2", "http://www.navteq.com/lbsp/Search-Search/4");

并将 xpath 查询 xml.SelectNodes() 更改为:

更新的 C# 代码

var status = xml.SelectNodes("/ns2:Search/Response/View/Result[1]/Location/NavigationPosition", nsmanager);
if (status.Count == 1)
{

    var lat = xml.SelectNodes("/ns2:Search/Response/View/Result[1]/Location/NavigationPosition/Latitude", nsmanager);
    var lng = xml.SelectNodes("/ns2:Search/Response/View/Result[1]/Location/NavigationPosition/Longitude", nsmanager);
}

我的问题

现在,添加了 NS 管理器后,我可以读取和解析 XML 响应了。

由于我只对第一个结果的 lat/lng 值感兴趣(可能有多个结果,多个结果节点),有没有办法避免可能的开销(由命名空间管理器引入也许)并更轻松地访问 lat/lng 值?由于我不需要解析整个响应,因此我可以重写用于检索 XML 响应的 c# 代码以提高效率吗?

【问题讨论】:

  • 一定要使用XmlDocument吗?命名空间与 LINQ to XML 一起使用要简单得多...
  • @JonSkeet 不,不需要 XmlDocument。我以前使用过很多次(即使用 Google Geocoder),因此在这个项目中实现了它。将研究 LINQ - 感谢您的提示!
  • 此外,无论您使用的是 LINQ to XML 还是 XmlDocument,我都建议 just 从流中解析。无需将流复制到MemoryStream,将其转换为字符串然后解析。
  • 您可以通过在请求中设置reponseattributeslocationattributes 参数来简化响应,例如http://geocoder.cit.api.here.com/6.2/geocode.xml?app_id=APP_ID&app_code=APP_CODE&gen=8&searchtext=TEXT &responseattributes=none&locationattributes=none&gen=8
  • 很好,@JasonFox!我错过了(虽然我仔细查看了文档,但我想)。谢谢!我没有看到(并阅读)任何关于 reponseattributeslocationattributes 的默认行为的信息 - 从文档的外观来看,将它们设置为 none 不会给出任何位置(甚至不是 lat/lng)......跨度>

标签: c# xml winforms here-api


【解决方案1】:

您可以获得的最小/最短响应是通过将 locationattributes 和 responseattributes 设置为“none”,将其与“maxresults=1”结合起来,根据我们的输入仅获得第一个最好的结果。例如,请参见下文。

http://geocoder.cit.api.here.com/6.2/geocode.xml?app_id=DemoAppId01082013GAL&app_code=AJKnXv84fjrb0KIHawS0Tg&gen=8&maxresults=1&locationattributes=none&responseattributes=none&searchtext=425%20W%20Randolph%20Chicago

这仍然包括导航位置(始终附加到街段)和显示位置。后来成为宗地质心,也就是屋顶,用于获得门牌号的精确结果。

【讨论】:

  • 感谢您提供maxresults=1 提示。 HERE API 文档 - 至少对我来说 - 有点误导。我将maxresults 的描述解释为分页指令。但是,使用 maxresult=1 只会给我一个结果(我猜是概率最高的那个)。
  • 感谢您对 Sebastian 的反馈,我们会接受并改进下一个版本的文档。
  • Philip,很高兴在这里见到 HERE 开发人员! HERE 是否有德国销售代表,您可以联系我(我知道,您在法兰克福)。 Frohe Weihnachten!
  • 嗨塞巴斯蒂安,当然。我在这里找不到与您联系的方法。我的全名是菲利普·休伯图斯。请查找我并取得联系。或者,您可以在我们的开发者门户上注册地理编码器计划。此页面有该计划的链接:developer.here.com/geocoder 这是一个深层链接:developer.here.com/get-started#/10134037
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-22
  • 2017-03-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-27
相关资源
最近更新 更多