Dubb Dubb - 4 years ago 77
Ruby Question

How to get siblings' child according to specific defined sibling content

I need to find the best method to gather writer and artist information from the following XML data. The

comic
node appears multiple times and includes data for a single comic book.

I can't grab the appropriate person according to their job function, writer, artist, etc. There are sometimes multiple writers and artists of each comic book. My plan is to add/append each to a List.

So, for this single comic book, I need to get all the writers' and artists' display name, but the job function (e.g. writer) is a sibling of the persons name.

Here is what I have, but doesn't work:

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


This is the XML file/data:

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


The code I have does not give me the desired results. I found "Getting the siblings of a node with Nokogiri" but I need to iterate and grab each sibling.

I can either search by
<roleid>dfWriter</roleid>
or
<role id="dfWriter">Writer</role>
as they are the same.

My expected output would be:

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

Answer Source

You can use XPath following-sibling axis for this purpose assuming the target element always located after role :

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

Or you can just iterate through credit instead of role in the first place :

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
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download