Connect the Dots

Ruby, 137 133 bytes

->s{eval"s.split($/).map(&:chars)#{".map{|x|x.join.gsub(/o +(?=o)/){|x|x.tr' ',?|}.chars}.transpose"*2}.map(&:join)*$/".sub'?|','?-'}

This is absolutely horrible. Still trying to golf.

Input as a padded rectangle, please.

Newline for "readability":

eval"s.split($/).map(&:chars)#{".map{|x|x.join.gsub(/o +(?=o)/){|x|x.tr' ',?|}
.chars}.transpose"*2}.map(&:join)*$/".sub'?|','?-'

Japt, 33 29 bytes

Uy eV="o +o"_rS'|} y eV,_rS'-

Test it online!

How it works

Uy         // Transpose rows with columns in the input.
eV="o +o"  // Set V to the regex-string "o +o", and recursively replace each match Z with:
_rS'|}     //  Z with spaces replaced with "|"s.
y          // Transpose again.
eV,        // Recursively replace matches Z of V with:
_rS'-      //  Z with spaces replaced with "-"s.

Retina, 80 bytes

T` `-`o.+o
Tm` `|`(?<=(?(1)!)^(?<-1>.)*o\D*¶(.)*) (?=(.)*¶\D*o(?<-2>.)*$(?(2)!))

Input needs to be padded.

Try it online!

Explanation

The first stage is pretty simple, it just turns all spaces into hyphens which are found between two os in the same line.

The second stage covers the |s. This is a bit trickier and requires balancing groups. The lookbehind

(?<=(?(1)!)^(?<-1>.)*o\D*¶(.)*)

checks that there's an o earlier in the same column. Remember that lookbehinds should be read from right to left. (.)* stores the horizontal position of match, \D*¶ checks skips to any character in the preceding lines, o matches literally. Then (?(1)!)^(?<-1>.)* ensures that the horizontal position of that o is the same.

The lookahead

(?=(.)*¶\D*o(?<-2>.)*$(?(2)!))

Does exactly the same thing in the opposite direction.