diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DOMDocument.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DOMDocument.java index be499d8228..bde1008edf 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DOMDocument.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DOMDocument.java @@ -268,11 +268,11 @@ public boolean hasProlog() { } private SchemaLocation createSchemaLocation(DOMNode root, String schemaInstancePrefix) { - String value = root.getAttribute(getPrefixedName(schemaInstancePrefix, "schemaLocation")); - if (value == null) { + DOMAttr attr = root.getAttributeNode(getPrefixedName(schemaInstancePrefix, "schemaLocation")); + if (attr == null) { return null; } - return new SchemaLocation(root.getOwnerDocument().getDocumentURI(), value); + return new SchemaLocation(root.getOwnerDocument().getDocumentURI(), attr); } private NoNamespaceSchemaLocation createNoNamespaceSchemaLocation(DOMNode root, String schemaInstancePrefix) { diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/SchemaLocation.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/SchemaLocation.java index b0a3c30573..8c4b8c0b85 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/SchemaLocation.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/SchemaLocation.java @@ -27,8 +27,12 @@ public class SchemaLocation { private final Map schemaLocationValuePairs; - public SchemaLocation(String base, String value) { + private final DOMAttr attr; + + public SchemaLocation(String base, DOMAttr attr) { + this.attr = attr; this.schemaLocationValuePairs = new HashMap<>(); + String value = attr.getValue(); StringTokenizer st = new StringTokenizer(value); do { String namespaceURI = st.hasMoreTokens() ? st.nextToken() : null; @@ -66,4 +70,8 @@ public boolean usesSchema(Path rootPath, Path xsdPath) { return false; } + public DOMAttr getAttr() { + return attr; + } + } diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/contentmodel/participants/XMLSchemaErrorCode.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/contentmodel/participants/XMLSchemaErrorCode.java index a01d0a457b..2a4a13542e 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/contentmodel/participants/XMLSchemaErrorCode.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/contentmodel/participants/XMLSchemaErrorCode.java @@ -13,9 +13,16 @@ import java.util.HashMap; import java.util.Map; +import javax.xml.validation.Schema; + import org.apache.xerces.xni.XMLLocator; +import org.eclipse.lsp4j.Position; import org.eclipse.lsp4j.Range; +import org.eclipse.lsp4xml.commons.BadLocationException; import org.eclipse.lsp4xml.dom.DOMDocument; +import org.eclipse.lsp4xml.dom.DOMNode; +import org.eclipse.lsp4xml.dom.NoNamespaceSchemaLocation; +import org.eclipse.lsp4xml.dom.SchemaLocation; import org.eclipse.lsp4xml.extensions.contentmodel.participants.codeactions.cvc_attribute_3CodeAction; import org.eclipse.lsp4xml.extensions.contentmodel.participants.codeactions.cvc_complex_type_2_1CodeAction; import org.eclipse.lsp4xml.extensions.contentmodel.participants.codeactions.cvc_complex_type_2_3CodeAction; @@ -46,7 +53,7 @@ public enum XMLSchemaErrorCode implements IXMLErrorCode { cvc_datatype_valid_1_2_1("cvc-datatype-valid.1.2.1"), // https://wiki.xmldation.com/Support/Validator/cvc-datatype-valid-1-2-1 cvc_elt_1_a("cvc-elt.1.a"), // https://wiki.xmldation.com/Support/Validator/cvc-elt-1 cvc_elt_3_1("cvc-elt.3.1"), // https://wiki.xmldation.com/Support/Validator/cvc-elt-3-1 - cvc_elt_3_2_1("cvc-elt.3.2.1"), //https://wiki.xmldation.com/Support/Validator/cvc-elt-3-2-1 + cvc_elt_3_2_1("cvc-elt.3.2.1"), // https://wiki.xmldation.com/Support/Validator/cvc-elt-3-2-1 cvc_elt_4_2("cvc-elt.4.2"), // https://wiki.xmldation.com/Support/Validator/cvc-elt-4-2 cvc_type_3_1_1("cvc-type.3.1.1"), // https://wiki.xmldation.com/Support/Validator/cvc-type-3-1-1 cvc_type_3_1_2("cvc-type.3.1.2"), // https://wiki.xmldation.com/Support/Validator/cvc-type-3-1-2 @@ -59,8 +66,9 @@ public enum XMLSchemaErrorCode implements IXMLErrorCode { cvc_maxInclusive_valid("cvc-maxInclusive-valid"), // https://wiki.xmldation.com/Support/validator/cvc-maxinclusive-valid cvc_minExclusive_valid("cvc-minExclusive-valid"), // https://wiki.xmldation.com/Support/validator/cvc-minexclusive-valid cvc_minInclusive_valid("cvc-minInclusive-valid"), // https://wiki.xmldation.com/Support/validator/cvc-mininclusive-valid - TargetNamespace_2("TargetNamespace.2"), - schema_reference_4("schema_reference.4"); // + TargetNamespace_2("TargetNamespace.2"), + SchemaLocation("SchemaLocation"), + schema_reference_4("schema_reference.4"); // private final String code; @@ -104,7 +112,7 @@ public static XMLSchemaErrorCode get(String name) { * @param location * @param key * @param arguments - * @param document.ge + * @param document * @return the LSP range from the SAX error. */ public static Range toLSPRange(XMLLocator location, XMLSchemaErrorCode code, Object[] arguments, @@ -127,7 +135,7 @@ public static Range toLSPRange(XMLLocator location, XMLSchemaErrorCode code, Obj return XMLPositionUtility.selectAttributeNameFromGivenNameAt(attrName, offset, document); } case cvc_elt_3_1: { - String namespaceAntAttrName = (String) arguments[1]; // http://www.w3.org/2001/XMLSchema-instance,nil + String namespaceAntAttrName = (String) arguments[1]; // http://www.w3.org/2001/XMLSchema-instance,nil String attrName = namespaceAntAttrName; int index = namespaceAntAttrName.indexOf(","); if (index != -1) { @@ -140,6 +148,32 @@ public static Range toLSPRange(XMLLocator location, XMLSchemaErrorCode code, Obj } return XMLPositionUtility.selectAttributeFromGivenNameAt(attrName, offset, document); } + case SchemaLocation: + case schema_reference_4: { + DOMNode attrValueNode; + if(code.equals(SchemaLocation)) { + SchemaLocation schemaLocation = document.getSchemaLocation(); + attrValueNode = schemaLocation.getAttr().getNodeAttrValue(); + } + else { + NoNamespaceSchemaLocation noNamespaceSchemaLocation = document.getNoNamespaceSchemaLocation(); + attrValueNode = noNamespaceSchemaLocation.getAttr().getNodeAttrValue(); + } + + if (attrValueNode != null) { + int startOffset = attrValueNode.getStart(); + int endOffset = attrValueNode.getEnd(); + try { + Position startPosition = document.positionAt(startOffset); + Position endPosition = document.positionAt(endOffset); + return new Range(startPosition, endPosition); + + } catch (BadLocationException e) { + return null; + } + } + return null; + } case cvc_attribute_3: case cvc_complex_type_3_1: case cvc_elt_4_2: { diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/services/extensions/diagnostics/AbstractLSPErrorReporter.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/services/extensions/diagnostics/AbstractLSPErrorReporter.java index 18f1999e93..144ff13f53 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/services/extensions/diagnostics/AbstractLSPErrorReporter.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/services/extensions/diagnostics/AbstractLSPErrorReporter.java @@ -12,6 +12,7 @@ import static org.eclipse.lsp4xml.utils.XMLPositionUtility.toLSPPosition; +import java.util.HashSet; import java.util.List; import org.apache.xerces.impl.XMLErrorReporter; @@ -39,6 +40,7 @@ public abstract class AbstractLSPErrorReporter extends XMLErrorReporter { private final DOMDocument xmlDocument; private final List diagnostics; + private final HashSet diagnosticSet; private final String source; @@ -46,6 +48,7 @@ public AbstractLSPErrorReporter(String source, DOMDocument xmlDocument, List(); XMLMessageFormatter xmft = new XMLMessageFormatter(); super.putMessageFormatter(XMLMessageFormatter.XML_DOMAIN, xmft); super.putMessageFormatter(XMLMessageFormatter.XMLNS_DOMAIN, xmft); @@ -82,9 +85,14 @@ public String reportError(XMLLocator location, String domain, String key, Object if(adjustedRange == null) { return null; } + + Diagnostic d = new Diagnostic(adjustedRange, message, toLSPSeverity(severity), source, key); + if(diagnosticSet.contains(d)) { + return null; + } + diagnosticSet.add(d); // Fill diagnostic - diagnostics.add(new Diagnostic(adjustedRange, message, - toLSPSeverity(severity), source, key)); + diagnostics.add(d); if (severity == SEVERITY_FATAL_ERROR && !fContinueAfterFatalError) { XMLParseException parseException = (exception != null) ? new XMLParseException(location, message, exception) diff --git a/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/extensions/contentmodel/XMLSchemaPublishDiagnosticsTest.java b/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/extensions/contentmodel/XMLSchemaPublishDiagnosticsTest.java index 669d83588e..259587f378 100644 --- a/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/extensions/contentmodel/XMLSchemaPublishDiagnosticsTest.java +++ b/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/extensions/contentmodel/XMLSchemaPublishDiagnosticsTest.java @@ -51,13 +51,72 @@ public void schemaWithUrlWithoutCache() throws Exception { " \r\n" + // ""; XMLAssert.testPublishDiagnosticsFor(xml, fileURI, configuration, pd(fileURI, // - new Diagnostic(r(2, 52, 2, 52), + new Diagnostic(r(2, 31, 2, 51), "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"))); } + @Test + public void schemaWithUrlWithoutCacheNoDuplicateWarning() throws Exception { + // Here we test the following context: + // - XML which have xsi:noNamespaceSchemaLocation="http://invoice.xsd" + // - XMLCacheResolverExtension which is disabled + // Result of test is to have one published diagnostics with several Xerces + // errors (schema) + + Consumer configuration = ls -> { + ContentModelManager contentModelManager = ls.getComponent(ContentModelManager.class); + // Use cache on file system + contentModelManager.setUseCache(false); + }; + + String fileURI = "test.xml"; + String xml = "\r\n" + // + "\r\n" + // + " \r\n" + // + " \r\n" + // + " \r\n" + // + " \r\n" + // + ""; + XMLAssert.testPublishDiagnosticsFor(xml, fileURI, configuration, pd(fileURI, // + new Diagnostic(r(2, 31, 2, 51), + "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"))); + } + + @Test + public void schemaWithUrlInvalidPathWithNamespace() throws Exception { + // Here we test the following context: + // - XML which have xsi:noNamespaceSchemaLocation="http://invoice.xsd" + // - XMLCacheResolverExtension which is disabled + // Result of test is to have one published diagnostics with several Xerces + // errors (schema) + + Consumer configuration = ls -> { + ContentModelManager contentModelManager = ls.getComponent(ContentModelManager.class); + // Use cache on file system + contentModelManager.setUseCache(false); + }; + + String fileURI = "test.xml"; + String xml = "\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.", + DiagnosticSeverity.Warning, "xml", "SchemaLocation"), // + 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"))); + } + @Test public void schemaWithUrlWithCache() throws Exception { // Here we test the following context: