savonrb / nori

XML to Hash translator

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Nori doesn't handle lists of named attributes and values

antaflos opened this issue · comments

Using Ruby 3.0.6 and Nori 2.7.0.

Not sure if the title describes the problem correctly, but given the following XML document, taken directly from a Zimbra SOAP response:

<GetDistributionListResponse total="0" more="0" xmlns="urn:zimbraAdmin">
  <dl name="testlist9976@test.example.com" dynamic="0" id="d78fd6b4-5eae-4959-8ed5-fce302d553c5">
    <a n="zimbraMailAlias">testlist9976@test.example.com</a>
    <a n="uid">testlist9976</a>
    <a n="mail">testlist9976@test.example.com</a>
    <a n="zimbraId">d78fd6b4-5eae-4959-8ed5-fce302d553c5</a>
    <a n="objectClass">zimbraDistributionList</a>
    <a n="objectClass">zimbraMailRecipient</a>
    <a n="zimbraMailHost">zimbra.example.com</a>
    <a n="zimbraCreateTimestamp">20240311090210.829Z</a>
    <a n="zimbraMailStatus">enabled</a>
  </dl>
</GetDistributionListResponse>

and creating a Nori object from it:

irb> Nori.new.parse(the_xml)
=>
{"GetDistributionListResponse"=>
  {"dl"=>
    {"a"=>
      ["testlist9976@test.example.com",
       "testlist9976",
       "testlist9976@test.example.com",
       "d78fd6b4-5eae-4959-8ed5-fce302d553c5",
       "zimbraDistributionList",
       "zimbraMailRecipient",
       "zimbra.example.com",
       "20240311090210.829Z",
       "enabled"],
     "@name"=>"testlist9976@test.example.com",
     "@dynamic"=>"0",
     "@id"=>"d78fd6b4-5eae-4959-8ed5-fce302d553c5"},
   "@xmlns"=>"urn:zimbraAdmin",
   "@total"=>"0",
   "@more"=>"0"}}

results in the a list containing just a list of values, but their corresponding attribute names (specified as n="zimbraId", for example) are missing. This makes the result rather unusable because there is no way to associate the values with their attributes any more (and Zimbra can return hundreds of attributes in this manner). I have not found a way to get the original attribute names, as none of the resulting nodes seem to be of class Nori::StringWithAttributes . Am I missing something?

I think Nori should return a list of hashes instead, and fold multi-valued attributes into a list (like with "objectClass"):


irb> Nori.new.parse(the_xml)
=>
{"GetDistributionListResponse"=>
  {"dl"=>
    {"a"=> [
      { "zimbraMailAlias" => "testlist9976@test.example.com" },
      { "uid" => "testlist9976" },
      { "mail" => "testlist9976@test.example.com" },
      { "zimbraId" => "d78fd6b4-5eae-4959-8ed5-fce302d553c5" },
      { "objectClass" => ["zimbraDistributionList", "zimbraMailRecipient" },
      { "zimbraMailHost" => ["zimbra.example.com"] },
      { "zimbraCreateTimestamp" => "20240311090210.829Z" },
      { "zimbraMailStatus" => "enabled" }
    ],
     "@name"=>"testlist9976@test.example.com",
     "@dynamic"=>"0",
     "@id"=>"d78fd6b4-5eae-4959-8ed5-fce302d553c5"},
   "@xmlns"=>"urn:zimbraAdmin",
   "@total"=>"0",
   "@more"=>"0"}}

Not sure what the implications of such a change would be, but as it looks now we have to parse the raw XML manually to get these attribute values along with the attribute names.

This seems to work as expected for me in 2.7.x:

require 'nori'
irb(main):021:0' val = '<GetDistributionListResponse total="0" more="0" xmlns="urn:zimbraAdmin">
irb(main):022:0'   <dl name="testlist9976@test.example.com" dynamic="0" id="d78fd6b4-5eae-4959-8ed5-fce302d553c5">
irb(main):023:0'     <a n="zimbraMailAlias">testlist9976@test.example.com</a>
irb(main):024:0'     <a n="uid">testlist9976</a>
irb(main):025:0'     <a n="mail">testlist9976@test.example.com</a>
irb(main):026:0'     <a n="zimbraId">d78fd6b4-5eae-4959-8ed5-fce302d553c5</a>
irb(main):027:0'     <a n="objectClass">zimbraDistributionList</a>
irb(main):028:0'     <a n="objectClass">zimbraMailRecipient</a>
irb(main):029:0'     <a n="zimbraMailHost">zimbra.example.com</a>
irb(main):030:0'     <a n="zimbraCreateTimestamp">20240311090210.829Z</a>
irb(main):031:0'     <a n="zimbraMailStatus">enabled</a>
irb(main):032:0'   </dl>
irb(main):033:0' </GetDistributionListResponse>'
irb(main):016:0> result = Nori.new.parse(val)
=> 
{"GetDistributionListResponse"=>                                              
...                                                                           
irb(main):017:0> result["GetDistributionListResponse"]["dl"]
=> 
{"a"=>                                                                        
  ["testlist9976@test.example.com",                                           
   "testlist9976",                                                            
   "testlist9976@test.example.com",                                           
 "zimbra.example.com",
 "20240311090210.829Z",
 "enabled"]
irb(main):019:0> result["GetDistributionListResponse"]["dl"]["a"].first.class
=> Nori::StringWithAttributes
irb(main):020:0> result["GetDistributionListResponse"]["dl"]["a"].first.attributes
=> {"n"=>"zimbraMailAlias"}
irb(main):021:0>

I agree it makes more sense for the data to be represented as a list of key-value pairs, but that's not how your XML is structured. It's clearly structured as a list of values, with an attribute named n where the value of n represents the key name of the inner content (???).

please reopen with additional information if you can reproduce a bug. thanks