Every repository with this icon (
Every repository with this icon (
| Description: | object to xml mapping library edit |
-
Cannot get attribute when there is element of same name
0 comments Created 7 months ago by jnunemakerComments
-
I have the following mapping for the attached xml:
module FamilySearch class AlternateIds include HappyMapper tag 'alternateIds' has_many :ids, String, :tag => 'id' end class Information include HappyMapper has_one :alternateIds, AlternateIds end class Person include HappyMapper attribute :version, String attribute :modified, Time attribute :id, String has_one :information, Information end class Persons include HappyMapper has_many :person, Person end class FamilyTree include HappyMapper tag 'familytree' attribute :version, String attribute :status_message, String, :tag => 'statusMessage' attribute :status_code, String, :tag => 'statusCode' has_one :persons, Persons end endNotice the AlternateIds class declares a has_many with type String, which should assign ids as a collection of Strings. However, ids ends up being a String of the first object.
I have a failing spec in my fork that represents this situation:
http://github.com/jimmyz/happymapper/commit/496365548e20a15707a46be9a756b1035301773eComments
knaveofdiamonds
Wed May 27 12:50:54 -0700 2009
| link
Another failing spec here: http://github.com/knaveofdiamonds/happymapper/commit/6635900aa35f2b414cd14c953f4b80107219a589
I've actually fixed this in my fork (http://github.com/knaveofdiamonds/happymapper/), but I've also switched over from using libxml directly to using nokogiri instead. You probably need to change find_first to find in line 122 item.rb, and then do something similar to this commit: http://github.com/knaveofdiamonds/happymapper/commit/440fc5aef143f064d99f6f91d433e61cfd8058f2
HTH,
Roland -
In the existing codebase, the xpath for non-primitive elements is from the downcased classname of the non-primitive class. This works well, but there are several cases where some more flexibility would be good.
For instance, consider this XML:
<game> <details> <quarter>1</quarter> <round>22</round> </details> <q1> <start>4:40:15 PM</start> </q1> <q2> <start>5:18:53 PM</start> </q2> <q3> <start>6:06:17 PM</start> </q3> <q4> <start>6:41:49 PM</start> </q4> </game>There is an obvious problem with this xml: the q1, q2, q3, q4 elements should be 'quarter' elements, with an attribute containing the quarter number. However, we usually don't have control of the format of external xml, so we just need to work with it. Anyway, we might map these with the following classes:
class Quarter include HappyMapper element :start, String end class Details include HappyMapper element :round, Integer element :quarter, Integer end class Game include HappyMapper has_one :details, QuarterTest::Details has_one :q1, QuarterTest::Quarter has_one :q2, QuarterTest::Quarter has_one :q3, QuarterTest::Quarter has_one :q4, QuarterTest::Quarter endThe problem is that the elements q1, q2, q3 and q4 will not be able to be found using the current HappyMapper implementation, since the xpath used will be 'quarter', which will find game/details/quarter in each case. Adding :tag => 'q1' etc will not help, since the tag name is derived from the class name.
We can fix this and allow mapping classes to be resuable. Instead of using the classname as the default tag name, we can use the following finders, in order:
1. specified tag (e.g. :tag => 'q1')
2. name of element (e.g. from has_one :q1)
3. tag_name (derived from class name by default)Using this method, the Game class changes to:
class Game include HappyMapper has_one :details, QuarterTest::Details has_one :q1, QuarterTest::Quarter, :tag => 'q1' has_one :q2, QuarterTest::Quarter, :tag => 'q2' has_one :q3, QuarterTest::Quarter, :tag => 'q3' has_one :q4, QuarterTest::Quarter, :tag => 'q4' endThis is a bit of a change, but the additional flexibility and reusability has worked really well for me in a variety of situations. In the existing specs, I only had to make one change for everything to pass:
class Radar include HappyMapper # OLD: has_many :places, Place # NEW: has_many :places, Place, :tag => :place endI've made the changes needed in my fork (http://github.com/lightningdb/happymapper/tree/master, commits ce59623 and 3251509), and updated the gemspec version to 0.3.0 to reflect that the change might need minor changes to existing mappings. I think the flexibility is worth it though.
Any thoughts or questions?
Comments
-
Cannot have multiple child elements with a default namespace
0 comments Created 7 months ago by jnunemakerHappyMapper 0.2.2 (commit 545ebcd) libxml 0.9.8
If an object including HappyMapper has multiple child elements (via has_one or has_many) and a default namespace, an exception is raised when processing the second child element.
I've recreated the issue in the specs, see attached diff.
It seems trying to assign a default namespace prefix to a node fails in libxml, but HappyMapper should probably not try to do this anyway.
I've fixed this ticket with http://github.com/lightningdb/happymapper/commit/ac6510bcec0314435d29ae092e857e965c0e1c28
The issue is that libxml falls over if the default prefix is assigned more than once. Seems to be a bug with libxml, but likewise it is probably something that happymapper should avoid anyway.
So before assigning the default prefix, we check whether a default prefix has already been assigned.
I've updated the tests to reflect this situation, by adding an extra 'has_one', which invokes the nested parsing that caused the error in the first place. I moved the Address class mapper definition up and added an address node to the product (I realise this doesn't make 'domain' sense, but it proves the issue and the fix).
Hopefully John approves and can pull into the main happymapper?
Comments
-
The following code gives a 'stack level too deep' error message when run on the attached data file:
require 'rubygems' require 'happymapper' class Node include HappyMapper element :node_name, String has_many :node, ::Node end class Taxonomy include HappyMapper element :taxonomy_name, String has_many :node, ::Node end class Taxonomies include HappyMapper has_many :taxonomy, ::Taxonomy end file_contents = File.read('worldguide_data/taxonomy_short.xml') taxonomies = Taxonomies.parse(file_contents) /opt/local/lib/ruby/gems/1.8/gems/jnunemaker-happymapper-0.1.5/lib/happymapper.rb:93:in `create_collection': stack level too deep (SystemStackError) from /opt/local/lib/ruby/gems/1.8/gems/jnunemaker-happymapper-0.1.5/lib/happymapper.rb:93:in `each' from /opt/local/lib/ruby/gems/1.8/gems/jnunemaker-happymapper-0.1.5/lib/happymapper.rb:93:in `create_collection' from /opt/local/lib/ruby/gems/1.8/gems/jnunemaker-happymapper-0.1.5/lib/happymapper.rb:107:in `inject' from /opt/local/lib/ruby/gems/1.8/gems/jnunemaker-happymapper-0.1.5/lib/happymapper.rb:90:in `each' from /opt/local/lib/ruby/gems/1.8/gems/jnunemaker-happymapper-0.1.5/lib/happymapper.rb:90:in `inject' from /opt/local/lib/ruby/gems/1.8/gems/jnunemaker-happymapper-0.1.5/lib/happymapper.rb:90:in `create_collection' from /opt/local/lib/ruby/gems/1.8/gems/jnunemaker-happymapper-0.1.5/lib/happymapper.rb:79:in `parse' from /opt/local/lib/ruby/gems/1.8/gems/jnunemaker-happymapper-0.1.5/lib/happymapper/item.rb:29:in `from_xml_node' ... 12965 levels... from /opt/local/lib/ruby/gems/1.8/gems/jnunemaker-happymapper-0.1.5/lib/happymapper.rb:90:in `inject' from /opt/local/lib/ruby/gems/1.8/gems/jnunemaker-happymapper-0.1.5/lib/happymapper.rb:90:in `create_collection' from /opt/local/lib/ruby/gems/1.8/gems/jnunemaker-happymapper-0.1.5/lib/happymapper.rb:79:in `parse' from test.rb:22Comments
jnunemaker
Thu Apr 16 15:48:53 -0700 2009
| link
From Mike Woodhouse (at old lighthouse project):
I tried that with 0.1.6 and didn't get the error, which was good.
Recursive structures still don't work properly, though: in Steve's example, the Taxonomy object gets 4 Nodes: the single "parent" one and the three "children". The parent does also get the children as you'd expect.
I'd already found this trying to write a script to play with my Google Reader OPML, which has some recursion of elements. See http://pastie.org/366720 , which shows where I was able to work around the problem by removing higher-level outlines that had no children (which got the desired result in this particular case).
-
I'm getting this error only when I use has_many or has_one method.
The code and xml is here: http://gist.github.com/105430
Comments
-
It could be nice if you let the gem decide to include libxml-jruby over libxml-ruby when jruby is used
I guess i could fork the project and test on JRubyComments
-
The documentation for declaring a namespace in HappyMapper is to use the value of the namespace. For example:
class Foo
tag 'foo'
namespace 'n'
endwhich one would expect to map to <n:foo/>, but in fact you must now provide the namespace declaration the path of the namespace. The above then becomes:
class Foo
tag 'foo'
namespace 'http://www.n.com'
end1) Are there good reasons for being less explicit?
2) This isn't documented anywhere, and it's not obvious one must use the uri for the namespace.Comments











