none
xmlから結果を抜き出したい RRS feed

  • 質問

  • いつもお世話になります。
    VisualC#2010、WindowsXPでの動作について質問があります。
    下記のxml文書から、fictionの場合の結果のみを抜き出したいと考えています。

    <?xml version="1.0" encoding="UTF-8" ?>
    <ResultSet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:test:jp:jlp" xsi:schemaLocation="urn:test:jp:jlp http://jlp.testapis.jp/Service/photoResponse.xsd">
    <allresult>
    <total_count>4</total_count>
    <filtered_count>4</filtered_count>
    <name_list>
     <name><view>明智小五郎</view><kana>あけちこごろう</kana><status>fiction</status></name>
     <name><view>明智光秀</view><kana>あけちみつひで</kana><status>real</status></name>
     <name><view>遠藤平吉</view><kana>えんどうへいきち</kana><status>fiction</status></name>
     <name><view>遠藤周作</view><kana>えんどうしゅうさく</kana><status>real</status></name>
    </name_list>
    </uniq_result>
    </ResultSet>

    XDocument xdoc = XDocument.Parse(xml);
    string answer = "";
    var query = from result in xdoc.Root.Elements("allresult").Elements("name_list").Elements("name")
    where result.Elements("status").Value == "fiction"
    select new{
     list = result.Elements("view").Value
    };
     foreach (var q in query) answer += q.list;

    とコードを書くと、
    where result.Elements("status").Value == "fiction"
    list = result.Elements("view").Value
    の行で、.Valueはないとエラーになります。
    そこで、そこをToString()にしてみたのですが、コンパイルはできるのですが、実行すると、nullになってエラーとなります。
    xdoc.Root.Elements("allresult")
    のところで、xdocのRootにあるのは、ResultSetなので、from result in xdoc.Root.Elements("ResultSet").Elements("allresult").Elements("name_list").Elements("name")
    としてもだめでした。
    名前空間かと思って、
    XNamespace xnamespace = "urn:test:jp:jlp";
    XNamespace xnamespace = "http://www.w3.org/2001/XMLSchema-instance";
    のように指定してみてもダメでした。
    添削よろしくお願いします。

    2010年10月10日 14:50

回答

  • Elements メソッドは、最後の s の通りその名前の子要素のコレクションを取得します。コレクションに対して「その要素の値は?」と聞いても当然答えられません。

    「最初の子要素」を取得する Element メソッドを使えば良いんではないでしょうか。

    • 回答としてマーク HANA01 2010年10月11日 4:28
    2010年10月10日 17:35
  • XML名前空間を使っているので、ElementやElementsで子要素を取得するときに、要素名だけでなくXNamespaceも指定する必要があります。

    こんな感じになります。

    XDocument xdoc = XDocument.Load("sample.xml");
    var ns = XNamespace.Get("urn:test:jp:jlp");
    var query = from result in xdoc.Root
                    .Element(ns + "allresult")
                    .Element(ns + "name_list")
                    .Elements(ns + "name")
          where result.Element(ns + "status").Value == "fiction"
          select new {
            list = result.Element(ns + "view").Value
          };
    
    


    なかむら(http://d.hatena.ne.jp/griefworker)
    • 回答としてマーク HANA01 2010年10月11日 4:28
    2010年10月11日 1:09
  • 動作は確認していませんが、こんな感じでしょうか?

    Elementsは子要素のコレクションを返すので、Valueプロパティが無いようです。

    あと、Xml定義に関してですが、allresultノードが閉じられていません。ご確認ください。

     

                var xdoc = XDocument.Parse(xml);
                string answer = "";
                var query = from result in xdoc.Root.Elements("allresult")
                                                    .Elements("name_list")
                                                    .Elements("name")
                            where result.Element("name").Value == "fiction"
                            select new {list = result.Value };
                foreach (var q in query) answer += q.list;

     

    • 回答としてマーク HANA01 2010年10月11日 4:28
    2010年10月11日 1:23

すべての返信

  • Elements メソッドは、最後の s の通りその名前の子要素のコレクションを取得します。コレクションに対して「その要素の値は?」と聞いても当然答えられません。

    「最初の子要素」を取得する Element メソッドを使えば良いんではないでしょうか。

    • 回答としてマーク HANA01 2010年10月11日 4:28
    2010年10月10日 17:35
  • XML名前空間を使っているので、ElementやElementsで子要素を取得するときに、要素名だけでなくXNamespaceも指定する必要があります。

    こんな感じになります。

    XDocument xdoc = XDocument.Load("sample.xml");
    var ns = XNamespace.Get("urn:test:jp:jlp");
    var query = from result in xdoc.Root
                    .Element(ns + "allresult")
                    .Element(ns + "name_list")
                    .Elements(ns + "name")
          where result.Element(ns + "status").Value == "fiction"
          select new {
            list = result.Element(ns + "view").Value
          };
    
    


    なかむら(http://d.hatena.ne.jp/griefworker)
    • 回答としてマーク HANA01 2010年10月11日 4:28
    2010年10月11日 1:09
  • 動作は確認していませんが、こんな感じでしょうか?

    Elementsは子要素のコレクションを返すので、Valueプロパティが無いようです。

    あと、Xml定義に関してですが、allresultノードが閉じられていません。ご確認ください。

     

                var xdoc = XDocument.Parse(xml);
                string answer = "";
                var query = from result in xdoc.Root.Elements("allresult")
                                                    .Elements("name_list")
                                                    .Elements("name")
                            where result.Element("name").Value == "fiction"
                            select new {list = result.Value };
                foreach (var q in query) answer += q.list;

     

    • 回答としてマーク HANA01 2010年10月11日 4:28
    2010年10月11日 1:23
  • アドバイスありがとうございます。
    from result in xdoc.Root.Elements("allresult").Elements("name_list").Elements("name")
    を、
    from result in xdoc.Root.Element("allresult").Element("name_list").Elements("name")
    にしました。
    Elementは単独で、Elementsは配列ということなのでしょうか。

    それで、デバッグで実行してみると、
     foreach (var q in query) answer += q.list;
    のところで、qのbase-valueというところに、明智小五郎という値が入っているのは見えたのですが、このとおり実行していくと、answerには、
    System.Xml.Linq.XContainer+<GetElements>d__11
    という文字列しか入りません。
    q.list;
    でなくて、別の書き方をしないとだめっぽいのですが、
    q.Valueとかではだめみたいです。
    ここはどうしたらよいでしょう?

    2010年10月11日 4:16
  • みなさんありがとうございます。
    その後もいろいろ試していて、xnamespaceが邪魔なので、
    xml = xml.Replace("<ResultSet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:test:jp:jlp" xsi:schemaLocation="urn:test:jp:jlp http://jlp.testapis.jp/Service/photoResponse.xsd">","");
    とかやって、namespaceを削除してみたりしていましたが、いまいちわかっていませんでしたが、わかりました!
    ElementsとElementは別だったのですね。

    where result.Elements("status").Value == "fiction"
    select new{
     list = result.Elements("view").Value

    where result.Element("status").Value == "fiction"
    select new{
     list = result.Element("view").Value
    としたところ、Valueを取り出せて、うまくいきました。

    XML定義ですが、適当に上半分抜いたところ、閉じてないように見えましたが、オリジナルのデータは閉じてありました。
    ありがとうございました。

    2010年10月11日 4:28