无法从xml文件中获取数据

时间:2010-08-18 19:15:28

标签: c# xml xpath google-geocoder

我正在尝试从Google的地理编码API中解析出一些信息,但我在从xml中有效地获取数据方面遇到了一些麻烦。 See link for example

我真正关心的是short_name来自address_component类型为administrative_area_level_1long_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);

        }
    }
}

任何人都可以帮我找到我做错了什么,或推荐更好的方法吗?

5 个答案:

答案 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#文件。

只要您将一种语言嵌入另一种语言并且该工具不知道它,就会出现这种情况。常见的例子是:

  • SQL
  • 正则表达式
  • HTML
  • 的XPath

当代码在另一种语言中显示为数据时,辅助语言会失去很多工具优势。

可以上下文切换到整个地方时,将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:

http://www.bit-101.com/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/