我正在尝试从Google的地理编码API中解析出一些信息,但我在从xml中有效地获取数据方面遇到了一些麻烦。 See link for example
我真正关心的是short_name
来自address_component
类型为administrative_area_level_1
而long_name
来自administrative_area_level_2
但是,对于我的测试程序,我的XPath查询不会为两个查询返回任何结果。
public static void Main(string[] args)
{
using(WebClient webclient = new WebClient())
{
webclient.Proxy = null;
string locationXml = webclient.DownloadString("http://maps.google.com/maps/api/geocode/xml?address=1600+Amphitheatre+Parkway,+Mountain+View,+CA&sensor=false");
using(var reader = new StringReader(locationXml))
{
var doc = new XPathDocument(reader);
var nav = doc.CreateNavigator();
Console.WriteLine(nav.SelectSingleNode("/GeocodeResponse/result/address_component[type=administrative_area_level_1]/short_name").InnerXml);
Console.WriteLine(nav.SelectSingleNode("/GeocodeResponse/result/address_component[type=administrative_area_level_2]/long_name").InnerXml);
}
}
}
任何人都可以帮我找到我做错了什么,或推荐更好的方法吗?
答案 0 :(得分:4)
您需要将您要查找的节点的值放在引号中:
".../address_component[type='administrative_area_level_1']/short_name"
↑ ↑
答案 1 :(得分:4)
我绝对建议使用LINQ to XML而不是XPathNavigator。根据我的经验,它使XML查询变得轻而易举。在这种情况下,我不确定到底出了什么问题......但我会想出一个LINQ to XML片段。
using System;
using System.Linq;
using System.Net;
using System.Xml.Linq;
class Test
{
public static void Main(string[] args)
{
using(WebClient webclient = new WebClient())
{
webclient.Proxy = null;
string locationXml = webclient.DownloadString
("http://maps.google.com/maps/api/geocode/xml?address=1600"
+ "+Amphitheatre+Parkway,+Mountain+View,+CA&sensor=false");
XElement root = XElement.Parse(locationXml);
XElement result = root.Element("result");
Console.WriteLine(result.Elements("address_component")
.Where(x => (string) x.Element("type") ==
"administrative_area_level_1")
.Select(x => x.Element("short_name").Value)
.First());
Console.WriteLine(result.Elements("address_component")
.Where(x => (string) x.Element("type") ==
"administrative_area_level_2")
.Select(x => x.Element("long_name").Value)
.First());
}
}
}
现在这个 更多代码 1 ...但我个人觉得比XPath更容易,因为编译器对我有所帮助。
编辑:我觉得值得深入了解为什么我通常喜欢这样的代码而不是使用XPath,即使它显然更长。在C#程序中使用XPath时,您有两种不同的语言 - 但只有一种处于控制状态(C#)。 XPath被降级到字符串领域:Visual Studio没有给XPath表达式任何特殊处理;它不理解它意味着它是一个XPath表达式,所以它无法帮助你。并不是Visual Studio不了解XPath;正如Dimitre指出的那样,如果您正在编辑XSLT文件,它就完全能够发现错误,而不是C#文件。
只要您将一种语言嵌入另一种语言并且该工具不知道它,就会出现这种情况。常见的例子是:
当代码在另一种语言中显示为数据时,辅助语言会失去很多工具优势。
当可以上下文切换到整个地方时,将XPath(或SQL或正则表达式等)拉出到自己的工具中(可能在同一个实际程序中,但在一个单独的文件中)或窗口)从长远来看,我发现这使得难以阅读的代码成为可能。如果代码只是编写过,之后再也没有读过,那可能没问题 - 但是做之后需要能够读取代码,而且我个人认为,当发生这种情况时,可读性会受到影响。
上面的LINQ to XML版本只使用字符串表示纯数据 - 元素的名称等 - 并使用代码(方法调用)来表示诸如“查找具有给定名称的元素”或“应用此过滤器”之类的操作。在我看来,这是更惯用的C#代码。
显然其他人不同意这个观点,但我认为值得扩展以显示我来自哪里。
请注意,这当然不是一个快速的规则 ......在某些情况下,XPath,正则表达式等是最佳解决方案。在这种情况下,我更喜欢LINQ to XML,这就是全部。
1 当然我可以将每个Console.WriteLine
来电保留在一行,但我不喜欢在SO上发布带水平滚动条的代码。请注意,使用与上面相同的缩进编写正确的XPath版本并避免滚动仍然非常讨厌:
Console.WriteLine(nav.SelectSingleNode("/GeocodeResponse/result/" +
"address_component[type='administrative_area_level_1']" +
"/short_name").InnerXml);
通常,在Visual Studio中,长行比在Stack Overflow上工作好得多......
答案 2 :(得分:2)
我建议只输入XPath表达式作为Visual Studio中的XSLT文件的一部分。您将“在键入时”收到错误消息 - 这是一个出色的XML / XSLT / XPath编辑器。
例如,我正在输入:
<xsl:apply-templates select="@* | node() x"/>
并立即进入错误列表窗口,出现以下错误:
Error 9 Expected end of the expression, found 'x'. @* | node() -->x<--
XSLTFile1.xslt 9 14 Miscellaneous Files
只有当XPath表达式没有引发任何错误时(我也可能会测试它是否也选择了预期的节点),我是否会将此表达式放入我的C#代码。
这确保了在运行C#程序时我没有XPath - 语法和语义错误。
答案 3 :(得分:1)
dtb的回复准确无误。我想补充一点,您可以使用xpath测试工具,如下面的链接,以帮助找到正确的xpath:
答案 4 :(得分:0)
string url = @"http://maps.google.com/maps/api/geocode/xml?address=1600+Amphitheatre+Parkway,+Mountain+View,+CA&sensor=false";
string value = "administrative_area_level_1";
using(WebClient client = new WebClient())
{
string wcResult = client.DownloadString(url);
XDocument xDoc = XDocument.Parse(wcResult);
var result = xDoc.Descendants("address_component")
.Where(p=>p.Descendants("type")
.Any(q=>q.Value.Contains(value))
);
}
结果是“address_component”的枚举,其中至少有一个“type”节点包含您要搜索的值。上面查询的结果是包含以下数据的XElement。
<address_component>
<long_name>California</long_name>
<short_name>CA</short_name>
<type>administrative_area_level_1</type>
<type>political</type>
</address_component>
我真的建议花一点时间来学习LINQ,因为它非常适用于操作和查询内存中对象,查询数据库,并且在使用XML时比使用XPath更容易。我最喜欢的网站是http://www.hookedonlinq.com/