From df229d28a518bae2de762cd2cd34fc707a51a2c8 Mon Sep 17 00:00:00 2001 From: azerr Date: Thu, 31 Dec 2020 09:39:33 +0100 Subject: [PATCH] Disable XSD validation when xsi:schemaLocation doesn't declare the namespace for the document element root. See #951 Signed-off-by: azerr --- .../diagnostics/XMLValidator.java | 25 ++++++++++++++++-- .../XMLSchemaDiagnosticsTest.java | 26 +++++++++++++++++++ .../XMLSchemaPublishDiagnosticsTest.java | 22 +++++++++------- 3 files changed, 62 insertions(+), 11 deletions(-) diff --git a/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/extensions/contentmodel/participants/diagnostics/XMLValidator.java b/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/extensions/contentmodel/participants/diagnostics/XMLValidator.java index 6bde7f2f2a..7db972ca87 100644 --- a/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/extensions/contentmodel/participants/diagnostics/XMLValidator.java +++ b/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/extensions/contentmodel/participants/diagnostics/XMLValidator.java @@ -28,6 +28,7 @@ import org.eclipse.lemminx.dom.DOMDocument; import org.eclipse.lemminx.dom.DOMDocumentType; import org.eclipse.lemminx.dom.DOMElement; +import org.eclipse.lemminx.dom.SchemaLocationHint; import org.eclipse.lemminx.extensions.contentmodel.model.ContentModelManager; import org.eclipse.lemminx.extensions.contentmodel.participants.XMLSyntaxErrorCode; import org.eclipse.lemminx.extensions.contentmodel.settings.XMLValidationSettings; @@ -82,8 +83,8 @@ public static void doDiagnostics(DOMDocument document, XMLEntityResolver entityR // Add LSP content handler to stop XML parsing if monitor is canceled. parser.setContentHandler(new LSPContentHandler(monitor)); - boolean hasSchemaGrammar = document.hasSchemaLocation() || document.hasNoNamespaceSchemaLocation() - || hasExternalSchemaGrammar(document); + boolean hasSchemaGrammar = isValidSchemaLocationForDocumentElement(document) + || document.hasNoNamespaceSchemaLocation() || hasExternalSchemaGrammar(document); boolean hasGrammar = document.hasDTD() || hasSchemaGrammar || document.hasExternalGrammar(); // If diagnostics for Schema preference is enabled if ((validationSettings == null) || validationSettings.isSchema()) { @@ -114,6 +115,26 @@ public static void doDiagnostics(DOMDocument document, XMLEntityResolver entityR } } + /** + * Returns true if the given DOM document declares a xsi:schemaLocation hint for + * the document element and false otherwise. + * + * @param document the DOM document. + * @return true if the given DOM document declares a xsi:schemaLocation hint for + * the document element and false otherwise. + */ + private static boolean isValidSchemaLocationForDocumentElement(DOMDocument document) { + if (!document.hasSchemaLocation()) { + return false; + } + String namespaceURI = document.getNamespaceURI(); + SchemaLocationHint hint = document.getSchemaLocation().getLocationHint(namespaceURI); + if (hint == null) { + return false; + } + return true; + } + private static boolean hasExternalSchemaGrammar(DOMDocument document) { if (document.getExternalGrammarFromNamespaceURI() != null) { return true; diff --git a/org.eclipse.lemminx/src/test/java/org/eclipse/lemminx/extensions/contentmodel/XMLSchemaDiagnosticsTest.java b/org.eclipse.lemminx/src/test/java/org/eclipse/lemminx/extensions/contentmodel/XMLSchemaDiagnosticsTest.java index 0872e7570b..b62e06fad4 100644 --- a/org.eclipse.lemminx/src/test/java/org/eclipse/lemminx/extensions/contentmodel/XMLSchemaDiagnosticsTest.java +++ b/org.eclipse.lemminx/src/test/java/org/eclipse/lemminx/extensions/contentmodel/XMLSchemaDiagnosticsTest.java @@ -1026,6 +1026,32 @@ public void diagnosticsWithCatalogAndXSDInclude() throws BadLocationException { Diagnostic diagnostic = d(1, 2, 1, 6, XMLSchemaErrorCode.cvc_complex_type_2_4_b); XMLAssert.testDiagnosticsFor(xml, "src/test/resources/catalogs/include/catalog-include.xml", diagnostic); } + + @Test + public void noHintSchemaLocationForRootElement() { + // Here the xsi:schemaLocation doens't declare the hint for + // http://www.eclipse.org/oomph/setup/1.0 (used in the root element) + String xml = "\r\n" + // + " \r\n" + // + " \r\n" + + // + " \r\n" + // + " \r\n" + // + " \r\n" + // + " \r\n" + // + " \r\n" + // + ""; + XMLAssert.testDiagnosticsFor(xml); + } private static void testDiagnosticsFor(String xml, Diagnostic... expected) { XMLAssert.testDiagnosticsFor(xml, "src/test/resources/catalogs/catalog.xml", expected); diff --git a/org.eclipse.lemminx/src/test/java/org/eclipse/lemminx/extensions/contentmodel/XMLSchemaPublishDiagnosticsTest.java b/org.eclipse.lemminx/src/test/java/org/eclipse/lemminx/extensions/contentmodel/XMLSchemaPublishDiagnosticsTest.java index 68a6c3d5eb..4ef5cda9ff 100644 --- a/org.eclipse.lemminx/src/test/java/org/eclipse/lemminx/extensions/contentmodel/XMLSchemaPublishDiagnosticsTest.java +++ b/org.eclipse.lemminx/src/test/java/org/eclipse/lemminx/extensions/contentmodel/XMLSchemaPublishDiagnosticsTest.java @@ -108,14 +108,16 @@ public void schemaWithUrlInvalidPathWithNamespace() throws Exception { String fileURI = "test.xml"; String xml = "\r\n" + // - "\r\n" + // - " \r\n" + // - ""; + "\r\n" + // + ""; XMLAssert.testPublishDiagnosticsFor(xml, fileURI, configuration, pd(fileURI, // - new Diagnostic(r(2, 20, 2, 40), - "SchemaLocation: schemaLocation value = 'http://invoice.xsd' must have even number of URI's.", + new Diagnostic(r(2, 20, 2, 79), + "SchemaLocation: schemaLocation value = 'http://invoice.xsd http://invoice.xsd http://invoice2.xsd' must have even number of URI's.", DiagnosticSeverity.Warning, "xml", "SchemaLocation"), // + new Diagnostic(r(2, 40, 2, 58), + "schema_reference.4: Failed to read schema document 'http://invoice.xsd', because 1) could not find the document; 2) the document could not be read; 3) the root element of the document is not .", + DiagnosticSeverity.Warning, "xml", "schema_reference.4"), // new Diagnostic(r(1, 1, 1, 8), "cvc-elt.1.a: Cannot find the declaration of element 'invoice'.", DiagnosticSeverity.Error, "xml", "cvc-elt.1.a"))); } @@ -148,8 +150,10 @@ public void schemaWithUrlWithCache() throws Exception { pd(fileURI, new Diagnostic(r(1, 1, 1, 8), "The resource 'http://invoice.xsd' is downloading.", DiagnosticSeverity.Information, "xml")), - pd(fileURI, new Diagnostic(r(1, 1, 1, 8), "Error while downloading 'http://invoice.xsd' to "+expectedLocation+".", - DiagnosticSeverity.Error, "xml"))); + pd(fileURI, + new Diagnostic(r(1, 1, 1, 8), + "Error while downloading 'http://invoice.xsd' to " + expectedLocation + ".", + DiagnosticSeverity.Error, "xml"))); } @Test @@ -187,7 +191,7 @@ public void schemaWithUrlWithCacheAndWithCatalog() throws Exception { XMLAssert.testPublishDiagnosticsFor(xml, fileURI, configuration, pd(fileURI, // new Diagnostic(r(3, 8, 3, 26), - "Content of type 'date' is expected.\n\nThe following content is not a valid type:\n '2017-11-30_INVALID'\n\nCode:", + "Content of type 'date' is expected.\n\nThe following content is not a valid type:\n '2017-11-30_INVALID'\n\nCode:", DiagnosticSeverity.Error, "xml", XMLSchemaErrorCode.cvc_datatype_valid_1_2_1.getCode()), // new Diagnostic(r(3, 8, 3, 26), "cvc-type.3.1.3: The value '2017-11-30_INVALID' of element 'date' is not valid.",