How to extract parts of an expression using Cases

One part of the problem has already been mentioned by @C.E. in his answer: Since Association is seen as atomic by the pattern matcher, no insertion of matched expressions happens within it.

The reason this is a problem at all is that your postproc is not actually evaluated after the matches have been identified, but before. To prevent evaluation of the right side of the replacement rule before the match has been found, you can use RuleDelayed (:>)

With[
 {syms = syms},
 Cases[exprs, # :> postproc[syms], Infinity] & /@ patts
 ]
(* {
    {<|"x1" -> 14, "x2" -> x2, "y" -> y|>},
    {<|"x1" -> x1, "x2" -> 12, "y" -> 3|>, <|"x1" -> x1, "x2" -> 2, "y" -> 8|>}
   } *)

Note the use of With to insert the value of syms into the now held right side of the rule (if syms were to be evaluated after the match is found, nothing would be inserted, since x1, x2, etc. need to be literally present in the replacement).


A possible workaround:

keys = ToString /@ syms;
postproc[x_, h_: keys] := Thread[h -> x]

Association @@@ Cases[exprs, # -> postproc[syms], Infinity] & /@ patts

{{<|"x1" -> 14, "x2" -> x2, "y" -> y|>}, {<|"x1" -> x1, "x2" -> 12,
"y" -> 3|>, <|"x1" -> x1, "x2" -> 2, "y" -> 8|>}}