2017-02-04 38 views
2

次のXMLデータからライターとアーティスト情報を収集する最適な方法を見つける必要があります。 comicノードは複数回表示され、1つの漫画本のデータが含まれています。特定の兄弟コンテンツに応じて兄弟の子供を得る方法

私は職業、作家、芸術家などによって適切な人を掴むことができません。各コミックの作家とアーティストは時々複数あります。私の計画は、それぞれをリストに追加/追加することです。

この1冊の漫画では、すべての作家とアーティストの表示名を取得する必要がありますが、仕事の機能(作家など)は人名の兄弟です。ここで

は私が持っているものですが、動作しません:

writer = [] 
penciler = [] 
doc.xpath('//comic').each do |main_element| 
main_element.xpath("mainsection/credits/credit/role[@id='dfWriter']").each do |n| 
    writer << n.xpath('person/displayname').text 
    end 
    main_element.xpath("mainsection/credits/credit/role[@id='dfPenciler']").each do |n| 
    penciler << n.xpath('person/displayname').text 
    end 
end 

p "Writer(s): ",writer 
p "Penciler(s): ",penciler 

これは、XMLファイル/データです:

<comic> 
    <id>3398</id> 
    <index>195</index> 
    <mainsection> 
    <title>Mind Games</title> 
    <myrating>0</myrating> 
    <myrating> 
     <displayname>0</displayname> 
     <sortname>0</sortname> 
    </myrating> 
    <pagecount>32</pagecount> 
    <credits> 
     <credit> 
     <role id="dfWriter">Writer</role> 
     <roleid>dfWriter</roleid> 
     <person> 
      <displayname>Will Pfeifer</displayname> 
      <sortname>Pfeifer, Will</sortname> 
      <lastname>Pfeifer</lastname> 
      <firstname>Will</firstname> 
     </person> 
     </credit> 
     <credit> 
     <role id="dfWriter">Writer</role> 
     <roleid>dfWriter</roleid> 
     <person> 
      <displayname>John Byrne</displayname> 
      <sortname>Byrne, John</sortname> 
      <lastname>Byrne</lastname> 
      <firstname>John</firstname> 
     </person> 
     </credit> 
     <credit> 
     <role id="dfPenciler">Penciller</role> 
     <roleid>dfPenciler</roleid> 
     <person> 
      <displayname>John Byrne</displayname> 
      <sortname>Byrne, John</sortname> 
      <lastname>Byrne</lastname> 
      <firstname>John</firstname> 
     </person> 
     </credit> 
    </credits> 
    </mainsection> 
</comic> 

私が持っているコードは私に望ましい結果を与えるものではありません。私は "Getting the siblings of a node with Nokogiri"を見つけましたが、私は反復し、それぞれの兄弟をつかむ必要があります。

<roleid>dfWriter</roleid>または<role id="dfWriter">Writer</role>で検索することができます。

私の予想出力は次のようになります。

Writer(s): Will Pfeifer, John Byrne 
Penciler(s): John Byrne 
+0

require 'nokogiri' xml = <<EOT <root> <displayname>Will Pfeifer</displayname> <displayname>John Byrne</displayname> <displayname>John Byrne</displayname> </root> EOT doc = Nokogiri::XML(xml) doc.search('displayname').class # => Nokogiri::XML::NodeSet doc.search('displayname').text # => "Will PfeiferJohn ByrneJohn Byrne" doc.at('displayname').class # => Nokogiri::XML::Element doc.at('displayname').text # => "Will Pfeifer" 

あなたが簡単に使用可能な形でノードセットのためのすべてのテキストをしたい場合は、各ノードからそれを抽出します。これを考慮してください。ルートノードとして '漫画'を表示しますが、 '漫画'は検索方法ではありません。 –

答えて

1

あなたは常にrole位置する標的要素を想定し、この目的のためのXPath following-sibling軸を使用することができます。

doc.xpath('//comic').each do |main_element| 
main_element.xpath("mainsection/credits/credit/role[@id='dfWriter']").each do |n| 
    writer << n.xpath('following-sibling::person/displayname').text 
    end 
    main_element.xpath("mainsection/credits/credit/role[@id='dfPenciler']").each do |n| 
    penciler << n.xpath('following-sibling::person/displayname').text 
    end 
end 

それとも、単に反復処理することができます最初にroleの代わりにcreditを入力してください。

doc.xpath('//comic').each do |main_element| 
main_element.xpath("mainsection/credits/credit[role/@id='dfWriter']").each do |n| 
    writer << n.xpath('person/displayname').text 
    end 
    main_element.xpath("mainsection/credits/credit[role/@id='dfPenciler']").each do |n| 
    penciler << n.xpath('person/displayname').text 
    end 
end 
+0

ありがとう。これはまさに私が探していたものです。あなたはそのような問題についてお勧めの読書をお持ちですか? – Dubb

+0

XPathを学ぶ。私は[w3school](http://www.w3schools.com/xml/xpath_intro.asp)、[MDN](https://developer.mozilla.org/en-US/docs/Web/XPath)から始めました。 [spec](https://www.w3.org/TR/xpath/)。そして、XPathテスター([xpathtester](http://www.xpathtester.com/xpath)や[xpatheval](http://xpatheval.apphb.com/)など)でXPathを使って遊んだことはたくさんあります。 – har07

+0

どのくらいの獣Xpathがどれくらいあるか分からなかった。ありがとう – Dubb

0

ここでは、私はこれをやっていいと思う方法は次のとおりです。

実行し、
require 'nokogiri' 

XML = <<EOT 
<comic> 
    <mainsection> 
    <credits> 
     <credit> 
     <role id="dfWriter">Writer</role> 
     <person> 
      <displayname>Will Pfeifer</displayname> 
     </person> 
     </credit> 
     <credit> 
     <role id="dfWriter">Writer</role> 
     <person> 
      <displayname>John Byrne</displayname> 
     </person> 
     </credit> 
     <credit> 
     <role id="dfPenciler">Penciller</role> 
     <person> 
      <displayname>John Byrne</displayname> 
     </person> 
     </credit> 
    </credits> 
    </mainsection> 
</comic> 
EOT 

doc = Nokogiri::XML(XML) 

writers = doc.search("credits role[id='dfWriter']").map { |w| w.parent.at('displayname').text } 
pencilers = doc.search("credits role[id='dfPenciler']").map { |n| n.parent.at('displayname').text } 

puts "Writer(s): %s" % writers.join(', ') 
puts "Penciler(s): %s" % pencilers.join(', ') 

# >> Writer(s): Will Pfeifer, John Byrne 
# >> Penciler(s): John Byrne 

、出力:

# >> Writer(s): Will Pfeifer, John Byrne 
# >> Penciler(s): John Byrne 

この:

writers = doc.search("credits role[id='dfWriter']").map { |w| w.parent.at('displayname').text } 
pencilers = doc.search("credits role[id='dfPenciler']").map { |n| n.parent.at('displayname').text } 

がDRY'dすることができ〜へ:

writers, pencilers = %w(dfWriter dfPenciler).map { |s| 
    doc.search("credits role[id='#{s}']").map { |w| w.parent.at('displayname').text } 
} 

可読性のためにCSSを使用しましたが、xpathの代わりにテキストを使用してNodeSetを返す場合は、ノードを返すatを使用しました。

ノードセットに対するノードセットとの区別は非常に重要です。 XMLは、あなたのコードと一致するように表示されません

doc.search('displayname').map(&:text) # => ["Will Pfeifer", "John Byrne", "John Byrne"]