C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[3]: 現在のタイトル番組を取得するLINQ to XML


(過去ログ 82 を表示中)

[トピック内 12 記事 (1 - 12 表示)]  << 0 >>

■48388 / inTopicNo.1)  現在のタイトル番組を取得するLINQ to XML
  
□投稿者/ インパラ (1回)-(2010/04/05(Mon) 00:29:47)

分類:[C#] 

C# VisualC# Express2008を使って開発をしています。
radikoの現在の番組を取得してみようと思いました。
http://radiko.jp/epg/epgapi.php?area_id=JP27&mode=now&station_id=TBS
から現在のタイトル番組を取得するLINQ to XMLはどう書けばよいでしょう?
htmlにhttp://radiko.jp/epg/epgapi.php?area_id=JP27&mode=now&station_id=TBSの内容が入っているとして、

XDocument xdoc = XDocument.Parse(html);
DateTime now = DateTime.Now.ToString("HH00")
var query = from Result in xdoc.Root.Elements()
select new{
		Name = Result.Element("radiko").Element("stations").Element("station").Element("scd").Element("name").Value,
		title = Result.Element("radiko").Element("stations").Element("station").Element("scd").Element("progs").Element("prog").Element("title").Value
		time = Result.Element("radiko").Element("stations").Element("station").Element("scd").Element("progs").Element("prog").Attribute("ftl").Value
		};
string nowonair;
foreach (var q in query){
	if(time.Contains(now) {
	nowonair += q.Name + "\t" + q.title + "\r\n";
	}
}
としてみたのですが、select句の部分がエラーです。
よろしくご指導お願いします。

引用返信 編集キー/
■48389 / inTopicNo.2)  Re[1]: 現在のタイトル番組を取得するLINQ to XML
□投稿者/ Hongliang (590回)-(2010/04/05(Mon) 01:30:09)
2010/04/05(Mon) 02:22:08 編集(投稿者)

この XML のルート要素は radiko 要素ですよね?
> var query = from Result in xdoc.Root.Elements()
この from 句は、ドキュメントのルート要素(Root)の子要素(Elements)を列挙しろ、という命令になります。
ルート要素は radiko ですから、その子要素は ttl 要素とか srvtime 要素とか stations 要素とかです。
それらの要素が Result に格納され、以後のクエリに使用されます。
で、ttl 要素にせよ stations 要素にせよ、その子要素に radiko 要素なんて持っていないので
> Name = Result.Element("radiko").
の時点でエラーが発生します。

おそらく列挙したいのは stations 要素の子要素である station 要素、及び progs 要素の子要素である prog 要素 でしょう。
まず station 要素を列挙する from 句を書きます。
次にその station 要素から prog 要素を列挙する from 句をもう一つ置きます。
あとはこの station 要素及び prog 要素から任意の情報を取り出すだけです。

例えば、station 要素を列挙する from 句は以下のように書けます。
from station in xdoc.Root.Element("stations").Elements("station")
xdoc に格納されている xml の、ルート要素 radiko の、子要素にある stations 要素を取り出し、その子要素で名前が station という要素を列挙し、それぞれ変数 station に格納して以降のクエリで使用できるようにする。
引用返信 編集キー/
■48393 / inTopicNo.3)  Re[1]: 現在のタイトル番組を取得するLINQ to XML
□投稿者/ aetos (260回)-(2010/04/05(Mon) 10:49:43)
No48388 (インパラ さん) に返信
> Name = Result.Element("radiko").Element("stations").Element("station").Element("scd").Element("name").Value,
> title = Result.Element("radiko").Element("stations").Element("station").Element("scd").Element("progs").Element("prog").Element("title").Value
> time = Result.Element("radiko").Element("stations").Element("station").Element("scd").Element("progs").Element("prog").Attribute("ftl").Value

