Question

I have this as my XML:

<systems>
  <system number="2" >
    <lists>
      <list critical="user" access="remote"></list>
      <list critical="root" access="local"></list>
    </lists>
    <os system="linux" basebox="AddBaseBox" ></os>
    <networks>
      <network name="homeonly" ></network>
      <network name="homeonly2"></network>
    </networks>
  </system>
</systems>

I want to add them to an array so I wrote this:

require 'nokogiri'

doc = Nokogiri::XML(File.open("boxesconfig.xml"))

doc.search('//systems/system').each do |system|
    list = []
    networks = []
    systemNumber  = system.at('@number').text
    os  = system.at('//os/@system').text
    base = system.at('//os/@basebox').text
   
    list << { "critical" => system.at('//lists/list/@critical').text, "access" => system.at('//lists/list/@access').text}
    networks << { "network" => system.at('//networks/network/@name').text}
    puts list
    puts systemNumber
    puts os
    puts networks    
end

The output I receive is:

{"critical"=>"user", "access"=>"remote"}
2
linux
{"network"=>"homeonly"}

I want to have multiple lists and multiple networks displayed in the array. What am I doing wrong?

The output I want is:

{"critical"=>"user", "access"=>"remote"}
{"root"=>"user", "access"=>"local"}
2
linux
{"network"=>"homeonly"}
{"network"=>"homeonly2"}
Was it helpful?

Solution

Nokogiri allows you to access the XML using CSS selectors. When your selectors match more than one thing, Nokogiri returns an array of those things. Here, we are using Ruby's Array#collect method to return a new array of items based on what the block returns:

lists = system.css('lists list').collect do |list| 
  { 'critical' => list['critical'], 'access' => list['access'] } 
end

networks = system.css('networks network').collect do |network| 
  { 'network' => network['name'] } 
end

This should give you the output you are looking for.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top