isbndb 1.5.5 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  module ISBNdb
2
-
2
+
3
3
  private
4
4
  # The Result object is a true testament of metaprogramming. Almost every method of the Result
5
5
  # is dynamically generated through the build_result() method. All attribtues of the XML are
@@ -9,52 +9,51 @@ module ISBNdb
9
9
  class Result
10
10
  # Initialize simply calls build_result. Because the method definition is recusive, it must
11
11
  # be moved into a separate helper.
12
- def initialize(top_node)
13
- build_result(top_node)
12
+ def initialize(json = {})
13
+ @store = build_result(json)
14
14
  end
15
-
16
- # Because a result may or may not contain a specified key, we always return nil for
15
+
16
+ # Because a result may or may not contain a specified key, we always return nil for
17
17
  # consistency. This allows developers to easily check for .nil? instead of checking for
18
- # a miriad of exceptions throughout their code.
18
+ # a myriad of exceptions throughout their code.
19
19
  def method_missing(m, *args, &block)
20
- nil
20
+ @store[m.to_s.underscore]
21
21
  end
22
-
23
- # Pretty preint the Result including the number of singleton methods that exist. If
22
+
23
+ # Return a list of all "methods" this class responds to
24
+ def instance_methods
25
+ @store.collect{ |key,value| key.to_s }
26
+ end
27
+
28
+ # Pretty print the Result including the number of singleton methods that exist. If
24
29
  # you want the ACTUAL singleton methods, call @result.singleton_methods.
25
30
  def to_s
26
- @singleton_methods ||= []
27
- "#<Result @num_singleton_methods=#{@singleton_methods.size}>"
31
+ "#<Result @num_singleton_methods=#{@store.size}>"
28
32
  end
29
-
30
- private
31
- # This is the `magical` method. It essentially parses each attribute of the XML as well as
32
- # the content of each XML node, dynamically sends a method to the instance with that attribute's
33
- # or content's value. Not to be outdone, it recursively iterates over all children too!
34
- def build_result(top_node)
35
- top_node.attributes.each do |attribute|
36
- singleton.send(:define_method, method_name(attribute.name)) { attribute.value } unless attribute.value.strip.empty?
37
- end
38
-
39
- if top_node.children?
40
- top_node.children.each { |child| build_result(child) }
41
- else
42
- singleton.send(:define_method, method_name(top_node.parent.name)) { top_node.content.strip.chomp(',') } unless top_node.content.strip.empty?
43
- end
33
+
34
+ def inspect
35
+ "#<Result #{@store.collect{ |key,value| ':' + key.to_s + ' => ' + value.inspect }.join(', ')}>"
44
36
  end
45
-
46
- # This helper function reduces code redundancy and maintains consistency by formatting
47
- # all method names the same. All method names are stripped of any trailing whitespaces,
48
- # converted from CamelCase to under_score, and converted to a symbol
49
- def method_name(name)
50
- name.strip.underscore.to_sym
37
+
38
+ def ==(result)
39
+ self.inspect == result.inspect
51
40
  end
52
-
53
- # We need a singleton reference to the current _instance_ so that we can dynamically define
54
- # methods. This is just a simple helper that returns the singleton class of the current
55
- # object instance.
56
- def singleton
57
- class << self; self end
41
+
42
+ private
43
+ def build_result(json)
44
+ result = {}
45
+
46
+ json.each do |key,value|
47
+ result[key.to_s.underscore] = if value.is_a?(Hash)
48
+ build_result(value)
49
+ elsif value.blank?
50
+ nil
51
+ else
52
+ value
53
+ end
54
+ end
55
+
56
+ result
58
57
  end
59
58
  end
60
- end
59
+ end
@@ -1,12 +1,16 @@
1
1
  module ISBNdb
2
-
2
+
3
3
  private
4
4
  # The ResultSet is a collection of Result objects with helper methods for pagination. It
5
5
  # allows for easy paginating through multiple pages of results as well as jumping to a
6
6
  # specific results page.
7
7
  class ResultSet
8
8
  include Enumerable
9
-
9
+ include HTTParty
10
+
11
+ base_uri 'http://isbndb.com/api'
12
+ headers 'Content-Type' => 'text/xml'
13
+
10
14
  # This method creates instance variables for @uri, @collection, and @current_page. It then
