@Override
    public void doDiagnostics(DOMDocument xmlDocument, List<Diagnostic> diagnostics,
            XMLValidationSettings validationSettings, CancelChecker cancelChecker) {

        if (!VespaExtension.match(xmlDocument))
            return;

        this.validationErrorSet.clear();

        // Fills the validationErrorSet with "actual" errors, i.e. errors that still occur after 
        // preprocessing.
        preprocessAndValidateDocument(xmlDocument);

        diagnostics.removeIf(diagnostic -> !this.validationErrorSet.contains(diagnostic.getMessage().trim()));

        DiagnosticsContext context = new DiagnosticsContext(xmlDocument, diagnostics, SchemaLSCommands.instance().hasSetupWorkspace());
        traverse(xmlDocument.getDocumentElement(), context);
    }
DiagnosticsParticipant that performs validation after Vespa Preprocessing.
Due to Lemminx' implementation of the DOM and parser, it seems impossible to run 
preprocessing on a parsed DOM. This is sad because it means we cannot connect preprocessing 
errors to their locations in the document as it was prior to preprocessing.

For now the workaround is to remove existing diagnostics (from Lemminx validation) that no longer
exist after the preprocessing step. To identify equal diagnostics, string hashing of the 
error messages is used, because that is the only information left from the {@link SAXParseException}
objects after Lemminx has validated.

This strategy makes the validation "nicer" than it should. Some errors will be removed
even though they are legit due to either string mismatch or because the choice of deployment 
settings is arbitrary at the moment. This is at the benefit of not showing errors on valid services.xml.
integration/schema-language-server/lemminx-vespa/src/main/java/ai/vespa/lemminx/participants/DiagnosticsParticipant.java