great_schools 0.1.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.
- checksums.yaml +15 -0
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +58 -0
- data/Rakefile +6 -0
- data/great_schools.gemspec +28 -0
- data/lib/great_schools.rb +88 -0
- data/lib/great_schools/census.rb +52 -0
- data/lib/great_schools/city.rb +72 -0
- data/lib/great_schools/district.rb +29 -0
- data/lib/great_schools/error.rb +51 -0
- data/lib/great_schools/ethnicity.rb +5 -0
- data/lib/great_schools/model.rb +45 -0
- data/lib/great_schools/rank.rb +5 -0
- data/lib/great_schools/result.rb +5 -0
- data/lib/great_schools/review.rb +47 -0
- data/lib/great_schools/school.rb +177 -0
- data/lib/great_schools/score.rb +47 -0
- data/lib/great_schools/test.rb +22 -0
- data/lib/great_schools/version.rb +14 -0
- data/spec/fixtures/browse_districts.xml +35 -0
- data/spec/fixtures/browse_schools.xml +46 -0
- data/spec/fixtures/city_overview.xml +12 -0
- data/spec/fixtures/error.xml +7 -0
- data/spec/fixtures/nearby_cities.xml +25 -0
- data/spec/fixtures/nearby_schools.xml +37 -0
- data/spec/fixtures/school_census_data.xml +40 -0
- data/spec/fixtures/school_profile.xml +70 -0
- data/spec/fixtures/school_reviews.xml +21 -0
- data/spec/fixtures/school_search.xml +38 -0
- data/spec/fixtures/school_test_scores.xml +33 -0
- data/spec/great_schools/census_spec.rb +28 -0
- data/spec/great_schools/city_spec.rb +72 -0
- data/spec/great_schools/district_spec.rb +34 -0
- data/spec/great_schools/ethnicity_spec.rb +17 -0
- data/spec/great_schools/rank_spec.rb +33 -0
- data/spec/great_schools/result_spec.rb +26 -0
- data/spec/great_schools/review_spec.rb +72 -0
- data/spec/great_schools/school_spec.rb +167 -0
- data/spec/great_schools/score_spec.rb +20 -0
- data/spec/great_schools/test_spec.rb +35 -0
- data/spec/great_schools_spec.rb +14 -0
- data/spec/spec_helper.rb +18 -0
- metadata +195 -0
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
|
3
|
+
module GreatSchools # :nodoc:
|
4
|
+
# = GreatSchools Base Model
|
5
|
+
class Model
|
6
|
+
class << self # Class methods
|
7
|
+
protected
|
8
|
+
# Makes a URL slug from the string.
|
9
|
+
#
|
10
|
+
# Replaces dashes with underscores, spaces with dashes, and URL encodes
|
11
|
+
# any special characters.
|
12
|
+
#
|
13
|
+
# ==== Examples
|
14
|
+
#
|
15
|
+
# parameterize('San Francisco') # => 'San-Francisco'
|
16
|
+
# parameterize('Cardiff-By-The-Sea') # => 'Cardiff_By_The_Sea'
|
17
|
+
def parameterize(string)
|
18
|
+
CGI.escape(string.gsub('-', '_').gsub(' ', '-'))
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# Base initializer, map camelCased XML attributes from the GreatSchools API
|
23
|
+
# response to the appropriately underscored attribute setters.
|
24
|
+
def initialize(attributes = {})
|
25
|
+
attributes.each do |key, value|
|
26
|
+
key = underscore(key)
|
27
|
+
send("#{key}=", value) if respond_to?("#{key}=")
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
protected
|
32
|
+
|
33
|
+
# Makes an underscored, lowercase form from the expression in the string.
|
34
|
+
#
|
35
|
+
# ==== Examples
|
36
|
+
#
|
37
|
+
# underscore('myACRONYMString') # => 'my_acronym_string'
|
38
|
+
def underscore(word)
|
39
|
+
word = word.to_s.dup # unfreeze any frozen strings
|
40
|
+
word.gsub!(/([a-z])([A-Z])/,'\1_\2') # myACRONYMString => my_ACRONYMString
|
41
|
+
word.gsub!(/([A-Z]+)(?=[A-Z][a-z])/, '\1_\2') # my_ACRONYMString => my_ACRONYM_String
|
42
|
+
word.downcase # my_ACRONYM_String => my_acronym_string
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module GreatSchools # :nodoc:
|
2
|
+
# = GreatSchools Review
|
3
|
+
class Review < Model
|
4
|
+
attr_accessor :school_name, :school_address
|
5
|
+
attr_accessor :review_link, :rating, :submitter, :posted_date, :comments
|
6
|
+
|
7
|
+
class << self # Class methods
|
8
|
+
# Returns a list of the most recent reviews for any schools in a city.
|
9
|
+
#
|
10
|
+
# ==== Attributes
|
11
|
+
#
|
12
|
+
# * +state+ - Two letter state abbreviation
|
13
|
+
# * +city+ - Name of city
|
14
|
+
#
|
15
|
+
# ==== Options
|
16
|
+
#
|
17
|
+
# * +:cutoff_age+ - Reviews must have been published after this many days
|
18
|
+
# ago to be returned.
|
19
|
+
# * +:limit+ - Maximum number of reviews to return. This defaults to 5.
|
20
|
+
def for_city(state, city, options = {})
|
21
|
+
options[:cutoffAge] = options.delete(:cutoff_age) # TODO: make helper method to camelCase or map query attributes
|
22
|
+
|
23
|
+
response = GreatSchools::API.get("reviews/city/#{state.upcase}/#{parameterize(city)}", options.slice(:cutoffAge, :limit))
|
24
|
+
|
25
|
+
Array.wrap(response).map { |review| new(review) }
|
26
|
+
end
|
27
|
+
|
28
|
+
# Returns a list of the most recent reviews for a school.
|
29
|
+
#
|
30
|
+
# ==== Attributes
|
31
|
+
#
|
32
|
+
# * +state+ - Two letter state abbreviation
|
33
|
+
# * +id+ - Numeric id of a school. This GreatSchools ID is included in
|
34
|
+
# other listing requests like +GreatSchools::School#browse+
|
35
|
+
# and +GreatSchools::School#nearby+
|
36
|
+
#
|
37
|
+
# ==== Options
|
38
|
+
#
|
39
|
+
# * +:limit+ - Maximum number of reviews to return. This defaults to 5.
|
40
|
+
def for_school(state, id, options = {})
|
41
|
+
response = GreatSchools::API.get("reviews/school/#{state.upcase}/#{id}", options.slice(:limit))
|
42
|
+
|
43
|
+
Array.wrap(response).map { |review| new(review) }
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,177 @@
|
|
1
|
+
module GreatSchools # :nodoc:
|
2
|
+
# = GreatSchools School
|
3
|
+
class School < Model
|
4
|
+
attr_accessor :id, :name, :type, :grade_range, :enrollment, :district_id, :district, :district_nces_id, :nces_id
|
5
|
+
attr_accessor :city, :state, :address, :phone, :fax, :website, :latitude, :longitude
|
6
|
+
attr_accessor :overview_link, :ratings_link, :reviews_link, :parent_reviews, :parent_rating
|
7
|
+
|
8
|
+
alias_method :gs_id=, :id=
|
9
|
+
alias_method :lat=, :latitude=
|
10
|
+
alias_method :lon=, :longitude=
|
11
|
+
|
12
|
+
class << self # Class methods
|
13
|
+
# Returns a list of schools in a city.
|
14
|
+
#
|
15
|
+
# ==== Attributes
|
16
|
+
#
|
17
|
+
# * +state+ - Two letter state abbreviation
|
18
|
+
# * +city+ - Name of city
|
19
|
+
#
|
20
|
+
# ==== Options
|
21
|
+
#
|
22
|
+
# * +:school_types+ - Type of school(s) you wish to appear in the list:
|
23
|
+
# 'public', 'charter', and/or 'private'
|
24
|
+
# * +:level+ - Level of school you wish to appear in the list:
|
25
|
+
# 'elementary-schools', 'middle-schools', or 'high-schools'
|
26
|
+
# * +:sort+ - How to sort the results, either by name (ascending),
|
27
|
+
# by GreatSchools rating (descending), or by overall
|
28
|
+
# parent rating (descending). The default sort is name
|
29
|
+
# (ascending). When sorted by rating, schools without
|
30
|
+
# a rating will appear last. Options: 'name',
|
31
|
+
# 'gs_rating', or 'parent_rating'
|
32
|
+
# * +:limit+ - Maximum number of schools to return. This defaults
|
33
|
+
# to 200. To get all results, use -1.
|
34
|
+
# --
|
35
|
+
# TODO: handle validations
|
36
|
+
# ++
|
37
|
+
def browse(state, city, options = {})
|
38
|
+
school_types = Array.wrap(options.delete(:school_types)).join('-')
|
39
|
+
level = options.delete(:level)
|
40
|
+
|
41
|
+
url = "schools/#{state.upcase}/#{parameterize(city)}"
|
42
|
+
url << "/#{school_types}" if school_types.present?
|
43
|
+
url << "/#{level}" if level.present?
|
44
|
+
|
45
|
+
response = GreatSchools::API.get(url, options.slice(:sort, :limit))
|
46
|
+
|
47
|
+
Array.wrap(response).map { |school| new(school) }
|
48
|
+
end
|
49
|
+
|
50
|
+
# Returns a list of schools closest to the center of a city, ZIP Code or
|
51
|
+
# address.
|
52
|
+
#
|
53
|
+
# ==== Attributes
|
54
|
+
#
|
55
|
+
# * +state+ - Two letter state abbreviation
|
56
|
+
#
|
57
|
+
# ==== Options
|
58
|
+
#
|
59
|
+
# * +:zip_code+ - 5 digit zip code
|
60
|
+
# * +:city+ - Name of city
|
61
|
+
# * +:address+ - Address of location
|
62
|
+
# * +:latitude+ - Latitude of location
|
63
|
+
# * +:longitude+ - Longitude of location
|
64
|
+
# * +:school_types+ - Type of school(s) you wish to appear in the list:
|
65
|
+
# 'public', 'charter', and/or 'private'
|
66
|
+
# * +:level+ - Level of school you wish to appear in the list:
|
67
|
+
# 'elementary-schools', 'middle-schools', or 'high-schools'
|
68
|
+
# * +:minimum_schools+ - Minimum number of schools to return. When provided,
|
69
|
+
# if the initial query field yields fewer schools than
|
70
|
+
# this value, the radius will be increased in 5 mile
|
71
|
+
# increments to a maximum of 50 miles or until the
|
72
|
+
# result set has enough schools to meet this value.
|
73
|
+
# Maximum value is 200. This value must be less than
|
74
|
+
# the limit or else it is ignored.
|
75
|
+
# * +:radius+ - Miles radius to confine search to. This default to 5,
|
76
|
+
# with a maximum of 50.
|
77
|
+
# * +:limit+ - Maximum number of schools to return. This defaults to 200.
|
78
|
+
# --
|
79
|
+
# TODO: handle validations
|
80
|
+
# ++
|
81
|
+
def nearby(state, options = {})
|
82
|
+
options[:lat] = options.delete(:latitude)
|
83
|
+
options[:levelCode] = options.delete(:level)
|
84
|
+
options[:lon] = options.delete(:longitude)
|
85
|
+
options[:minimumSchools] = options.delete(:minimum_schools)
|
86
|
+
options[:schoolType] = options.delete(:school_types).try(:join, '-')
|
87
|
+
options[:state] = state
|
88
|
+
options[:zip] = options.delete(:zip_code)
|
89
|
+
|
90
|
+
options.slice!(:address, :city, :lat, :levelCode, :limit, :lon, :minimumSchools, :radius, :schoolType, :state, :zip)
|
91
|
+
|
92
|
+
response = GreatSchools::API.get('schools/nearby', options)
|
93
|
+
|
94
|
+
Array.wrap(response).map { |school| new(school) }
|
95
|
+
end
|
96
|
+
|
97
|
+
# Returns profile data for a specific school.
|
98
|
+
#
|
99
|
+
# ==== Attributes
|
100
|
+
#
|
101
|
+
# * +state+ - Two letter state abbreviation
|
102
|
+
# * +id+ - Numeric id of a school. This GreatSchools ID is included in
|
103
|
+
# other listing requests like +GreatSchools::School#browse+
|
104
|
+
# and +GreatSchools::School#nearby+
|
105
|
+
def profile(state, id)
|
106
|
+
response = GreatSchools::API.get("schools/#{state.upcase}/#{id}")
|
107
|
+
|
108
|
+
new(response)
|
109
|
+
end
|
110
|
+
|
111
|
+
# Returns a list of schools based on a search string.
|
112
|
+
#
|
113
|
+
# ==== Attributes
|
114
|
+
#
|
115
|
+
# * +state+ - Two letter state abbreviation
|
116
|
+
# * +query+ - Search query string
|
117
|
+
#
|
118
|
+
# ==== Options
|
119
|
+
#
|
120
|
+
# * +:level+ - Level of school you wish to appear in the list:
|
121
|
+
# 'elementary-schools', 'middle-schools', or 'high-schools'
|
122
|
+
# * +:sort+ - This call by default sorts the results by relevance. You
|
123
|
+
# can sort the results alphabetically by using 'alpha'.
|
124
|
+
# * +:limit+ - Maximum number of schools to return. This defaults to
|
125
|
+
# 200 and must be at least 1.
|
126
|
+
# --
|
127
|
+
# TODO: handle validations
|
128
|
+
# ++
|
129
|
+
def search(state, query, options = {})
|
130
|
+
options[:levelCode] = options.delete(:level)
|
131
|
+
options[:q] = query
|
132
|
+
options[:state] = state
|
133
|
+
options.slice!(:state, :q, :levelCode, :sort, :limit)
|
134
|
+
|
135
|
+
response = GreatSchools::API.get('search/schools', options)
|
136
|
+
|
137
|
+
Array.wrap(response).map { |school| new(school) }
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
# Returns census and profile data for the school.
|
142
|
+
def census
|
143
|
+
GreatSchools::Census.for_school(state, id)
|
144
|
+
end
|
145
|
+
|
146
|
+
# Set an array of +GreatSchools::Review+.
|
147
|
+
#
|
148
|
+
# ==== Attributes
|
149
|
+
#
|
150
|
+
# * +params+ - a +Hash+ or +Array+ of +GreatSchools::Review+ attributes.
|
151
|
+
def parent_reviews=(params)
|
152
|
+
@parent_reviews = []
|
153
|
+
|
154
|
+
params = params['review'] if params.is_a?(Hash) && params.key?('review')
|
155
|
+
|
156
|
+
Array.wrap(params).each do |hash|
|
157
|
+
@parent_reviews << GreatSchools::Review.new(hash)
|
158
|
+
end
|
159
|
+
|
160
|
+
@parent_reviews
|
161
|
+
end
|
162
|
+
|
163
|
+
# Returns a list of the most recent reviews for the school.
|
164
|
+
#
|
165
|
+
# ==== Options
|
166
|
+
#
|
167
|
+
# * +:limit+ - Maximum number of reviews to return. This defaults to 5.
|
168
|
+
def reviews(options = {})
|
169
|
+
GreatSchools::Review.for_school(state, id, options.slice(:limit))
|
170
|
+
end
|
171
|
+
|
172
|
+
# Returns test and rank data for the school.
|
173
|
+
def score
|
174
|
+
GreatSchools::Score.for_school(state, id)
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module GreatSchools # :nodoc:
|
2
|
+
# = GreatSchools Score
|
3
|
+
class Score < Model
|
4
|
+
attr_accessor :school_name, :rank, :tests
|
5
|
+
|
6
|
+
class << self # Class methods
|
7
|
+
# Returns test and rank data for a specific school.
|
8
|
+
#
|
9
|
+
# ==== Attributes
|
10
|
+
#
|
11
|
+
# * +state+ - Two letter state abbreviation
|
12
|
+
# * +id+ - Numeric id of a school. This GreatSchools ID is included in
|
13
|
+
# other listing requests like +GreatSchools::School#browse+
|
14
|
+
# and +GreatSchools::School#nearby+
|
15
|
+
def for_school(state, id)
|
16
|
+
response = GreatSchools::API.get("school/tests/#{state.upcase}/#{id}")
|
17
|
+
|
18
|
+
new(response)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# Set the +GreatSchools::Rank+.
|
23
|
+
#
|
24
|
+
# ==== Attributes
|
25
|
+
#
|
26
|
+
# * +params+ - a +Hash+ of +GreatSchools::Rank+ attributes.
|
27
|
+
def rank=(params)
|
28
|
+
@rank = GreatSchools::Rank.new(params)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Set an array of +GreatSchools::Test+.
|
32
|
+
#
|
33
|
+
# ==== Attributes
|
34
|
+
#
|
35
|
+
# * +params+ - a +Hash+ or +Array+ of +GreatSchools::Test+ attributes.
|
36
|
+
def tests=(params)
|
37
|
+
@tests = []
|
38
|
+
|
39
|
+
Array.wrap(params).each do |hash|
|
40
|
+
@tests << GreatSchools::Test.new(hash)
|
41
|
+
end
|
42
|
+
|
43
|
+
@tests
|
44
|
+
end
|
45
|
+
alias_method :test=, :tests=
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module GreatSchools # :nodoc:
|
2
|
+
# = GreatSchools Test
|
3
|
+
class Test < Model
|
4
|
+
attr_accessor :name, :id, :description, :abbreviation, :scale, :level_code, :results
|
5
|
+
|
6
|
+
# Set an array of +GreatSchools::Result+.
|
7
|
+
#
|
8
|
+
# ==== Attributes
|
9
|
+
#
|
10
|
+
# * +params+ - a +Hash+ or +Array+ of +GreatSchools::Result+ attributes.
|
11
|
+
def results=(params)
|
12
|
+
@results = []
|
13
|
+
|
14
|
+
Array.wrap(params).each do |hash|
|
15
|
+
@results << GreatSchools::Result.new(hash)
|
16
|
+
end
|
17
|
+
|
18
|
+
@results
|
19
|
+
end
|
20
|
+
alias_method :test_result=, :results=
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module GreatSchools # :nodoc:
|
2
|
+
class Version # :nodoc:
|
3
|
+
MAJOR = 0 # version when you make incompatible API changes
|
4
|
+
MINOR = 1 # version when you add functionality in a backwards-compatible manner
|
5
|
+
PATCH = 0 # version when you make backwards-compatible bug fixes
|
6
|
+
|
7
|
+
class << self # Class methods
|
8
|
+
# MAJOR.MINOR.PATCH per Semantic Versioning 2.0.0
|
9
|
+
def to_s
|
10
|
+
"#{MAJOR}.#{MINOR}.#{PATCH}"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
2
|
+
<districts>
|
3
|
+
<district>
|
4
|
+
<name>San Francisco Unified School District</name>
|
5
|
+
<ncesCode>0634410</ncesCode>
|
6
|
+
<districtRating>6</districtRating>
|
7
|
+
<address>555 Franklin St., San Francisco, CA 94102</address>
|
8
|
+
<phone>(415) 241-6000</phone>
|
9
|
+
<fax>(415) 241-6012</fax>
|
10
|
+
<website>http://www.sfusd.k12.ca.us</website>
|
11
|
+
<gradeRange>K-12 & ungraded</gradeRange>
|
12
|
+
<totalSchools>121</totalSchools>
|
13
|
+
<elementarySchools>84</elementarySchools>
|
14
|
+
<middleSchools>36</middleSchools>
|
15
|
+
<highSchools>34</highSchools>
|
16
|
+
<publicSchools>113</publicSchools>
|
17
|
+
<charterSchools>8</charterSchools>
|
18
|
+
</district>
|
19
|
+
<district>
|
20
|
+
<name>San Francisco County Office of Education</name>
|
21
|
+
<ncesCode>0691111</ncesCode>
|
22
|
+
<districtRating>1</districtRating>
|
23
|
+
<address>555 Franklin St., San Francisco, CA 94102</address>
|
24
|
+
<phone>(415) 241-6000</phone>
|
25
|
+
<fax>(415) 241-6012</fax>
|
26
|
+
<website>http://www.sfusd.k12.ca.us</website>
|
27
|
+
<gradeRange>K-12</gradeRange>
|
28
|
+
<totalSchools>4</totalSchools>
|
29
|
+
<elementarySchools>2</elementarySchools>
|
30
|
+
<middleSchools>3</middleSchools>
|
31
|
+
<highSchools>4</highSchools>
|
32
|
+
<publicSchools>4</publicSchools>
|
33
|
+
<charterSchools>0</charterSchools>
|
34
|
+
</district>
|
35
|
+
</districts>
|
@@ -0,0 +1,46 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
2
|
+
<schools>
|
3
|
+
<school>
|
4
|
+
<gsId>13978</gsId>
|
5
|
+
<name>Alder Creek Middle School</name>
|
6
|
+
<type>public</type>
|
7
|
+
<gradeRange>6-8</gradeRange>
|
8
|
+
<enrollment>598</enrollment>
|
9
|
+
<city>Truckee</city>
|
10
|
+
<state>CA</state>
|
11
|
+
<districtId>509</districtId>
|
12
|
+
<district>Tahoe-Truckee Joint Unified School District</district>
|
13
|
+
<districtNCESId>0638770</districtNCESId>
|
14
|
+
<address>10931 Alder Dr., Truckee, CA 96161</address>
|
15
|
+
<phone>(530) 582-2750</phone>
|
16
|
+
<fax>(530) 582-7640</fax>
|
17
|
+
<website>http://www.ttusd.org</website>
|
18
|
+
<ncesId>063877011005</ncesId>
|
19
|
+
<lat>39.3454</lat>
|
20
|
+
<lon>-120.1735</lon>
|
21
|
+
<overviewLink>http://www.greatschools.org/modperl/browse_school/ca/13978?s_cid=gsapi</overviewLink>
|
22
|
+
<ratingsLink>http://www.greatschools.org/school/rating.page?state=CA&id=13978&s_cid=gsapi</ratingsLink>
|
23
|
+
<reviewsLink>http://www.greatschools.org/school/parentReviews.page?state=CA&id=13978&s_cid=gsapi</reviewsLink>
|
24
|
+
</school>
|
25
|
+
<school>
|
26
|
+
<gsId>11039</gsId>
|
27
|
+
<name>Cold Stream Alternative School</name>
|
28
|
+
<type>public</type>
|
29
|
+
<gradeRange>9-12</gradeRange>
|
30
|
+
<enrollment>47</enrollment>
|
31
|
+
<city>Truckee</city>
|
32
|
+
<state>CA</state>
|
33
|
+
<districtId>509</districtId>
|
34
|
+
<district>Tahoe-Truckee Joint Unified School District</district>
|
35
|
+
<districtNCESId>0638770</districtNCESId>
|
36
|
+
<address>11661 Donner Pass Rd., Truckee, CA 96161</address>
|
37
|
+
<phone>(530) 582-2640</phone>
|
38
|
+
<fax>(530) 582-7640</fax>
|
39
|
+
<ncesId>063877006175</ncesId>
|
40
|
+
<lat>39.3259</lat>
|
41
|
+
<lon>-120.2147</lon>
|
42
|
+
<overviewLink>http://www.greatschools.org/modperl/browse_school/ca/11039?s_cid=gsapi</overviewLink>
|
43
|
+
<ratingsLink>http://www.greatschools.org/school/rating.page?state=CA&id=11039&s_cid=gsapi</ratingsLink>
|
44
|
+
<reviewsLink>http://www.greatschools.org/school/parentReviews.page?state=CA&id=11039&s_cid=gsapi</reviewsLink>
|
45
|
+
</school>
|
46
|
+
</schools>
|