11
15
  # attempts to parse the XML at the gieven URI. If it cannot parse the URI for any reason,
12
16
  # it will raise an ISBNdb::InvalidURIError. Next, the results are checked for an any error
@@ -14,76 +18,71 @@ module ISBNdb
14
18
  # Finally, this method then actually builds the ResultSet.
15
19
  def initialize(uri, collection, current_page = 1)
16
20
  @uri = uri
17
- @collection = collection
21
+ @collection = collection.to_s.titleize.singularize
18
22
  @current_page = current_page
19
- @xml = parse_xml
20
-
23
+ @parsed_response = self.class.get(@uri).parsed_response['ISBNdb']
24
+
21
25
  check_results
22
26
  build_results
23
27
  end
24
-
28
+
29
+ def size
30
+ @results.size
31
+ end
32
+
25
33
  # Because ResultSet extends Enumerable, we need to define the each method. This allows users
26
34
  # to call methods like .first, .last, [5], and .each on the ResultSet, making it behave like
27
35
  # a primitive array.
28
36
  def each(&block)
29
37
  @results.each &block
30
38
  end
31
-
39
+
32
40
  # Jump to a specific page. This method will return nil if the specified page does not exist.
33
41
  def go_to_page(page)
34
42
  get_total_pages unless @total_pages
35
- return nil if page < 1 || page > @total_pages
43
+ return nil if page.to_i < 1 || page.to_i > @total_pages
36
44
  ISBNdb::ResultSet.new("#{@uri}&page_number=#{page}", @collection, page)
37
45
  end
38
-
46
+
39
47
  # Go to the next page. This method will return nil if a next page does not exist.
40
48
  def next_page
41
49
  go_to_page(@current_page+1)
42
50
  end
43
-
51
+
44
52
  # Go to the previous page. This method will return nil if a previous page does not exist.
45
53
  def prev_page
46
54
  go_to_page(@current_page-1)
47
55
  end
48
-
56
+
49
57
  # Pretty prints the Result set information.
50
58
  def to_s
51
- "#<ResultSet @collection=#{@collection}, total_results=#{@results.size}>"
59
+ "#<ResultSet::#{@collection} :total_results => #{@results.size}>"
52
60
  end
53
-
54
- private
55
- # Try and parses and returns the XML from the given URI. If the parsing fails for any reason, this method
56
- # raises ISBNdb::InvalidURIError.
57
- def parse_xml
58
- begin
59
- LibXML::XML::Parser.file(@uri).parse
60
- rescue
61
- raise ISBNdb::InvalidURIError
62
- end
61
+
62
+ def ==(result_set)
63
+ self.size == result_set.size && self.instance_variable_get('@results') == result_set.instance_variable_get('@results')
63
64
  end
64
-
65
- # Check the results for an error message. If one exists, raise an ISBNdb::AccessKeyError for now.
65
+
66
+ private
67
+ # Check the results for an error message. If one exists, raise an ISBNdb::AccessKeyError for now.
66
68
  # Currently the API does not differentiate between an overloaded API key and an invalid one
67
69
  # (it returns the same exact response), so there only exists one exception for now...
68
70
  def check_results
69
- raise ISBNdb::AccessKeyError unless @xml.find("ErrorMessage").first.nil?
71
+ raise ISBNdb::AccessKeyError if @parsed_response['ErrorMessage']
70
72
  end
71
-
73
+
72
74
  # Iterate over #{@collection}List/#{@collection}Data (ex. BookList/BookData) and build a result with
73
75
  # each child. This method works because the API always returns #{@collection}List followed by a subset
74
76
  # of #{@collection}Data. These results are all pushed into the @results array for accessing.
75
77
  def build_results
76
- @results = []
77
- list = @xml.find("#{@collection}List/#{@collection}Data")
78
- return [nil] if list.empty?
79
- list.collect { |node| @results << Result.new(node) }
78
+ @results = @parsed_response["#{@collection}List"]["#{@collection}Data"].collect{ |json| Result.new(json) }
80
79
  end
81
-
80
+
82
81
  # This helper method is mainly designed for use with the go_to_page(page) method. It parses the XML
83
82
  # and returns the total number of pages that exist for this result set.
84
83
  def get_total_pages
