4

Google のジオコーディング API からいくつかの情報を解析しようとしていますが、xml からデータを効率的に取得するのに少し問題があります。たとえば、リンクを参照してください

私が本当に気にかけているのは、タイプがどこにあるかとshort_namefromを取得することだけですが 、私のテスト プログラムでは、私の XPath クエリは両方のクエリに対して結果を返しません。address_componentadministrative_area_level_1long_nameadministrative_area_level_2

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);

        }
    }
}

私が間違っていることを見つけたり、より良い方法を推奨したりするのを手伝ってくれる人はいますか?

4

5 に答える 5

4

探しているノードの値を引用符で囲む必要があります。

".../address_component[type='administrative_area_level_1']/short_name"
                            ↑                           ↑
于 2010-08-18T19:17:37.917 に答える
4

XPathNavigator の代わりに LINQ to XML を使用することを強くお勧めします。私の経験では、これにより 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 を使用すると、2 つの異なる言語が使用されますが、制御できるのは 1 つだけです (C#)。XPath は文字列の領域に追いやられます。Visual Studio は XPath 式に特別な処理を与えません。XPath 式であることを理解していないため、役に立ちません。Visual Studio が XPath を認識していないわけではありません。Dimitre が指摘しているように、C# ファイルではなく、XSLT ファイルを編集している場合、エラーを完全に見つけることができます。

これは、ある言語が別の言語に埋め込まれていて、ツールがそれを認識していない場合に当てはまります。一般的な例は次のとおりです。

  • SQL
  • 正規表現
  • HTML
  • XPath

コードが別の言語内でデータとして提示されると、2 次言語はそのツールの利点の多くを失います。

XPath(またはSQL、または正規表現など)を独自のツール(おそらく同じ実際のプログラム内ですが、別のファイルまたはウィンドウ内)に引き出して、あらゆる場所でコンテキストスイッチを切り替えることができますが、これは難しくなります-長期的にはコードを読む。コードが書かれただけで、その後に読み取られることがない場合は、それで問題ないかもしれませんが、後でコードを読み取れるようにする必要があります。

上記の LINQ to XML バージョンでは、純粋なデータ (要素の名前など) にのみ文字列を使用し、コード (メソッド呼び出し) を使用して、「指定された名前の要素を検索する」または「このフィルターを適用する」などのアクションを表します。私の見解では、それはより慣用的な C# コードです。

明らかに、他の人はこの視点を共有していませんが、私がどこから来たのかを示すために拡張する価値があると思いました.

もちろん、これは厳密で迅速なルールではないことに注意してください...場合によっては、XPath、正規表現などが最適なソリューションです。この場合、XML よりも LINQ を使用したいと思います。それだけです。


1もちろん、各呼び出しを 1 行にまとめることもできConsole.WriteLineましたが、SO に水平スクロールバーを含むコードを投稿するのは好きではありません。上記と同じインデントを使用して正しい XPath バージョンを記述し、スクロールを回避することは、依然としてかなり厄介であることに注意してください。

            Console.WriteLine(nav.SelectSingleNode("/GeocodeResponse/result/" +
                "address_component[type='administrative_area_level_1']" +
                "/short_name").InnerXml);

一般に、長い行は、スタック オーバーフローよりも Visual Studio の方がうまく機能します...

于 2010-08-18T19:18:25.967 に答える
2

Visual Studio で XSLT ファイルの一部として XPath 式を入力することをお勧めします。「入力すると」エラー メッセージが表示されます。これは優れた 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 (構文エラーとセマンティック エラー) が発生しないことが保証されます。

于 2010-08-19T20:19:59.410 に答える
1

dtb の応答は正確です。以下のリンクのような xpath テスト ツールを使用して、正しい xpath を見つけることができることを付け加えたいと思います。

http://www.bit-101.com/xpath/

于 2010-08-18T19:21:58.643 に答える
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))
                    );

}

結果は、検索している値を含む「type」ノードが少なくとも 1 つある「address_component」の列挙です。上記のクエリの結果は、次のデータを含む 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 を使用するよりも簡単な傾向があるため、LINQ 全般について少し時間をかけて学習することをお勧めします。参照する私のお気に入りのサイトはhttp://www.hookedonlinq.com/です

于 2010-08-18T19:59:51.513 に答える