The output you're after is printed to stdout. Each xmllint will inherit the stdout from find, so the simplest approach is just to redirect the stdout of find:
find -type f -name "*.xml" -exec xmllint --noout {} \; 2>xml_not_valide.txt
However if find prints anything to stdout then it will be written to the file as well.
A single xmllint can take more than one file to check. Reduce the number of new processes by running xmllint for as many arguments as possible:
find -type f -name "*.xml" -exec xmllint --noout {} + 2>xml_not_valide.txt
If you want to redirect stderr from xmllint process(es) but not from find then you need to run an additional shell:
: >xml_not_valide.txt
find -type f -name "*.xml" -exec sh -c '
xmllint --noout "$@" 2>>xml_not_valide.txt
' find-sh {} +
Note I used >> because find -exec sh … + does not guarantee there will be only one sh. Note each redirection with > truncates the file. We want to truncate once at the very beginning, so we redirect the output of null command :; after this >> is the way to go.
If you need to know problematic files without the detailed output of xmllint, make use of its exit status. The tool will return non-zero if there are problems, zero otherwise. Use -exec … \; as a (negated) test:
find -type f -name "*.xml" ! -exec xmllint --noout {} \; -print 2>/dev/null >xml_not_valide.txt
Only if ! -exec … succeeds (e.i. if -exec … fails, i.e. if xmllint returns non-zero), find will -print. It will print to stdout. We silence what xmllint prints to stderr and keep what find prints to its stdout.
You cannot do this with -exec … +. This time you must run one xmllint per file.