こんなふうに Element をいくつも書くよりは、XPathSelectElement をおすすめします。すっきりしますよ。
引用返信 編集キー/
■48401 / inTopicNo.4)  Re[2]: 現在のタイトル番組を取得するLINQ to XML
□投稿者/ インパラ (2回)-(2010/04/05(Mon) 14:19:10)
No48389 (Hongliang さん) に返信
ありがとうございました。LINQの勉強になりました。
var query = from station in xdoc.Root.Element("stations").Elements("station").Elements("scd")
select new{
Name = station.Element("name").Value,
title = station.Element("progs").Element("prog").Element("title").Value
};
で実現できました。

引用返信 編集キー/
■48402 / inTopicNo.5)  Re[2]: 現在のタイトル番組を取得するLINQ to XML
□投稿者/ インパラ (3回)-(2010/04/05(Mon) 14:36:28)
No48393 (aetos さん) に返信
XPathSelectElement
は初めて知りました。
マスターすれば簡単そうなので、とりあえずいろいろ調べて試してみました。

public static XElement XPathSelectElement(
this XNode node,
string expression
);

とクラスに書くらしいのですが、これを書くと、
「拡張メソッドは、非ジェネリック静的クラスで定義する必要がある」
とエラーになります。
むずかしくて定義できなかったので、次のようにしました。

XDocument xdoc = XDocument.Parse(html);
System.Xml.XPath.Extensions.XPathSelectElement(xdoc, "station[@name=TBS]").Value;
これを実行すると、「オブジェクト参照がオブジェクトに登録されていません」とエラーでした。
System.Xml.XPath.Extensions.XPathSelectElement(xdoc, "//station[@name=TBS]").Value;
などいくつも試してみたのですが、どれもだめでした。
expressionの書き方のヒントをいただけないでしょうか。

引用返信 編集キー/
■48413 / inTopicNo.6)  Re[3]: 現在のタイトル番組を取得するLINQ to XML
□投稿者/ インパラ (4回)-(2010/04/05(Mon) 19:00:31)
応用で、Googleカレンダーでやってみました。
<?xml version='1.0' encoding='UTF-8'?>
<feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:gCal='http://schemas.google.com/gCal/2005'>
	<id>http://www.google.com/calendar/feeds/id/private-uniqid/basic</id>
	<updated>2010-04-05T09:04:25.000Z</updated>
	<category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/g/2005#event'/>
	<title type='text'>name</title>
	<subtitle type='text'>name</subtitle>
	<link rel='alternate' type='text/html' href='http://www.google.com/calendar/embed?src=id'/>
	<link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://www.google.com/calendar/feeds/id/private-uniqid/basic'/>
	<link rel='http://schemas.google.com/g/2005#batch' type='application/atom+xml' href='http://www.google.com/calendar/feeds/id/private-uniqid/basic/batch'/>
	<link rel='self' type='application/atom+xml' href='http://www.google.com/calendar/feeds/id/private-uniqid/basic?max-results=25&amp;start-min=2010-04-07&amp;start-max=2010-04-08'/>
	<author>
		<name>name</name>
		<email>name@gmail.com</email>
	</author>
	<generator version='1.0' uri='http://www.google.com/calendar'>Google Calendar</generator>
	<openSearch:totalResults>1</openSearch:totalResults>
	<openSearch:startIndex>1</openSearch:startIndex>
	<openSearch:itemsPerPage>25</openSearch:itemsPerPage>
	<gCal:timezone value='Asia/Tokyo'/>
	<gCal:timesCleaned value='0'/>
	<entry>
		<id>http://www.google.com/calendar/feeds/id/private-uniqid/basic/idid</id>
		<published>2010-04-04T15:12:04.000Z</published>
		<updated>2010-04-05T07:40:39.000Z</updated>
		<category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/g/2005#event'/>
		<title type='html'>ミーティング</title>
		<summary type='html'>期間: 2010/04/07 (&amp;#27700;) 12:30〜15:00&amp;nbsp;
			JST&lt;br&gt;
			&lt;br&gt;予定のステータス: 確定</summary>
		<content type='html'>期間: 2010/04/07 (水) 12:30〜15:00?
			JST&lt;br /&gt;
			&lt;br /&gt;予定のステータス: 確定</content>
		<link rel='alternate' type='text/html' href='http://www.google.com/calendar/event?eid=abcde' title='alternate'/>
		<link rel='self' type='application/atom+xml' href='http://www.google.com/calendar/feeds/id/private-uniqid/basic/idid'/>
		<author>
			<name>name</name>
			<email>name@gmail.com</email>
		</author>
	</entry>
</feed>
ルート要素はfeedで、entryのtitleとsummaryを取得しようと考えました。
XDocument xdoc = XDocument.Parse(contents);
var query = from entry in xdoc.Root.Elements("entry")
select new{
	Date = entry.Element("summary").Value,
	title = entry.Element("title").Value
};
としてみました。
ところが、queryのところで「結果を生成しませんでした」となり、うまく取得できません。
おなじように書いたつもりなのですが、どこで間違えているのでしょう?

引用返信 編集キー/
■48415 / inTopicNo.7)  Re[4]: 現在のタイトル番組を取得するLINQ to XML
□投稿者/ Hongliang (591回)-(2010/04/05(Mon) 20:02:02)
名前空間を持っている XML 要素は、名前空間を明示する必要があります。
feed 要素に既定の名前空間として xmlns="http://www.w3.org/2005/Atom" が定義されていますから、feed 要素及びその子孫要素は、(名前空間プリフィクスで明示していたり既定の名前空間を再定義したりしていない限り)すべてこの名前空間に属することになります。
// 属性は別。
LINQ to XML において XML 名前空間を指定するには、XNamespace クラスを使用します。
引用返信 編集キー/
■48416 / inTopicNo.8)  Re[3]: 現在のタイトル番組を取得するLINQ to XML
□投稿者/ Hongliang (592回)-(2010/04/05(Mon) 20:07:11)
XPathSelectElement は拡張メソッドです。これは静的メソッドでありながらインスタンスメソッドのように呼び出せる機構です。
MSDN で XPathSelectElement メソッドを調べればサンプルソースも載っていますよ。

