質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
XML

XMLは仕様の1つで、マークアップ言語群を構築するために使われています。

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

XMLパーサ

XML文書のテキストデータだけを抜き出して、アプリケーションソフトが利用しやすい形式に変換させるソフトウェアをXMLパーサと呼びます。

Q&A

解決済

2回答

4105閲覧

REXMLを利用した XMLパースで、子要素の属性が一致する親要素を表示する

TosuTosu

総合スコア49

XML

XMLは仕様の1つで、マークアップ言語群を構築するために使われています。

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

XMLパーサ

XML文書のテキストデータだけを抜き出して、アプリケーションソフトが利用しやすい形式に変換させるソフトウェアをXMLパーサと呼びます。

0グッド

0クリップ

投稿2015/11/09 04:19

編集2015/11/09 05:17

お世話になっております。

rexmlライブラリを使用してxmlの要素を取得したいと考えています。

このとき、要素Aが子要素B1, B2の属性が一致する場合のみを取得したいのですが、解決できません。

具体的には、、

XML

1<?xml> 2<feed> 3 <title>Mail Filters</title> 4 5 <A> # 表示する 6 <category term='filter'></category> 7 <title>Mail Filter</title> 8 <id>tag:mail.google.com</id> 9 <content></content> 10 <B name='MatchName_B1' value='matchValue_1st_B1'/> # 一致する 11 <B name='MatchName_B2' value='matchValue_1st_B2'/> # 一致する 12 </entry> 13 <A> # 表示しない 14 <category term='filter'></category> 15 <title>Mail Filter</title> 16 <id>tag:mail.google.com</id> 17 <content></content> 18 <B name='MachtName_B1' value='machValue_2nd_B1'/> # 一致する 19 <B name= 'NotMachtName_B2' value='NotMachValue_2nd_B2'/> #一致しない 20 </entry> 21 22</feed>

上記の例のXMLから
B要素の属性 Name が 'MatchName_B1' ,'MatchName_B2' の両方を含む(一致する)
要素A を表示したいと考えています。(上記の例では上のA要素のみ表示します)

以下のように2重のループで処理できないかと考えたのですが、
属性を取得できませんでした。

ruby

1require 'rexml/document' 2 3doc = REXML::Document.new(open(ARGV[0])) 4 5doc.elements.each('feed/entry') do |A| 6 7 atterB1 = "" 8 atterB2 = "" 9 10 A.each do |atterXml| 11 if atterXml.attributes["name"] == "B1" then #<-コンパイルエラー 12 atterB1 = listNames.push(element.attributes["value"] 13 elsif atterFacter.attributes["name"] == "B2" then 14 atterB2 = listNames.push(element.attributes["value"] 15 end 16 end 17 18 ## Do something 19 # atterB1 と atterB2 に文字列があれば 要素Aを表示する。 20end

初歩的なところなのかもしれませんが、お力添えをお願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

xpath を利用できるXPath モジュールで、条件に合う要素を探して、その親を返す、というのができるみたいです

対象XML

target.xml:

xml

1<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> 2<feed version="1.0"> 3 <title>Mail Filters</title> 4 5 <entry> <!-- 表示する --> 6 <category term='filter'></category> 7 <title>Mail Filter</title> 8 <id>tag:mail.google.com</id> 9 <content>Foo</content> 10 <B name='MatchName_B1' value='matchValue_1st_B1'/> 11 <B name='MatchName_B2' value='matchValue_1st_B2'/> 12 </entry> 13 <entry> <!-- 表示する --> 14 <category term='filter'></category> 15 <title>Mail Filter</title> 16 <id>tag:mail.google.com</id> 17 <content>Bar</content> 18 <B name='MatchName_B1' value='matchValue_1st_B1'/> 19 <B name='MatchName_B2' value='matchValue_1st_B2'/> 20 </entry> 21 <entry notmatch="true"> <!-- 表示しない --> 22 <category term='filter'></category> 23 <title>Mail Filter</title> 24 <id>tag:mail.google.com</id> 25 <content></content> 26 <B name='MachtName_B1' value='machValue_2nd_B1'/> 27 <B name= 'NotMachtName_B2' value='NotMachValue_2nd_B2'/> 28 </entry> 29</feed>

XML から要素を検索

ruby

1require 'rexml/document' 2include REXML 3 4xml = File.open(File.expand_path('./target.xml')) 5 6doc = Document.new(xml) 7 8xpath = '//entry/B[starts-with(@name, "MatchName_B") and not(starts-with(@name, "NotMatchName_"))]/..' 9 10# 重複が出るのでuniq 11p XPath.each(doc, xpath).to_a.uniq # => [<entry> ... </>, <entry> ... </>]

<entry/> の中身:

ruby

1puts XPath.each(doc, xpath).to_a.uniq.map(&:to_s) 2# <entry> <!-- 表示する --> 3# <category term='filter'/> 4# <title>Mail Filter</title> 5# <id>tag:mail.google.com</id> 6# <content>Foo</content> 7# <B name='MatchName_B1' value='matchValue_1st_B1'/> 8# <B name='MatchName_B2' value='matchValue_1st_B2'/> 9# </entry> 10# <entry> <!-- 表示する --> 11# <category term='filter'/> 12# <title>Mail Filter</title> 13# <id>tag:mail.google.com</id> 14# <content>Bar</content> 15# <B name='MatchName_B1' value='matchValue_1st_B1'/> 16# <B name='MatchName_B2' value='matchValue_1st_B2'/> 17# </entry>

検索させた結果に重複がでるので、イマイチな書き方をしているかもしれません

簡単に調べてみましたが、何か参考になれば幸いです

Link

投稿2015/11/09 07:20

編集2015/11/09 07:27
gouf

総合スコア2321

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

TosuTosu

2015/11/11 06:18 編集

ご回答ありがとうございました。 xPathの利用したコードを試してみましたが、本来の目的とするコードが複雑になってしまい検討を見送らせて頂きましたが、私自身、知識が不足しており勉強になりました。 xPathは非常に柔軟に要素を取得出来るようですので、今後の機会に利用してみたいと思います。どうもありがとうございました。
guest

0

自己解決

Element#each_elementで解決しました

elements.each()メソッドと同じようにelementに対してeach文を回すことができました。
ただしelementインスタンスに対してはeach_element()メソッドを使用します。
each()メソッドとeach_element()メソッドの利用方法は同じです。

elementsインスタンス ー> each()メソッド
elementインスタンス ー> each_element()メソッド

ruby

1require 'rexml/document' 2 3doc = REXML::Document.new(open(ARGV[0])) 4 5doc.elements.each('feed/entry') do |A| 6 7 atterB1 = "" 8 atterB2 = "" 9 10 A.each_element('B') do |atterXml|  #<-重要 11 if atterXml.attributes["name"] == "B1" then 12 atterB1 = listNames.push(element.attributes["value"] 13 elsif atterFacter.attributes["name"] == "B2" then 14 atterB2 = listNames.push(element.attributes["value"] 15 end 16 end 17 18 ## Do something 19 # atterB1 と atterB2 に文字列があれば 要素Aを表示する。 20end

投稿2015/11/11 06:11

編集2015/11/11 06:20
TosuTosu

総合スコア49

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問