nori icon indicating copy to clipboard operation
nori copied to clipboard

It ignores attributes when a child is a text node.

Open barberj opened this issue 10 years ago • 10 comments

Original conversation with @tjarratt started in #50

I'm working with a soap api that has xml text nodes with an attribute. I'm not sure how to pass the hash to savon to render this node correctly. Using nori parse to try and reverse engineer the hash from the xml i saw that it didn't return a hash with the attribute visible.

This is apparently desired feature as i found a supporting spec #L305:

305       it "should ignore attributes when a child is a text node" do
306         xml = "<root attr1='1'>Stuff</root>"
307         expect(parse(xml)).to eq({ "root" => "Stuff" })
308       end

I feel this is incorrect and the attribute should not be ignored. How else can we pass attributes for nodes where the child is text?

barberj avatar Jun 03 '14 11:06 barberj

Haven't had a chance to try this yet, but off top of my head i see this being the no code change solution to my problem

[16]  child = Nori::StringWithAttributes.new('active')
=> "active"
[17]  child.attributes = {"xmlns:v1"=>"http://example.com"}
=> {"xmlns:v1"=>"http://example.com"}
[18] hash_for_savon =  {"v1:userResponse"=> child}
=> {"v1:userResponse"=>"active"}

Savon.client(action, :message => hash_for_savon)

barberj avatar Jun 03 '14 11:06 barberj

Finally got around to testing this...

The code

188
189 def get_subscriber
190   child = Nori::StringWithAttributes.new('active')
191   child.attributes = {"xmlns:v1"=>"http://example.com"}
192   soap.call :retrieve, :message => {
193     'RetrieveRequest' => {
194       'ObjectType' => 'Subscriber',
195       'Properties' => [
196         "ID",
197         "PartnerKey",
198         "CreatedDate",
199         "Client.ID",
200         "Client.PartnerClientKey",
201         "EmailAddress",
202         "SubscriberKey",
203         "UnsubscribedDate",
204         "Status",
205         "EmailTypePreference"
206       ],
207       'Filter' =>
208         child
209       }
210   }
211 end

The xml...

        <tns:Properties>SubscriberKey</tns:Properties>
        <tns:Properties>UnsubscribedDate</tns:Properties>
        <tns:Properties>Status</tns:Properties>
        <tns:Properties>EmailTypePreference</tns:Properties>
        <tns:Filter>active</tns:Filter>
      </tns:RetrieveRequest>

Savon does not read the child attributes.

@tjarratt is this a savon bug to check for nori attributes or a nori bug for not being able to express child text nodes with attributes?

barberj avatar Jun 12 '14 13:06 barberj

also tried using gyoku syntax

281 def inlinetest
282   soap.call :retrieve, :message => {
283     'RetrieveRequest' => {
284       'ObjectType' => 'Subscriber',
285       'Properties' => [
286         "ID",
287         "PartnerKey",
288         "CreatedDate",
289         "Client.ID",
290         "Client.PartnerClientKey",
291         "EmailAddress",
292         "SubscriberKey",
293         "UnsubscribedDate",
294         "Status",
295         "EmailTypePreference"
296       ],
297       'Filter' => {
298         :content! => "active",
299         '@xmlns:v1' => 'http://example.com'
300       }
301     }
302   }
303 end

The xml...

        <tns:Properties>UnsubscribedDate</tns:Properties>
        <tns:Properties>Status</tns:Properties>
        <tns:Properties>EmailTypePreference</tns:Properties>
        <tns:Filter xmlns:v1="http://example.com">
          <tns:content>active</tns:content>
        </tns:Filter>
      </tns:RetrieveRequest>
    </tns:RetrieveRequestMsg>
  </env:Body>
</env:Envelope>

barberj avatar Jun 18 '14 15:06 barberj

Sorry for taking so long to respond @barberj! I've been trying to find time to read this issue and fully understand what's going on. The only supporting evidence I can find is from a year ago discussing how attributes and text can collide. I suspect that @rubiii was describing a subtle issue with how Savon attempts to avoid collisions.

In your last example, it seemed to work correctly with you used :content! as the key (although I'm not entirely clear what the XML should look like for this example). Does that actually work? It might be worth diving into this some more to find a better way of allowing users to do this, but to my eyes, what you posted seems fairly reasonable.

 'Filter' => {
    :content! => "active", '@xmlns:v1' => 'http://example.com'
  }
}

tjarratt avatar Jul 01 '14 06:07 tjarratt

@tjarratt it didn't work. The expected xml was

        <tns:Filter xmlns:v1="http://example.com">active</tns:Filter>

Looking at gyoku documentation

Using "@" keys and ":content!"

Gyoku.xml(
  "foo/" => {
    :@bar => "1",
    :@biz => "2",
    :@baz => "3",
    :content! => ""
  })
# => "<foo baz=\"3\" bar=\"1\" biz=\"2\"/>"

barberj avatar Jul 01 '14 18:07 barberj

I've found a problem while parsing this kind of attributes, and my guess is that it is related to this issue.

This is what I've seen while debugging: {:total=>[<totalcode="EUR">166141</total>]} The original XML was like <Total Code="EUR">166141</Total>, so at some point it seems to be wrongly merging the first attribute with the element itself, producing the problem and being this attribute ignored. I'm still trying to find the bug in Nori's code.

xurde avatar Aug 06 '15 02:08 xurde

+1

bdwyertech avatar Apr 29 '17 21:04 bdwyertech

What if I want to get the attributes value also? Tried this

xml_parser = Nori.new
xml_parser.parse "<FareReference ResBookDesigCode='Q'>Value</FareReference>"

Result is {"FareReference"=>"Value"}

I wanted to retrieve ResBookDesigCode value also

yllihv27 avatar Dec 01 '19 05:12 yllihv27

What if I want to get the attributes value also? Tried this

xml_parser = Nori.new
xml_parser.parse "<FareReference ResBookDesigCode='Q'>Value</FareReference>"

Result is {"FareReference"=>"Value"}

I wanted to retrieve ResBookDesigCode value also

@yllihv27 I came to the issues here trying to find the answer to the same thing. I'm trying to use Savon with an API that returns tags that have attributes which defines what the text in the tags actually mean. I was trying to figure out how to not lose the attributes when converting the response body to a hash. Have you found any way?

anirbanmu avatar Jan 09 '20 05:01 anirbanmu

@yllihv27 @anirbanmu I had the same use-case and found the solution here: https://github.com/savonrb/nori/issues/50#issuecomment-22622159. You can access the attributes via the Nori::StringWithAttributes#attributes method.

trezona-lecomte avatar Jan 14 '21 00:01 trezona-lecomte

Hi. I've updated the readme here with examples of how to access attributes from a text node, since it's not super obvious from repl that the result is of type Nori::StringWithAttributes#attributes

pcai avatar Sep 29 '22 21:09 pcai