これは既にライブラリが用意しているメソッドですから、自分で何か宣言したり定義したりする物ではありません。
引用返信 編集キー/
■48421 / inTopicNo.9)  Re[5]: 現在のタイトル番組を取得するLINQ to XML
□投稿者/ インパラ (5回)-(2010/04/06(Tue) 00:03:53)
No48415 (Hongliang さん) に返信
> 名前空間を持っている XML 要素は、名前空間を明示する必要があります。
> LINQ to XML において XML 名前空間を指定するには、XNamespace クラスを使用します。
xmlの名前空間ですか。
XDocument xdoc = XDocument.Parse(contents);
XNamespace xnamespace = "http://www.w3.org/2005/Atom";
var query = from entry in xdoc.Root.Elements(xnamespace + "entry")
select new{
	Date = entry.Element("summary").Value,
	title = entry.Element("title").Value
};


XDocument xdoc = XDocument.Parse(contents);
XNamespace xnamespace = "http://www.w3.org/2005/Atom";
var query = from entry in xdoc.Root.Elements("entry")
where entry.Name == xnamespace + "summary"
where entry.Name == xnamespace + "title"
select new{
	Date = entry.Element("summary").Value,
	title = entry.Element("title").Value
};
などやってみたのですが、取得できません。
添削していただけるとうれしいです。

引用返信 編集キー/
■48422 / inTopicNo.10)  Re[6]: 現在のタイトル番組を取得するLINQ to XML
□投稿者/ Hongliang (593回)-(2010/04/06(Tue) 00:28:37)
> XNamespace xnamespace = "http://www.w3.org/2005/Atom";
> var query = from entry in xdoc.Root.Elements(xnamespace + "entry")
> select new{
> Date = entry.Element("summary").Value,
> title = entry.Element("title").Value
> };

