uva-happymapper 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. data/README.md +528 -0
  2. data/TODO +0 -0
  3. data/lib/happymapper.rb +617 -0
  4. data/lib/happymapper/attribute.rb +3 -0
  5. data/lib/happymapper/element.rb +3 -0
  6. data/lib/happymapper/item.rb +250 -0
  7. data/lib/happymapper/text_node.rb +3 -0
  8. data/spec/fixtures/address.xml +8 -0
  9. data/spec/fixtures/ambigous_items.xml +22 -0
  10. data/spec/fixtures/analytics.xml +61 -0
  11. data/spec/fixtures/analytics_profile.xml +127 -0
  12. data/spec/fixtures/atom.xml +19 -0
  13. data/spec/fixtures/commit.xml +52 -0
  14. data/spec/fixtures/current_weather.xml +89 -0
  15. data/spec/fixtures/dictionary.xml +20 -0
  16. data/spec/fixtures/family_tree.xml +21 -0
  17. data/spec/fixtures/inagy.xml +86 -0
  18. data/spec/fixtures/lastfm.xml +355 -0
  19. data/spec/fixtures/multiple_namespaces.xml +170 -0
  20. data/spec/fixtures/multiple_primitives.xml +5 -0
  21. data/spec/fixtures/pita.xml +133 -0
  22. data/spec/fixtures/posts.xml +23 -0
  23. data/spec/fixtures/product_default_namespace.xml +17 -0
  24. data/spec/fixtures/product_no_namespace.xml +10 -0
  25. data/spec/fixtures/product_single_namespace.xml +10 -0
  26. data/spec/fixtures/quarters.xml +19 -0
  27. data/spec/fixtures/radar.xml +21 -0
  28. data/spec/fixtures/statuses.xml +422 -0
  29. data/spec/fixtures/subclass_namespace.xml +50 -0
  30. data/spec/happymapper_attribute_spec.rb +21 -0
  31. data/spec/happymapper_element_spec.rb +21 -0
  32. data/spec/happymapper_item_spec.rb +115 -0
  33. data/spec/happymapper_spec.rb +968 -0
  34. data/spec/happymapper_text_node_spec.rb +21 -0
  35. data/spec/happymapper_to_xml_namespaces_spec.rb +196 -0
  36. data/spec/happymapper_to_xml_spec.rb +196 -0
  37. data/spec/ignay_spec.rb +95 -0
  38. data/spec/spec_helper.rb +7 -0
  39. data/spec/xpath_spec.rb +88 -0
  40. metadata +118 -0
@@ -0,0 +1,3 @@
1
+ module HappyMapper
2
+ class Attribute < Item; end
3
+ end
@@ -0,0 +1,3 @@
1
+ module HappyMapper
2
+ class Element < Item; end
3
+ end
@@ -0,0 +1,250 @@
1
+ module HappyMapper
2
+ class Item
3
+ attr_accessor :name, :type, :tag, :options, :namespace
4
+
5
+ Types = [String, Float, Time, Date, DateTime, Integer, Boolean]
6
+
7
+ # options:
8
+ # :deep => Boolean False to only parse element's children, True to include
9
+ # grandchildren and all others down the chain (// in xpath)
10
+ # :namespace => String Element's namespace if it's not the global or inherited
11
+ # default
12
+ # :parser => Symbol Class method to use for type coercion.
13
+ # :raw => Boolean Use raw node value (inc. tags) when parsing.
14
+ # :single => Boolean False if object should be collection, True for single object
15
+ # :tag => String Element name if it doesn't match the specified name.
16
+ def initialize(name, type, o={})
17
+ self.name = name.to_s
18
+ self.type = type
19
+ #self.tag = o.delete(:tag) || name.to_s
20
+ self.tag = o[:tag] || name.to_s
21
+ self.options = { :single => true }.merge(o.merge(:name => self.name))
22
+
23
+ @xml_type = self.class.to_s.split('::').last.downcase
24
+ end
25
+
26
+ def constant
27
+ @constant ||= constantize(type)
28
+ end
29
+
30
+ #
31
+ # @param [XMLNode] node the xml node that is being parsed
32
+ # @param [String] namespace the name of the namespace
33
+ # @param [Hash] xpath_options additional xpath options
34
+ #
35
+ def from_xml_node(node, namespace, xpath_options)
36
+
37
+ # If the item is defined as a primitive type then cast the value to that type
38
+ # else if the type is XMLContent then store the xml value
39
+ # else the type, specified, needs to handle the parsing.
40
+
41
+ if primitive?
42
+ find(node, namespace, xpath_options) do |n|
43
+ if n.respond_to?(:content)
44
+ typecast(n.content)
45
+ else
46
+ typecast(n.to_s)
47
+ end
48
+ end
49
+ elsif constant == XmlContent
50
+ find(node, namespace, xpath_options) do |n|
51
+ n = n.children if n.respond_to?(:children)
52
+ n.respond_to?(:to_xml) ? n.to_xml : n.to_s
53
+ end
54
+ else
55
+
56
+ # When not a primitive type or XMLContent then default to using the
57
+ # class method #parse of the type class. If the option 'parser' has been
58
+ # defined then call that method on the type class instead of #parse
59
+
60
+ if options[:parser]
61
+ find(node, namespace, xpath_options) do |n|
62
+ if n.respond_to?(:content) && !options[:raw]
63
+ value = n.content
64
+ else
65
+ value = n.to_s
66
+ end
67
+
68
+ begin
69
+ constant.send(options[:parser].to_sym, value)
70
+ rescue
71
+ nil
72
+ end
73
+ end
74
+ else
75
+ constant.parse(node, options.merge(:namespaces => xpath_options))
76
+ end
77
+ end
78
+ end
79
+
80
+ def xpath(namespace = self.namespace)
81
+ xpath = ''
82
+ xpath += './/' if options[:deep]
83
+ xpath += "#{namespace}:" if namespace
84
+ xpath += tag
85
+ #puts "xpath: #{xpath}"
86
+ xpath
87
+ end
88
+
89
+ # @return [Boolean] true if the type defined for the item is defined in the
90
+ # list of primite types {Types}.
91
+ def primitive?
92
+ Types.include?(constant)
93
+ end
94
+
95
+ def element?
96
+ @xml_type == 'element'
97
+ end
98
+
99
+ def attribute?
100
+ @xml_type == 'attribute'
101
+ end
102
+
103
+ def text_node?
104
+ @xml_type == 'textnode'
105
+ end
106
+
107
+ def method_name
108
+ @method_name ||= name.tr('-', '_')
109
+ end
110
+
111
+ #
112
+ # When the type of the item is a primitive type, this will convert value specifed
113
+ # to the particular primitive type. If it fails during this process it will
114
+ # return the original String value.
115
+ #
116
+ # @param [String] value the string value parsed from the XML value that will
117
+ # be converted to the particular primitive type.
118
+ #
119
+ # @return [String,Float,Time,Date,DateTime,Boolean,Integer] the converted value
120
+ # to the new type.
121
+ #
122
+ def typecast(value)
123
+ return value if value.kind_of?(constant) || value.nil?
124
+ begin
125
+ if constant == String then value.to_s
126
+ elsif constant == Float then value.to_f
127
+ elsif constant == Time then Time.parse(value.to_s) rescue Time.at(value.to_i)
128
+ elsif constant == Date then Date.parse(value.to_s)
129
+ elsif constant == DateTime then DateTime.parse(value.to_s)
130
+ elsif constant == Boolean then ['true', 't', '1'].include?(value.to_s.downcase)
131
+ elsif constant == Integer
132
+ # ganked from datamapper
133
+ value_to_i = value.to_i
134
+ if value_to_i == 0 && value != '0'
135
+ value_to_s = value.to_s
136
+ begin
137
+ Integer(value_to_s =~ /^(\d+)/ ? $1 : value_to_s)
138
+ rescue ArgumentError
139
+ nil
140
+ end
141
+ else
142
+ value_to_i
143
+ end
144
+ else
145
+ value
146
+ end
147
+ rescue
148
+ value
149
+ end
150
+ end
151
+
152
+ private
153
+
154
+ #
155
+ # Convert any String defined types into their constant version so that
156
+ # the method #parse or the custom defined parser method would be used.
157
+ #
158
+ # @param [String,Constant] type is the name of the class or the constant
159
+ # for the class.
160
+ # @return [Constant] the constant of the type
161
+ #
162
+ def constantize(type)
163
+ if type.is_a?(String)
164
+ names = type.split('::')
165
+ constant = Object
166
+ names.each do |name|
167
+ constant =
168
+ if constant.const_defined?(name)
169
+ constant.const_get(name)
170
+ else
171
+ constant.const_missing(name)
172
+ end
173
+ end
174
+ constant
175
+ else
176
+ type
177
+ end
178
+ end
179
+
180
+
181
+ def find(node, namespace, xpath_options, &block)
182
+ if self.namespace && xpath_options["xmlns:#{self.namespace}"]
183
+ # from the class definition
184
+ namespace = self.namespace
185
+ elsif options[:namespace] && xpath_options["xmlns:#{options[:namespace]}"]
186
+ namespace = options[:namespace]
187
+ end
188
+
189
+ if element?
190
+ if options[:single]
191
+
192
+ result = nil
193
+
194
+ if options[:xpath]
195
+ result = node.xpath(options[:xpath], xpath_options)
196
+ else
197
+ result = node.xpath(xpath(namespace), xpath_options)
198
+ end
199
+
200
+ if result
201
+ value = options[:single] ? yield(result.first) : result.map {|r| yield r }
202
+ handle_attributes_option(result, value, xpath_options)
203
+
204
+ value
205
+ end
206
+ else
207
+
208
+ target_path = options[:xpath] ? options[:xpath] : xpath(namespace)
209
+
210
+ results = node.xpath(target_path, xpath_options).collect do |result|
211
+ value = yield(result)
212
+ handle_attributes_option(result, value, xpath_options)
213
+ value
214
+ end
215
+ results
216
+ end
217
+ elsif attribute?
218
+
219
+ if options[:xpath]
220
+ yield(node.xpath(options[:xpath],xpath_options))
221
+ else
222
+ yield(node[tag])
223
+ end
224
+
225
+ else # text node
226
+ yield(node.children.detect{|c| c.text?})
227
+ end
228
+ end
229
+
230
+ def handle_attributes_option(result, value, xpath_options)
231
+ if options[:attributes].is_a?(Hash)
232
+ result = result.first unless result.respond_to?(:attribute_nodes)
233
+
234
+ result.attribute_nodes.each do |xml_attribute|
235
+ if attribute_options = options[:attributes][xml_attribute.name.to_sym]
236
+ attribute_value = Attribute.new(xml_attribute.name.to_sym, *attribute_options).from_xml_node(result, namespace, xpath_options)
237
+
238
+ result.instance_eval <<-EOV
239
+ def value.#{xml_attribute.name}
240
+ #{attribute_value.inspect}
241
+ end
242
+ EOV
243
+ end # if attributes_options
244
+ end # attribute_nodes.each
245
+ end # if options[:attributes]
246
+ end # def handle...
247
+
248
+ # end private methods
249
+ end
250
+ end
@@ -0,0 +1,3 @@
1
+ module HappyMapper
2
+ class TextNode < Item; end
3
+ end
@@ -0,0 +1,8 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <address>
3
+ <street>Milchstrasse</street>
4
+ <housenumber>23</housenumber>
5
+ <postcode>26131</postcode>
6
+ <city>Oldenburg</city>
7
+ <country code="de">Germany</country>
8
+ </address>
@@ -0,0 +1,22 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <ambigous>
3
+ <my-items>
4
+ <item>
5
+ <name>My first item</name>
6
+ <item><name>My first internal item</name></item>
7
+ </item>
8
+ <item>
9
+ <name>My second item</name>
10
+ <item><name>My second internal item</name></item>
11
+ </item>
12
+ <item>
13
+ <name>My third item</name>
14
+ <item><name>My third internal item</name></item>
15
+ </item>
16
+ </my-items>
17
+ <others-items>
18
+ <item>
19
+ <name>Other item</name>
20
+ </item>
21
+ <others-items>
22
+ </ambigous>
@@ -0,0 +1,61 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <feed xmlns="http://www.w3.org/2005/Atom"
3
+ xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/"
4
+ xmlns:dxp="http://schemas.google.com/analytics/2009">
5
+ <id>http://www.google.com/analytics/feeds/accounts/nunemaker@gmail.com</id>
6
+ <updated>2009-04-22T23:21:23.000-07:00</updated>
7
+ <title type="text">Profile list for nunemaker@gmail.com</title>
8
+ <link rel="self" type="application/atom+xml"
9
+ href="http://www.google.com/analytics/feeds/accounts/default"/>
10
+ <author>
11
+ <name>Google Analytics</name>
12
+ </author>
13
+ <generator version="1.0">Google Analytics</generator>
14
+ <openSearch:totalResults>4</openSearch:totalResults>
15
+ <openSearch:startIndex>1</openSearch:startIndex>
16
+ <openSearch:itemsPerPage>4</openSearch:itemsPerPage>
17
+ <entry>
18
+ <id>http://www.google.com/analytics/feeds/accounts/ga:47912</id>
19
+ <updated>2008-11-24T12:11:32.000-08:00</updated>
20
+ <title type="text">addictedtonew.com</title>
21
+ <link rel="alternate" type="text/html" href="http://www.google.com/analytics"/>
22
+ <dxp:tableId>ga:47912</dxp:tableId>
23
+ <dxp:property name="ga:accountId" value="85301"/>
24
+ <dxp:property name="ga:accountName" value="addictedtonew.com"/>
25
+ <dxp:property name="ga:profileId" value="47912"/>
26
+ <dxp:property name="ga:webPropertyId" value="UA-85301-1"/>
27
+ </entry>
28
+ <entry>
29
+ <id>http://www.google.com/analytics/feeds/accounts/ga:1897579</id>
30
+ <updated>2008-11-24T12:11:32.000-08:00</updated>
31
+ <title type="text">railstips.org</title>
32
+ <link rel="alternate" type="text/html" href="http://www.google.com/analytics"/>
33
+ <dxp:tableId>ga:1897579</dxp:tableId>
34
+ <dxp:property name="ga:accountId" value="85301"/>
35
+ <dxp:property name="ga:accountName" value="addictedtonew.com"/>
36
+ <dxp:property name="ga:profileId" value="1897579"/>
37
+ <dxp:property name="ga:webPropertyId" value="UA-85301-7"/>
38
+ </entry>
39
+ <entry>
40
+ <id>http://www.google.com/analytics/feeds/accounts/ga:17132454</id>
41
+ <updated>2009-04-22T23:21:23.000-07:00</updated>
42
+ <title type="text">johnnunemaker.com</title>
43
+ <link rel="alternate" type="text/html" href="http://www.google.com/analytics"/>
44
+ <dxp:tableId>ga:17132454</dxp:tableId>
45
+ <dxp:property name="ga:accountId" value="85301"/>
46
+ <dxp:property name="ga:accountName" value="addictedtonew.com"/>
47
+ <dxp:property name="ga:profileId" value="17132454"/>
48
+ <dxp:property name="ga:webPropertyId" value="UA-85301-25"/>
49
+ </entry>
50
+ <entry>
51
+ <id>http://www.google.com/analytics/feeds/accounts/ga:17132478</id>
52
+ <updated>2009-04-22T23:21:23.000-07:00</updated>
53
+ <title type="text">harmonyapp.com</title>
54
+ <link rel="alternate" type="text/html" href="http://www.google.com/analytics"/>
55
+ <dxp:tableId>ga:17132478</dxp:tableId>
56
+ <dxp:property name="ga:accountId" value="85301"/>
57
+ <dxp:property name="ga:accountName" value="addictedtonew.com"/>
58
+ <dxp:property name="ga:profileId" value="17132478"/>
59
+ <dxp:property name="ga:webPropertyId" value="UA-85301-26"/>
60
+ </entry>
61
+ </feed>
@@ -0,0 +1,127 @@
1
+ <feed xmlns='http://www.w3.org/2005/Atom' xmlns:dxp='http://schemas.google.com/analytics/2009' xmlns:openSearch='http://a9.com/-/spec/opensearch/1.1/' xmlns:gd='http://schemas.google.com/g/2005' gd:etag='W/&quot;CU4CSXo_cCp7I2A9Wx9RGU0.&quot;' gd:kind='analytics#accounts'>
2
+ <id>http://www.google.com/analytics/feeds/accounts/someuser@gmail.com</id>
3
+ <updated>2010-12-20T19:59:28.448-08:00</updated>
4
+ <title>Profile list for someuser@gmail.com</title>
5
+ <link rel='self' type='application/atom+xml' href='https://www.google.com/analytics/feeds/accounts/default'/>
6
+ <author>
7
+ <name>Google Analytics</name>
8
+ </author>
9
+ <generator version='1.0'>Google Analytics</generator>
10
+ <openSearch:totalResults>9</openSearch:totalResults>
11
+ <openSearch:startIndex>1</openSearch:startIndex>
12
+ <openSearch:itemsPerPage>9</openSearch:itemsPerPage>
13
+ <dxp:segment id='gaid::-1' name='All Visits'>
14
+ <dxp:definition> </dxp:definition>
15
+ </dxp:segment>
16
+ <dxp:segment id='gaid::-2' name='New Visitors'>
17
+ <dxp:definition>ga:visitorType==New Visitor</dxp:definition>
18
+ </dxp:segment>
19
+ <dxp:segment id='gaid::-3' name='Returning Visitors'>
20
+ <dxp:definition>ga:visitorType==Returning Visitor</dxp:definition>
21
+ </dxp:segment>
22
+ <dxp:segment id='gaid::-4' name='Paid Search Traffic'>
23
+ <dxp:definition>ga:medium==cpa,ga:medium==cpc,ga:medium==cpm,ga:medium==cpp,ga:medium==cpv,ga:medium==ppc</dxp:definition>
24
+ </dxp:segment>
25
+ <dxp:segment id='gaid::-5' name='Non-paid Search Traffic'>
26
+ <dxp:definition>ga:medium==organic</dxp:definition>
27
+ </dxp:segment>
28
+ <dxp:segment id='gaid::-6' name='Search Traffic'>
29
+ <dxp:definition>ga:medium==cpa,ga:medium==cpc,ga:medium==cpm,ga:medium==cpp,ga:medium==cpv,ga:medium==organic,ga:medium==ppc</dxp:definition>
30
+ </dxp:segment>
31
+ <dxp:segment id='gaid::-7' name='Direct Traffic'>
32
+ <dxp:definition>ga:medium==(none)</dxp:definition>
33
+ </dxp:segment>
34
+ <dxp:segment id='gaid::-8' name='Referral Traffic'>
35
+ <dxp:definition>ga:medium==referral</dxp:definition>
36
+ </dxp:segment>
37
+ <dxp:segment id='gaid::-9' name='Visits with Conversions'>
38
+ <dxp:definition>ga:goalCompletionsAll&gt;0</dxp:definition>
39
+ </dxp:segment>
40
+ <dxp:segment id='gaid::-10' name='Visits with Transactions'>
41
+ <dxp:definition>ga:transactions&gt;0</dxp:definition>
42
+ </dxp:segment>
43
+ <dxp:segment id='gaid::-11' name='Mobile Traffic'>
44
+ <dxp:definition>ga:isMobile==Yes</dxp:definition>
45
+ </dxp:segment>
46
+ <dxp:segment id='gaid::-12' name='Non-bounce Visits'>
47
+ <dxp:definition>ga:bounces==0</dxp:definition>
48
+ </dxp:segment>
49
+ <entry gd:etag='W/&quot;CkENQXs9fip7I2A9Wx5SE0w.&quot;' gd:kind='analytics#account'>
50
+ <id>http://www.google.com/analytics/feeds/accounts/ga:123456</id>
51
+ <updated>2010-08-08T16:38:10.566-07:00</updated>
52
+ <title>www.homedepot.com</title>
53
+ <link rel='alternate' type='text/html' href='http://www.google.com/analytics'/>
54
+ <dxp:property name='ga:accountId' value='254087'/>
55
+ <dxp:property name='ga:accountName' value='www.homechefdepot.com'/>
56
+ <dxp:property name='ga:profileId' value='123456'/>
57
+ <dxp:property name='ga:webPropertyId' value='UA-254087-1'/>
58
+ <dxp:property name='ga:currency' value='USD'/>
59
+ <dxp:property name='ga:timezone' value='America/Los_Angeles'/>
60
+ <dxp:tableId>ga:123456</dxp:tableId>
61
+ </entry>
62
+ <entry gd:etag='W/&quot;C0YESXcyfyp7I2A9Wx9SFkU.&quot;' gd:kind='analytics#account'>
63
+ <id>http://www.google.com/analytics/feeds/accounts/ga:8575980</id>
64
+ <updated>2010-12-06T16:18:28.997-08:00</updated>
65
+ <title>www.pda.org</title>
66
+ <link rel='alternate' type='text/html' href='http://www.google.com/analytics'/>
67
+ <dxp:property name='ga:accountId' value='4277553'/>
68
+ <dxp:property name='ga:accountName' value='www.pdma.org'/>
69
+ <dxp:property name='ga:profileId' value='8575980'/>
70
+ <dxp:property name='ga:webPropertyId' value='UA-4277553-1'/>
71
+ <dxp:property name='ga:currency' value='USD'/>
72
+ <dxp:property name='ga:timezone' value='America/Los_Angeles'/>
73
+ <dxp:tableId>ga:8575980</dxp:tableId>
74
+ </entry>
75
+ <entry gd:etag='W/&quot;CU4CSXo_cCp7I2A9Wx9RGU0.&quot;' gd:kind='analytics#account'>
76
+ <id>http://www.google.com/analytics/feeds/accounts/ga:25620226</id>
77
+ <updated>2010-12-20T19:59:28.448-08:00</updated>
78
+ <title>business.com</title>
79
+ <link rel='alternate' type='text/html' href='http://www.google.com/analytics'/>
80
+ <dxp:property name='ga:accountId' value='12312214'/>
81
+ <dxp:property name='ga:accountName' value='business.com'/>
82
+ <dxp:property name='ga:profileId' value='25620226'/>
83
+ <dxp:property name='ga:webPropertyId' value='UA-12312214-1'/>
84
+ <dxp:property name='ga:currency' value='USD'/>
85
+ <dxp:property name='ga:timezone' value='America/Los_Angeles'/>
86
+ <dxp:tableId>ga:25620226</dxp:tableId>
87
+ </entry>
88
+ <entry gd:etag='W/&quot;CU4CSX0yfCp7I2A9Wx9RGU0.&quot;' gd:kind='analytics#account'>
89
+ <id>http://www.google.com/analytics/feeds/accounts/ga:12123131</id>
90
+ <updated>2010-12-20T19:59:28.394-08:00</updated>
91
+ <title>blog.com</title>
92
+ <link rel='alternate' type='text/html' href='http://www.google.com/analytics'/>
93
+ <dxp:property name='ga:accountId' value='12312214'/>
94
+ <dxp:property name='ga:accountName' value='business.com'/>
95
+ <dxp:property name='ga:profileId' value='12123131'/>
96
+ <dxp:property name='ga:webPropertyId' value='UA-12345678-1'/>
97
+ <dxp:property name='ga:currency' value='USD'/>
98
+ <dxp:property name='ga:timezone' value='America/Los_Angeles'/>
99
+ <dxp:tableId>ga:12123131</dxp:tableId>
100
+ </entry>
101
+ <entry gd:etag='W/&quot;DUMNQHk_fSp7I2A9Wx5bEE4.&quot;' gd:kind='analytics#account'>
102
+ <id>http://www.google.com/analytics/feeds/accounts/ga:37685582</id>
103
+ <updated>2010-10-25T13:11:31.745-07:00</updated>
104
+ <title>The Social</title>
105
+ <link rel='alternate' type='text/html' href='http://www.google.com/analytics'/>
106
+ <dxp:property name='ga:accountId' value='12312214'/>
107
+ <dxp:property name='ga:accountName' value='business.com'/>
108
+ <dxp:property name='ga:profileId' value='37685582'/>
109
+ <dxp:property name='ga:webPropertyId' value='UA-12312214-1'/>
110
+ <dxp:property name='ga:currency' value='USD'/>
111
+ <dxp:property name='ga:timezone' value='America/Los_Angeles'/>
112
+ <dxp:tableId>ga:37685582</dxp:tableId>
113
+ </entry>
114
+ <entry gd:etag='W/&quot;DE8HR3o4eCp7I2A9Wx5UF0w.&quot;' gd:kind='analytics#account'>
115
+ <id>http://www.google.com/analytics/feeds/accounts/ga:38132423</id>
116
+ <updated>2010-10-21T20:07:16.430-07:00</updated>
117
+ <title>Skyline</title>
118
+ <link rel='alternate' type='text/html' href='http://www.google.com/analytics'/>
119
+ <dxp:property name='ga:accountId' value='12312214'/>
120
+ <dxp:property name='ga:accountName' value='business.com'/>
121
+ <dxp:property name='ga:profileId' value='38132423'/>
122
+ <dxp:property name='ga:webPropertyId' value='UA-12312214-1'/>
123
+ <dxp:property name='ga:currency' value='USD'/>
124
+ <dxp:property name='ga:timezone' value='America/Los_Angeles'/>
125
+ <dxp:tableId>ga:38132423</dxp:tableId>
126
+ </entry>
127
+ </feed>