85
- list = @xml.find("#{@collection}List").first.attributes
84
+ list = @parsed_response["#{@collection}List"]
86
85
  @total_pages = (list['total_results'].to_f/list['page_size'].to_f).ceil
87
86
  end
88
87
  end
89
- end
88
+ end
@@ -0,0 +1,5 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+
3
+ <ISBNdb server_time="2012-06-16T19:19:05Z">
4
+ <ErrorMessage>Access key error</ErrorMessage>
5
+ </ISBNdb>
@@ -0,0 +1,46 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+
3
+ <ISBNdb server_time="2012-06-16T20:26:27Z">
4
+ <AuthorList total_results="401" page_size="10" page_number="1" shown_results="10">
5
+ <AuthorData person_id="abraham_seth">
6
+ <Name>Abraham, Seth</Name>
7
+ <Details first_name="Seth" last_name="Abraham" dates="" has_books="1" />
8
+ </AuthorData>
9
+ <AuthorData person_id="abramson_seth_f">
10
+ <Name>Abramson, Seth F.</Name>
11
+ <Details first_name="Seth" last_name="Abramson" dates="1926-" has_books="1" />
12
+ </AuthorData>
13
+ <AuthorData person_id="adams_seth">
14
+ <Name>Adams, Seth</Name>
15
+ <Details first_name="Seth" last_name="Adams" dates="" has_books="1" />
16
+ </AuthorData>
17
+ <AuthorData person_id="seth_afikorah_danquah">
18
+ <Name>Seth Afikorah-Danquah</Name>
19
+ <Details first_name="Seth" last_name="Afikorah-Danquah" dates="" has_books="1" />
20
+ </AuthorData>
21
+ <AuthorData person_id="agata_seth_h">
22
+ <Name>Agata, Seth H</Name>
23
+ <Details first_name="Seth" last_name="Agata" dates="" has_books="1" />
24
+ </AuthorData>
25
+ <AuthorData person_id="agbo_seth_a">
26
+ <Name>Agbo, Seth A.</Name>
27
+ <Details first_name="Seth" last_name="Agbo" dates="1951-" has_books="1" />
28
+ </AuthorData>
29
+ <AuthorData person_id="allcorn_seth">
30
+ <Name>Allcorn, Seth</Name>
31
+ <Details first_name="Seth" last_name="Allcorn" dates="" has_books="1" />
32
+ </AuthorData>
33
+ <AuthorData person_id="ames_seth">
34
+ <Name>Ames, Seth</Name>
35
+ <Details first_name="Seth" last_name="Ames" dates="1805-1881." has_books="1" />
36
+ </AuthorData>
37
+ <AuthorData person_id="anderson_seth_b">
38
+ <Name>Anderson, Seth B.</Name>
39
+ <Details first_name="Seth" last_name="Anderson" dates="" has_books="1" />
40
+ </AuthorData>
41
+ <AuthorData person_id="seth_andrew_a01">
42
+ <Name>Seth Andrew</Name>
43
+ <Details first_name="Seth" last_name="Andrew" dates="" has_books="1" />
44
+ </AuthorData>
45
+ </AuthorList>
46
+ </ISBNdb>
@@ -0,0 +1,76 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+
3
+ <ISBNdb server_time="2012-06-16T20:10:13Z">
4
+ <BookList total_results="1664" page_size="10" page_number="1" shown_results="10">
5
+ <BookData book_id="100th_day_of_school_a04" isbn="1590543947" isbn13="9781590543948">
6
+ <Title>100th Day of School</Title>
7
+ <TitleLong>100th Day of School (Hello Reader Level 2)</TitleLong>
8
+ <AuthorsText>Angela Shelf Medearis, </AuthorsText>
9
+ <PublisherText publisher_id="fitzgerald_books">Fitzgerald Books</PublisherText>
10
+ <Details change_time="2011-03-08T18:28:45Z" price_time="2012-05-29T16:45:46Z" edition_info="Unknown Binding; 2007-01" language="" physical_description_text="6.0&quot;x9.0&quot;x0.5&quot;; 0.4 lb; 32 pages" lcc_number="" dewey_decimal_normalized="" dewey_decimal="" />
11
+ </BookData>
12
+ <BookData book_id="100th_day_the" isbn="0439330173" isbn13="9780439330176">
13
+ <Title>100th Day, The</Title>
14
+ <TitleLong>100th Day, The (level 1) (Hello Reader Level 1)</TitleLong>
15
+ <AuthorsText>Alayne Pick, Grace Maccarone, Laura Freeman (Illustrator)</AuthorsText>
16
+ <PublisherText publisher_id="cartwheel">Cartwheel</PublisherText>
17
+ <Details change_time="2006-02-27T21:34:15Z" price_time="2012-05-29T16:46:08Z" edition_info="Paperback; 2002-12-01" language="" physical_description_text="32 pages" lcc_number="" dewey_decimal_normalized="" dewey_decimal="" />
18
+ </BookData>
19
+ <BookData book_id="2011_hello_kitty_engagement_calendar" isbn="1423803558" isbn13="9781423803553">
20
+ <Title>2011 Hello Kitty Engagement Calendar</Title>
21
+ <TitleLong></TitleLong>
22
+ <AuthorsText>Day Dream (Contributor)</AuthorsText>
23
+ <PublisherText publisher_id="day_dream">Day Dream</PublisherText>
24
+ <Details change_time="2010-09-21T21:20:39Z" price_time="2012-03-24T04:44:44Z" edition_info="Calendar; 2010-08-01" language="" physical_description_text="7.0&quot;x8.5&quot;x0.9&quot;; 1.1 lb" lcc_number="" dewey_decimal_normalized="741" dewey_decimal="741" />
25
+ </BookData>
26
+ <BookData book_id="2011_hello_kitty_wall_calendar" isbn="1423803981" isbn13="9781423803980">
27
+ <Title>2011 Hello Kitty Wall Calendar</Title>
28
+ <TitleLong></TitleLong>
29
+ <AuthorsText>Day Dream (Contributor)</AuthorsText>
30
+ <PublisherText publisher_id="day_dream">Day Dream</PublisherText>
31
+ <Details change_time="2010-09-21T18:46:02Z" price_time="2012-04-25T20:26:40Z" edition_info="Calendar; 2010-08-01" language="" physical_description_text="10.8&quot;x11.8&quot;x0.2&quot;; 0.3 lb" lcc_number="" dewey_decimal_normalized="" dewey_decimal="" />
32
+ </BookData>
33
+ <BookData book_id="2012_hello_kitty_2_year_pocket_planner_calendar" isbn="1423809424" isbn13="9781423809425">
34
+ <Title>2012 Hello Kitty 2 Year Pocket Planner Calendar</Title>
35
+ <TitleLong></TitleLong>
36
+ <AuthorsText>Day Dream, </AuthorsText>
37
+ <PublisherText publisher_id="day_dream">Day Dream</PublisherText>
38
+ <Details change_time="2012-01-17T22:23:43Z" price_time="2012-03-04T05:32:03Z" edition_info="Calendar; 2011-07-01" language="" physical_description_text="3.5&quot;x6.2&quot;x0.0&quot;; 0.1 lb" lcc_number="" dewey_decimal_normalized="636" dewey_decimal="636" />
39
+ </BookData>
40
+ <BookData book_id="2012_hello_kitty_juvenile_activity_calendar" isbn="1423811194" isbn13="9781423811190">
41
+ <Title>2012 Hello Kitty Juvenile Activity Calendar</Title>
42
+ <TitleLong></TitleLong>
43
+ <AuthorsText>Day Dream, </AuthorsText>
44
+ <PublisherText publisher_id="day_dream">Day Dream</PublisherText>
45
+ <Details change_time="2012-05-15T00:52:54Z" price_time="2012-06-16T20:10:13Z" edition_info="Calendar; 2011-07-01" language="" physical_description_text="11.0&quot;x12.0&quot;x0.3&quot;; 0.8 lb" lcc_number="" dewey_decimal_normalized="741" dewey_decimal="741" />
46
+ </BookData>
47
+ <BookData book_id="2012_hello_kitty_mini_calendar" isbn="1423809165" isbn13="9781423809166">
48
+ <Title>2012 Hello Kitty Mini Calendar</Title>
49
+ <TitleLong></TitleLong>
50
+ <AuthorsText>Day Dream, </AuthorsText>
51
+ <PublisherText publisher_id="day_dream">Day Dream</PublisherText>
52
+ <Details change_time="2012-01-17T22:24:12Z" price_time="2012-02-09T06:11:01Z" edition_info="Calendar; 2011-07-01" language="" physical_description_text="6.2&quot;x6.9&quot;x0.2&quot;; 0.1 lb" lcc_number="" dewey_decimal_normalized="741" dewey_decimal="741" />
53
+ </BookData>
54
+ <BookData book_id="2012_hello_kitty_wall_calendar" isbn="1423809696" isbn13="9781423809692">
55
+ <Title>2012 Hello Kitty Wall Calendar</Title>
56
+ <TitleLong></TitleLong>
57
+ <AuthorsText>Day Dream, </AuthorsText>
58
+ <PublisherText publisher_id="day_dream">Day Dream</PublisherText>
59
+ <Details change_time="2012-01-17T22:14:27Z" price_time="2012-02-09T06:02:14Z" edition_info="Calendar; 2011-07-01" language="" physical_description_text="10.6&quot;x11.8&quot;x0.2&quot;; 0.5 lb" lcc_number="" dewey_decimal_normalized="741" dewey_decimal="741" />
60
+ </BookData>
61
+ <BookData book_id="2012_hello_kitty_weekly_engagement_calendar" isbn="1423809092" isbn13="9781423809098">
62
+ <Title>2012 Hello Kitty Weekly Engagement Calendar</Title>
63
+ <TitleLong></TitleLong>
64
+ <AuthorsText>Day Dream, </AuthorsText>
65
+ <PublisherText publisher_id="day_dream">Day Dream</PublisherText>
66
+ <Details change_time="2012-01-17T22:14:34Z" price_time="2012-02-08T12:37:05Z" edition_info="Calendar; 2011-07-01" language="" physical_description_text="7.2&quot;x8.5&quot;x0.9&quot;; 1.0 lb" lcc_number="" dewey_decimal_normalized="741" dewey_decimal="741" />
67
+ </BookData>
68
+ <BookData book_id="2_grrrls_hello_gorgeous" isbn="0439187370" isbn13="9780439187374">
69
+ <Title>Hello gorgeous</Title>
70
+ <TitleLong>Hello gorgeous: a guide to style</TitleLong>
71
+ <AuthorsText>by Kristen Kemp</AuthorsText>
72
+ <PublisherText publisher_id="scholastic">New York : Scholastic, c2000.</PublisherText>
73
+ <Details change_time="2009-09-29T18:09:13Z" price_time="2011-03-25T22:20:05Z" edition_info="(pbk.) :$3.99" language="eng" physical_description_text="64 p. : ill. (some col.) ; 20 cm." lcc_number="" dewey_decimal_normalized="" dewey_decimal="" />
74
+ </BookData>
75
+ </BookList>
76
+ </ISBNdb>
@@ -0,0 +1,46 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+
3
+ <ISBNdb server_time="2012-06-16T20:36:49Z">
4
+ <CategoryList total_results="99" page_size="10" page_number="1" shown_results="10">
5
+ <CategoryData category_id="society.religion.christianity.denominations.catholicism.literature.fiction" parent_id="society.religion.christianity.denominations.catholicism.literature">
6
+ <Name>Fiction</Name>
7
+ <Details summary="" depth="6" element_count="30" />
8
+ </CategoryData>
9
+ <CategoryData category_id="society.religion.christianity.denominations.catholicism.clergy.fiction" parent_id="society.religion.christianity.denominations.catholicism.clergy">
10
+ <Name>Fiction</Name>
11
+ <Details summary="" depth="6" element_count="16" />
12
+ </CategoryData>
13
+ <CategoryData category_id="society.family.family_members.fathers.single_and_divorced.fiction" parent_id="society.family.family_members.fathers.single_and_divorced">
14
+ <Name>Fiction</Name>
15
+ <Details summary="" depth="5" element_count="7" />
16
+ </CategoryData>
17
+ <CategoryData category_id="society.family.family_members.mothers.single_and_divorced.fiction" parent_id="society.family.family_members.mothers.single_and_divorced">
18
+ <Name>Fiction</Name>
19
+ <Details summary="" depth="5" element_count="25" />
20
+ </CategoryData>
21
+ <CategoryData category_id="society.family.family_members.mothers.working_mothers.fiction" parent_id="society.family.family_members.mothers.working_mothers">
22
+ <Name>Fiction</Name>
23
+ <Details summary="" depth="5" element_count="6" />
24
+ </CategoryData>
25
+ <CategoryData category_id="society.family.family_members.mothers.teenage_mothers.fiction" parent_id="society.family.family_members.mothers.teenage_mothers">
26
+ <Name>Fiction</Name>
27
+ <Details summary="" depth="5" element_count="4" />
28
+ </CategoryData>
29
+ <CategoryData category_id="society.sexuality.homosexuality.lesbians.literature.fiction" parent_id="society.sexuality.homosexuality.lesbians.literature">
30
+ <Name>Fiction</Name>
31
+ <Details summary="" depth="5" element_count="24" />
32
+ </CategoryData>
33
+ <CategoryData category_id="arts.music.styles.jazz.musicians.fiction" parent_id="arts.music.styles.jazz.musicians">
34
+ <Name>Fiction</Name>
35
+ <Details summary="" depth="5" element_count="6" />
36
+ </CategoryData>
37
+ <CategoryData category_id="regions.france.history.famous_people.napoleon_i.fiction" parent_id="regions.france.history.famous_people.napoleon_i">
38
+ <Name>Fiction</Name>
39
+ <Details summary="" depth="5" element_count="4" />
40
+ </CategoryData>
41
+ <CategoryData category_id="science.biology.fields.genetics.literature.fiction" parent_id="science.biology.fields.genetics.literature">
42
+ <Name>Fiction</Name>
43
+ <Details summary="" depth="5" element_count="3" />
44
+ </CategoryData>
45
+ </CategoryList>
46
+ </ISBNdb>
@@ -0,0 +1,6 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+
3
+ <ISBNdb server_time="2012-06-16T18:32:28Z">
4
+ <KeyStats granted="2" access_key="ABC123" requests="5" limit="0" />
5
+ <BookList total_results="0" page_size="10" page_number="1" shown_results="0"></BookList>
6
+ </ISBNdb>
@@ -0,0 +1,46 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+
3
+ <ISBNdb server_time="2012-06-16T20:42:39Z">
4
+ <PublisherList total_results="276" page_size="10" page_number="1" shown_results="10">
5
+ <PublisherData publisher_id="taylor_francis_a01">
6
+ <Name>: Taylor &amp; Francis</Name>
7
+ <Details location="London [etc.]" />
8
+ </PublisherData>
9
+ <PublisherData publisher_id="a_a_balkema_taylor_francis">
10
+ <Name>A.A. Balkema/Taylor &amp; Francis</Name>
11
+ <Details location="Leiden, The Netherlands" />
12
+ </PublisherData>
13
+ <PublisherData publisher_id="albert_francis_perrin">
14
+ <Name>Albert Francis Perrin</Name>
15
+ <Details location="Ottawa" />
16
+ </PublisherData>
17
+ <PublisherData publisher_id="auerbach_publications_tayl_a02">
18
+ <Name>Auerbach Publications, Taylor &amp; Francis Group</Name>
19
+ <Details location="Boca Raton, FL" />
20
+ </PublisherData>
21
+ <PublisherData publisher_id="auerbach_publications_tayl_a01">
22
+ <Name>Auerbach Publications/Taylor &amp; Francis</Name>
23
+ <Details location="Boca Raton, FL" />
24
+ </PublisherData>
25
+ <PublisherData publisher_id="auerbach_publications_taylor_f">
26
+ <Name>Auerbach Publications/Taylor &amp; Francis Group</Name>
27
+ <Details location="Boca Raton, FL" />
28
+ </PublisherData>
29
+ <PublisherData publisher_id="auerbach_taylor_francis">
30
+ <Name>Auerbach/Taylor&amp;Francis</Name>
31
+ <Details location="Boca Raton" />
32
+ </PublisherData>
33
+ <PublisherData publisher_id="b_francis">
34
+ <Name>B. Francis</Name>
35
+ <Details location="[Coolangatta, Qld.]" />
36
+ </PublisherData>
37
+ <PublisherData publisher_id="balkema_taylor_francis">
38
+ <Name>Balkema/Taylor &amp; Francis</Name>
39
+ <Details location="[London]" />
40
+ </PublisherData>
41
+ <PublisherData publisher_id="beau_francis_press">
42
+ <Name>Beau Francis Press</Name>
43
+ <Details location="" />
44
+ </PublisherData>
45
+ </PublisherList>
46
+ </ISBNdb>