// Gets the string representation of a BSON object that can be correctly written to a CSV file string csvString (const BSONElement& object) { const char* binData; // Only used with BinData type switch (object.type()) { case MinKey: return "$MinKey"; case MaxKey: return "$MaxKey"; case NumberInt: case NumberDouble: case NumberLong: case Bool: return object.toString(false); case String: case Symbol: return csvEscape(object.toString(false), true); case Object: return csvEscape(object.jsonString(Strict, false)); case Array: return csvEscape(object.jsonString(Strict, false)); case BinData: int len; binData = object.binDataClean(len); return toHex(binData, len); case jstOID: return "ObjectID(" + object.OID().toString() + ")"; // OIDs are always 24 bytes case Date: return timeToISOString(object.Date() / 1000); case Timestamp: return csvEscape(object.jsonString(Strict, false)); case RegEx: return csvEscape("/" + string(object.regex()) + "/" + string(object.regexFlags())); case Code: return csvEscape(object.toString(false)); case CodeWScope: if (string(object.codeWScopeScopeDataUnsafe()) == "") { return csvEscape(object.toString(false)); } else { return csvEscape(object.jsonString(Strict, false)); } case EOO: case Undefined: case DBRef: case jstNULL: cerr << "Invalid BSON object type for CSV output: " << object.type() << endl; return ""; } // Can never get here verify(false); return ""; }
string BSONObj::jsonString( JsonStringFormat format, int pretty, bool isArray ) const { if ( isEmpty() ) return isArray ? "[]" : "{}"; StringBuilder s; s << (isArray ? "[ " : "{ "); BSONObjIterator i(*this); BSONElement e = i.next(); if ( !e.eoo() ) while ( 1 ) { s << e.jsonString( format, !isArray, pretty?pretty+1:0 ); e = i.next(); if ( e.eoo() ) break; s << ","; if ( pretty ) { s << '\n'; for( int x = 0; x < pretty; x++ ) s << " "; } else { s << " "; } } s << (isArray ? " ]" : " }"); return s.str(); }
string BSONObj::jsonString( JsonStringFormat format, int pretty ) const { if ( isEmpty() ) return "{}"; stringstream s; s << "{ "; BSONObjIterator i(*this); BSONElement e = i.next(); if ( !e.eoo() ) while ( 1 ) { s << e.jsonString( format, true, pretty?pretty+1:0 ); e = i.next(); if ( e.eoo() ) break; s << ","; if ( pretty ) { s << '\n'; for( int x = 0; x < pretty; x++ ) s << " "; } else { s << " "; } } s << " }"; return s.str(); }
string BSONObj::jsonString( JsonStringFormat format ) const { if ( isEmpty() ) return "{}"; stringstream s; s << "{ "; BSONObjIterator i(*this); BSONElement e = i.next(); if ( !e.eoo() ) while ( 1 ) { s << e.jsonString( format ); e = i.next(); if ( e.eoo() ) break; s << ", "; } s << " }"; return s.str(); }
string BSONElement::jsonString( JsonStringFormat format, bool includeFieldNames ) const { stringstream s; if ( includeFieldNames ) s << '"' << escape( fieldName() ) << "\" : "; switch ( type() ) { case String: case Symbol: s << '"' << escape( valuestr() ) << '"'; break; case NumberInt: case NumberDouble: if ( number() >= -numeric_limits< double >::max() && number() <= numeric_limits< double >::max() ) { s.precision( 16 ); s << number(); } else { stringstream ss; ss << "Number " << number() << " cannot be represented in JSON"; string message = ss.str(); massert( message.c_str(), false ); } break; case Bool: s << ( boolean() ? "true" : "false" ); break; case jstNULL: s << "null"; break; case Object: s << embeddedObject().jsonString( format ); break; case Array: { if ( embeddedObject().isEmpty() ) { s << "[]"; break; } s << "[ "; BSONObjIterator i( embeddedObject() ); BSONElement e = i.next(); if ( !e.eoo() ) while ( 1 ) { s << e.jsonString( format, false ); e = i.next(); if ( e.eoo() ) break; s << ", "; } s << " ]"; break; } case DBRef: { OID *x = (OID *) (valuestr() + valuestrsize()); if ( format == TenGen ) s << "Dbref( "; else s << "{ \"$ns\" : "; s << '"' << valuestr() << "\", "; if ( format != TenGen ) s << "\"$id\" : "; s << '"' << *x << "\" "; if ( format == TenGen ) s << ')'; else s << '}'; break; } case jstOID: if ( format == TenGen ) s << "ObjectId( "; s << '"' << __oid() << '"'; if ( format == TenGen ) s << " )"; break; case BinData: { int len = *(int *)( value() ); BinDataType type = BinDataType( *(char *)( (int *)( value() ) + 1 ) ); s << "{ \"$binary\" : \""; char *start = ( char * )( value() ) + sizeof( int ) + 1; string temp(start, len); string base64 = string( base64_t( temp.begin() ), base64_t( temp.end() ) ); s << base64; int padding = ( 4 - ( base64.length() % 4 ) ) % 4; for ( int i = 0; i < padding; ++i ) s << '='; s << "\", \"$type\" : \"" << hex; s.width( 2 ); s.fill( '0' ); s << type << dec; s << "\" }"; break; } case Date: if ( format == Strict ) s << "{ \"$date\" : "; else s << "Date( "; s << date(); if ( format == Strict ) s << " }"; else s << " )"; break; case RegEx: if ( format == Strict ) s << "{ \"$regex\" : \""; else s << "/"; s << escape( regex() ); if ( format == Strict ) s << "\", \"$options\" : \"" << regexFlags() << "\" }"; else { s << "/"; // FIXME Worry about alpha order? for ( const char *f = regexFlags(); *f; ++f ) switch ( *f ) { case 'g': case 'i': case 'm': s << *f; default: break; } } break; default: stringstream ss; ss << "Cannot create a properly formatted JSON string with " << "element: " << toString() << " of type: " << type(); string message = ss.str(); massert( message.c_str(), false ); } return s.str(); }
string BSONElement::jsonString( JsonStringFormat format, bool includeFieldNames, int pretty ) const { BSONType t = type(); if ( t == Undefined ) return ""; stringstream s; if ( includeFieldNames ) s << '"' << escape( fieldName() ) << "\" : "; switch ( type() ) { case mongo::String: case Symbol: s << '"' << escape( string(valuestr(), valuestrsize()-1) ) << '"'; break; case NumberLong: s << _numberLong(); break; case NumberInt: case NumberDouble: if ( number() >= -numeric_limits< double >::max() && number() <= numeric_limits< double >::max() ) { s.precision( 16 ); s << number(); } else { stringstream ss; ss << "Number " << number() << " cannot be represented in JSON"; string message = ss.str(); massert( 10311 , message.c_str(), false ); } break; case mongo::Bool: s << ( boolean() ? "true" : "false" ); break; case jstNULL: s << "null"; break; case Object: s << embeddedObject().jsonString( format, pretty ); break; case mongo::Array: { if ( embeddedObject().isEmpty() ) { s << "[]"; break; } s << "[ "; BSONObjIterator i( embeddedObject() ); BSONElement e = i.next(); if ( !e.eoo() ) while ( 1 ) { if( pretty ) { s << '\n'; for( int x = 0; x < pretty; x++ ) s << " "; } s << e.jsonString( format, false, pretty?pretty+1:0 ); e = i.next(); if ( e.eoo() ) break; s << ", "; } s << " ]"; break; } case DBRef: { mongo::OID *x = (mongo::OID *) (valuestr() + valuestrsize()); if ( format == TenGen ) s << "Dbref( "; else s << "{ \"$ref\" : "; s << '"' << valuestr() << "\", "; if ( format != TenGen ) s << "\"$id\" : "; s << '"' << *x << "\" "; if ( format == TenGen ) s << ')'; else s << '}'; break; } case jstOID: if ( format == TenGen ) { s << "ObjectId( "; } else { s << "{ \"$oid\" : "; } s << '"' << __oid() << '"'; if ( format == TenGen ) { s << " )"; } else { s << " }"; } break; case BinData: { int len = *(int *)( value() ); BinDataType type = BinDataType( *(char *)( (int *)( value() ) + 1 ) ); s << "{ \"$binary\" : \""; char *start = ( char * )( value() ) + sizeof( int ) + 1; base64::encode( s , start , len ); s << "\", \"$type\" : \"" << hex; s.width( 2 ); s.fill( '0' ); s << type << dec; s << "\" }"; break; } case mongo::Date: if ( format == Strict ) s << "{ \"$date\" : "; else s << "Date( "; if( pretty ) { Date_t d = date(); if( d == 0 ) s << '0'; else s << '"' << date().toString() << '"'; } else s << date(); if ( format == Strict ) s << " }"; else s << " )"; break; case RegEx: if ( format == Strict ){ s << "{ \"$regex\" : \"" << escape( regex() ); s << "\", \"$options\" : \"" << regexFlags() << "\" }"; } else { s << "/" << escape( regex() , true ) << "/"; // FIXME Worry about alpha order? for ( const char *f = regexFlags(); *f; ++f ){ switch ( *f ) { case 'g': case 'i': case 'm': s << *f; default: break; } } } break; case CodeWScope: { BSONObj scope = codeWScopeObject(); if ( ! scope.isEmpty() ){ s << "{ \"$code\" : " << _asCode() << " , " << " \"$scope\" : " << scope.jsonString() << " }"; break; } } case Code: s << _asCode(); break; case Timestamp: s << "{ \"t\" : " << timestampTime() << " , \"i\" : " << timestampInc() << " }"; break; case MinKey: s << "{ \"$minKey\" : 1 }"; break; case MaxKey: s << "{ \"$maxKey\" : 1 }"; break; default: stringstream ss; ss << "Cannot create a properly formatted JSON string with " << "element: " << toString() << " of type: " << type(); string message = ss.str(); massert( 10312 , message.c_str(), false ); } return s.str(); }