【发布时间】: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>
由于我只对提取 <NavigationPosition> 节点中的内容真正感兴趣,我想我可以编写如下代码:
用于检索 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,将其转换为字符串然后解析。 -
您可以通过在请求中设置
reponseattributes和locationattributes参数来简化响应,例如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!我错过了(虽然我仔细查看了文档,但我想)。谢谢!我没有看到(并阅读)任何关于
reponseattributes和locationattributes的默认行为的信息 - 从文档的外观来看,将它们设置为 none 不会给出任何位置(甚至不是 lat/lng)......跨度>