diff --git a/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/extensions/contentmodel/participants/XMLSchemaErrorCode.java b/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/extensions/contentmodel/participants/XMLSchemaErrorCode.java index ebc900d46c..100ad37f98 100644 --- a/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/extensions/contentmodel/participants/XMLSchemaErrorCode.java +++ b/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/extensions/contentmodel/participants/XMLSchemaErrorCode.java @@ -24,6 +24,7 @@ import org.eclipse.lemminx.dom.DOMNode; import org.eclipse.lemminx.dom.NoNamespaceSchemaLocation; import org.eclipse.lemminx.dom.SchemaLocation; +import org.eclipse.lemminx.extensions.contentmodel.participants.codeactions.TargetNamespace_1CodeAction; import org.eclipse.lemminx.extensions.contentmodel.participants.codeactions.cvc_attribute_3CodeAction; import org.eclipse.lemminx.extensions.contentmodel.participants.codeactions.cvc_complex_type_2_1CodeAction; import org.eclipse.lemminx.extensions.contentmodel.participants.codeactions.cvc_complex_type_2_3CodeAction; @@ -74,6 +75,7 @@ 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_1("TargetNamespace.1"), // TargetNamespace_2("TargetNamespace.2"), SchemaLocation("SchemaLocation"), schema_reference_4("schema_reference.4"), // src_element_3("src-element.3"); @@ -138,7 +140,6 @@ public static Range toLSPRange(XMLLocator location, XMLSchemaErrorCode code, Obj case cvc_elt_1_a: case cvc_complex_type_4: case src_element_3: - case TargetNamespace_2: return XMLPositionUtility.selectStartTagName(offset, document); case cvc_complex_type_3_2_2: { String attrName = getString(arguments[1]); @@ -245,6 +246,10 @@ public static Range toLSPRange(XMLLocator location, XMLSchemaErrorCode code, Obj } case cvc_type_3_1_2: return XMLPositionUtility.selectStartTagName(offset, document); + case TargetNamespace_1: + return XMLPositionUtility.selectRootAttributeValue("xmlns", document); + case TargetNamespace_2: + return XMLPositionUtility.selectRootStartTag(document); default: } return null; @@ -260,5 +265,6 @@ public static void registerCodeActionParticipants(Map codeActions, + SharedSettings sharedSettings, IComponentProvider componentProvider) { + + Matcher namespaceMatcher = NAMESPACE_EXTRACTOR.matcher(diagnostic.getMessage()); + if (namespaceMatcher.find()){ + String correctNamespace = namespaceMatcher.group(1); + String quote = "\""; + if (sharedSettings.getFormattingSettings().getEnforceQuoteStyle() == EnforceQuoteStyle.preferred) { + quote = sharedSettings.getPreferences().getQuotationAsString(); + } + // @formatter:off + CodeAction replaceNamespace = CodeActionFactory.replace( + "Replace with '" + correctNamespace + "'", + diagnostic.getRange(), + quote + correctNamespace + quote, + document.getTextDocument(), diagnostic); + // @formatter:on + codeActions.add(replaceNamespace); + } + } + +} diff --git a/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/utils/XMLPositionUtility.java b/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/utils/XMLPositionUtility.java index 5f1749faf7..e5c354b267 100644 --- a/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/utils/XMLPositionUtility.java +++ b/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/utils/XMLPositionUtility.java @@ -325,6 +325,21 @@ public static Range selectRootStartTag(DOMDocument document) { return selectStartTagName(root); } + public static Range selectRootAttributeValue(String attrName, DOMDocument document) { + DOMNode root = document.getDocumentElement(); + if (root == null) { + root = document.getChild(0); + } + if (root == null) { + return null; + } + DOMAttr attr = root.getAttributeNode(attrName); + if (attr == null) { + return null; + } + return selectAttributeValue(attr); + } + public static Range selectStartTagName(int offset, DOMDocument document) { DOMNode element = document.findNodeAt(offset); if (element != null) { 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 e6d811ad1b..282f3b766f 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 @@ -577,6 +577,28 @@ public void cvc_complex_type_2_2_withText() throws Exception { testDiagnosticsFor(xml, diagnosticBob, diagnostic_cvc_2_2); } + @Test + public void testTargetNamespace_1Normal() throws Exception { + String xml = "\n" + // + "\n" + // + "Io"; + testDiagnosticsFor(xml, + d(2, 23, 2, 31, XMLSchemaErrorCode.TargetNamespace_1, "TargetNamespace.1: Expecting namespace 'BAD_NS', but the target namespace of the schema document is 'http://two-letter-name'."), + d(2, 1, 2, 16, XMLSchemaErrorCode.cvc_elt_1_a, "cvc-elt.1.a: Cannot find the declaration of element 'two-letter-name'.") + ); + } + + @Test + public void testTargetNamespace_1ShortNS() throws Exception { + String xml = "\n" + // + "\n" + // + "Io"; + testDiagnosticsFor(xml, + d(2, 23, 2, 26, XMLSchemaErrorCode.TargetNamespace_1, "TargetNamespace.1: Expecting namespace '_', but the target namespace of the schema document is 'http://two-letter-name'."), + d(2, 1, 2, 16, XMLSchemaErrorCode.cvc_elt_1_a, "cvc-elt.1.a: Cannot find the declaration of element 'two-letter-name'.") + ); + } + 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/XMLSyntaxDiagnosticsTest.java b/org.eclipse.lemminx/src/test/java/org/eclipse/lemminx/extensions/contentmodel/XMLSyntaxDiagnosticsTest.java index f2932f912f..0db6fc2dda 100644 --- a/org.eclipse.lemminx/src/test/java/org/eclipse/lemminx/extensions/contentmodel/XMLSyntaxDiagnosticsTest.java +++ b/org.eclipse.lemminx/src/test/java/org/eclipse/lemminx/extensions/contentmodel/XMLSyntaxDiagnosticsTest.java @@ -19,6 +19,7 @@ import static org.eclipse.lemminx.XMLAssert.testDiagnosticsFor; import org.eclipse.lemminx.XMLAssert; +import org.eclipse.lemminx.extensions.contentmodel.participants.XMLSchemaErrorCode; import org.eclipse.lemminx.extensions.contentmodel.participants.XMLSyntaxErrorCode; import org.eclipse.lemminx.settings.EnforceQuoteStyle; import org.eclipse.lemminx.settings.QuoteStyle; diff --git a/org.eclipse.lemminx/src/test/resources/xsd/two-letter-name.xsd b/org.eclipse.lemminx/src/test/resources/xsd/two-letter-name.xsd new file mode 100644 index 0000000000..83ede5f3a1 --- /dev/null +++ b/org.eclipse.lemminx/src/test/resources/xsd/two-letter-name.xsd @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file