宣言された名前空間は子孫の要素に継承されます。ルート要素の既定の名前空間が定義されていれば、その子孫の要素も既定の名前空間に属します。
要するに、feed 要素の子要素である entry 要素も、さらにその子要素の summary 要素や title 要素も、全て "http://www.w3.org/2005/Atom" 名前空間に存在するのであって、名前空間を持たないわけではありません。

下の方のは意味不明ですね。
引用返信 編集キー/
■48424 / inTopicNo.11)  Re[7]: 現在のタイトル番組を取得するLINQ to XML
□投稿者/ インパラ (6回)-(2010/04/06(Tue) 02:46:38)
No48422 (Hongliang さん) に返信
> 宣言された名前空間は子孫の要素に継承されます。ルート要素の既定の名前空間が定義されていれば、その子孫の要素も既定の名前空間に属します。
> 要するに、feed 要素の子要素である entry 要素も、さらにその子要素の summary 要素や title 要素も、全て "http://www.w3.org/2005/Atom" 名前空間に存在するのであって、名前空間を持たないわけではありません。
>
なにをおっしゃっているのか、まったく理解できませんでした。
引用返信 編集キー/
■48426 / inTopicNo.12)  Re[8]: 現在のタイトル番組を取得するLINQ to XML
□投稿者/ aetos (261回)-(2010/04/06(Tue) 10:24:21)
No48424 (インパラ さん) に返信
> ■No48422 (Hongliang さん) に返信
>>宣言された名前空間は子孫の要素に継承されます。ルート要素の既定の名前空間が定義されていれば、その子孫の要素も既定の名前空間に属します。
>>要するに、feed 要素の子要素である entry 要素も、さらにその子要素の summary 要素や title 要素も、全て "http://www.w3.org/2005/Atom" 名前空間に存在するのであって、名前空間を持たないわけではありません。
>>
> なにをおっしゃっているのか、まったく理解できませんでした。

いろいろと基礎知識が足りていないのに、一足飛びに実現しようとしている印象を受けます。

まずこれは XML 名前空間の話。

> <feed xmlns='http://www.w3.org/2005/Atom'

とありますね。
この feed 要素の XML 名前空間は 'http://www.w3.org/2005/Atom' です。
で、これは、それ以降の要素にも継承されます。
ですから、feed の直下にある id も updated も category も entry も、entry の下にある title も summary も、すべて名前空間は 'http://www.w3.org/2005/Atom' なのです。
要するに、こういった要素にアクセスるする際は常に

> Elements(xnamespace + "entry")

こんな風に書かなければいけないということです。

> Element("summary").Value

これでは「名前空間のない summary 要素」を取得しようとしているので失敗するわけです。

ただし例外もありまして、例でいうところの

> <gCal:timezone value='Asia/Tokyo'/>
> <gCal:timesCleaned value='0'/>

これらに関しては名前空間は Atom ではありません。
これらの名前空間は feed 要素で

> xmlns:gCal='http://schemas.google.com/gCal/2005'

とされているので、'http://schemas.google.com/gCal/2005' となります。

それから、Linq の問題。

> var query = from entry in xdoc.Root.Elements("entry")
> where entry.Name == xnamespace + "summary"
> where entry.Name == xnamespace + "title"

まず1行目ですが、xdoc のルート直下の entry 要素を取得しようとしています(ここにも名前空間が欠けていますね)。
が、xdoc が例にある Google カレンダーだとすれば、Root は feed 要素になります。
その直下に entry 要素はありませんから、1行目は何も返しません。
これが間違いの1つ目。

仮に1行目が entry 要素を返したとしても、2行目と3行目で台無しにしています。
2行目の意味は「entry 要素のうち、名前が xnamespace + "summary" であるものを取得する」です。
でも entry 要素の名前は entry であって summary ではないので、2行目は決して成立しません。3行目も同様。
また、where は複数書くと and 条件になります。
つまり2行目と3行目は「entry 要素のうち、名前が "summary" であり、かつ "title" であるものを取得する」です。
どうです、意味不明でしょう?
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -