readme.markdown
1# JSONStream
2
3streaming JSON.parse and stringify
4
5![](https://secure.travis-ci.org/dominictarr/JSONStream.png?branch=master)
6
7## install
8```npm install JSONStream```
9
10## example
11
12``` js
13
14var request = require('request')
15 , JSONStream = require('JSONStream')
16 , es = require('event-stream')
17
18request({url: 'http://isaacs.couchone.com/registry/_all_docs'})
19 .pipe(JSONStream.parse('rows.*'))
20 .pipe(es.mapSync(function (data) {
21 console.error(data)
22 return data
23 }))
24```
25
26## JSONStream.parse(path)
27
28parse stream of values that match a path
29
30``` js
31 JSONStream.parse('rows.*.doc')
32```
33
34The `..` operator is the recursive descent operator from [JSONPath](http://goessner.net/articles/JsonPath/), which will match a child at any depth (see examples below).
35
36If your keys have keys that include `.` or `*` etc, use an array instead.
37`['row', true, /^doc/]`.
38
39If you use an array, `RegExp`s, booleans, and/or functions. The `..` operator is also available in array representation, using `{recurse: true}`.
40any object that matches the path will be emitted as 'data' (and `pipe`d down stream)
41
42If `path` is empty or null, no 'data' events are emitted.
43
44If you want to have keys emitted, you can prefix your `*` operator with `$`: `obj.$*` - in this case the data passed to the stream is an object with a `key` holding the key and a `value` property holding the data.
45
46### Examples
47
48query a couchdb view:
49
50``` bash
51curl -sS localhost:5984/tests/_all_docs&include_docs=true
52```
53you will get something like this:
54
55``` js
56{"total_rows":129,"offset":0,"rows":[
57 { "id":"change1_0.6995461115147918"
58 , "key":"change1_0.6995461115147918"
59 , "value":{"rev":"1-e240bae28c7bb3667f02760f6398d508"}
60 , "doc":{
61 "_id": "change1_0.6995461115147918"
62 , "_rev": "1-e240bae28c7bb3667f02760f6398d508","hello":1}
63 },
64 { "id":"change2_0.6995461115147918"
65 , "key":"change2_0.6995461115147918"
66 , "value":{"rev":"1-13677d36b98c0c075145bb8975105153"}
67 , "doc":{
68 "_id":"change2_0.6995461115147918"
69 , "_rev":"1-13677d36b98c0c075145bb8975105153"
70 , "hello":2
71 }
72 },
73]}
74
75```
76
77we are probably most interested in the `rows.*.doc`
78
79create a `Stream` that parses the documents from the feed like this:
80
81``` js
82var stream = JSONStream.parse(['rows', true, 'doc']) //rows, ANYTHING, doc
83
84stream.on('data', function(data) {
85 console.log('received:', data);
86});
87//emits anything from _before_ the first match
88stream.on('header', function (data) {
89 console.log('header:', data) // => {"total_rows":129,"offset":0}
90})
91
92```
93awesome!
94
95In case you wanted the contents the doc emitted:
96
97``` js
98var stream = JSONStream.parse(['rows', true, 'doc', {emitKey: true}]) //rows, ANYTHING, doc, items in docs with keys
99
100stream.on('data', function(data) {
101 console.log('key:', data.key);
102 console.log('value:', data.value);
103});
104
105```
106
107You can also emit the path:
108
109``` js
110var stream = JSONStream.parse(['rows', true, 'doc', {emitPath: true}]) //rows, ANYTHING, doc, items in docs with keys
111
112stream.on('data', function(data) {
113 console.log('path:', data.path);
114 console.log('value:', data.value);
115});
116
117```
118
119### recursive patterns (..)
120
121`JSONStream.parse('docs..value')`
122(or `JSONStream.parse(['docs', {recurse: true}, 'value'])` using an array)
123will emit every `value` object that is a child, grand-child, etc. of the
124`docs` object. In this example, it will match exactly 5 times at various depth
125levels, emitting 0, 1, 2, 3 and 4 as results.
126
127```js
128{
129 "total": 5,
130 "docs": [
131 {
132 "key": {
133 "value": 0,
134 "some": "property"
135 }
136 },
137 {"value": 1},
138 {"value": 2},
139 {"blbl": [{}, {"a":0, "b":1, "value":3}, 10]},
140 {"value": 4}
141 ]
142}
143```
144
145## JSONStream.parse(pattern, map)
146
147provide a function that can be used to map or filter
148the json output. `map` is passed the value at that node of the pattern,
149if `map` return non-nullish (anything but `null` or `undefined`)
150that value will be emitted in the stream. If it returns a nullish value,
151nothing will be emitted.
152
153`JSONStream` also emits `'header'` and `'footer'` events,
154the `'header'` event contains anything in the output that was before
155the first match, and the `'footer'`, is anything after the last match.
156
157## JSONStream.stringify(open, sep, close)
158
159Create a writable stream.
160
161you may pass in custom `open`, `close`, and `seperator` strings.
162But, by default, `JSONStream.stringify()` will create an array,
163(with default options `open='[\n', sep='\n,\n', close='\n]\n'`)
164
165If you call `JSONStream.stringify(false)`
166the elements will only be seperated by a newline.
167
168If you only write one item this will be valid JSON.
169
170If you write many items,
171you can use a `RegExp` to split it into valid chunks.
172
173## JSONStream.stringifyObject(open, sep, close)
174
175Very much like `JSONStream.stringify`,
176but creates a writable stream for objects instead of arrays.
177
178Accordingly, `open='{\n', sep='\n,\n', close='\n}\n'`.
179
180When you `.write()` to the stream you must supply an array with `[ key, data ]`
181as the first argument.
182
183## unix tool
184
185query npm to see all the modules that browserify has ever depended on.
186
187``` bash
188curl https://registry.npmjs.org/browserify | JSONStream 'versions.*.dependencies'
189```
190
191## numbers
192
193numbers will be emitted as numbers.
194huge numbers that cannot be represented in memory as javascript numbers will be emitted as strings.
195cf https://github.com/creationix/jsonparse/commit/044b268f01c4b8f97fb936fc85d3bcfba179e5bb for details.
196
197## Acknowlegements
198
199this module depends on https://github.com/creationix/jsonparse
200by Tim Caswell
201and also thanks to Florent Jaby for teaching me about parsing with:
202https://github.com/Floby/node-json-streams
203
204## license
205
206Dual-licensed under the MIT License or the Apache License, version 2.0
207
208