From 2ee715942b0b6be04f952323bbb394c29fb47b41 Mon Sep 17 00:00:00 2001 From: azerr Date: Mon, 17 Jun 2019 10:32:07 -0400 Subject: [PATCH] XSD 1.1 working Fix #363 Signed-off-by: azerr --- org.eclipse.lsp4xml/pom.xml | 5 +- .../contentmodel/ContentModelPlugin.java | 17 ++--- .../model/ContentModelManager.java | 11 +++ .../ContentModelDiagnosticsParticipant.java | 14 ++-- .../LSPXMLParserConfiguration.java | 55 ++++++++++++++ .../diagnostics/XMLValidator.java | 23 +++--- .../settings/XMLValidationSettings.java | 73 ++++++++++++++++++- .../lsp4xml/extensions/xsd/XSDPlugin.java | 5 +- .../contentmodel/CMXSDElementDeclaration.java | 2 +- .../XSDDiagnosticsParticipant.java | 11 ++- .../diagnostics/XSDValidator.java | 15 +++- .../diagnostics/LSPMessageFormatter.java | 4 +- .../xsd/XSDValidationExtensionsTest.java | 32 ++++++++ 13 files changed, 223 insertions(+), 44 deletions(-) create mode 100644 org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/contentmodel/participants/diagnostics/LSPXMLParserConfiguration.java diff --git a/org.eclipse.lsp4xml/pom.xml b/org.eclipse.lsp4xml/pom.xml index fb095d0345..96b4fb64ab 100644 --- a/org.eclipse.lsp4xml/pom.xml +++ b/org.eclipse.lsp4xml/pom.xml @@ -97,10 +97,11 @@ org.eclipse.lsp4j.jsonrpc - xerces + org.exist-db.thirdparty.xerces xercesImpl 2.12.0 - + xml-schema-1.1 + xml-apis xml-apis diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/contentmodel/ContentModelPlugin.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/contentmodel/ContentModelPlugin.java index df7bb55918..e895dbd79b 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/contentmodel/ContentModelPlugin.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/contentmodel/ContentModelPlugin.java @@ -32,7 +32,7 @@ public class ContentModelPlugin implements IXMLExtension { private final IHoverParticipant hoverParticipant; - private final ContentModelDiagnosticsParticipant diagnosticsParticipant; + private ContentModelDiagnosticsParticipant diagnosticsParticipant; private final ContentModelCodeActionParticipant codeActionParticipant; @@ -40,12 +40,9 @@ public class ContentModelPlugin implements IXMLExtension { ContentModelManager contentModelManager; - private ContentModelSettings cmSettings; - public ContentModelPlugin() { completionParticipant = new ContentModelCompletionParticipant(); hoverParticipant = new ContentModelHoverParticipant(); - diagnosticsParticipant = new ContentModelDiagnosticsParticipant(this); codeActionParticipant = new ContentModelCodeActionParticipant(); documentLinkParticipant = new ContentModelDocumentLinkParticipant(); } @@ -75,10 +72,12 @@ public void doSave(ISaveContext context) { private void updateSettings(ISaveContext saveContext) { Object initializationOptionsSettings = saveContext.getSettings(); - cmSettings = ContentModelSettings.getContentModelXMLSettings(initializationOptionsSettings); + ContentModelSettings cmSettings = ContentModelSettings + .getContentModelXMLSettings(initializationOptionsSettings); if (cmSettings != null) { updateSettings(cmSettings, saveContext); } + contentModelManager.setSettings(cmSettings); } private void updateSettings(ContentModelSettings settings, ISaveContext context) { @@ -99,8 +98,7 @@ private void updateSettings(ContentModelSettings settings, ISaveContext context) } if (settings.getFileAssociations() != null) { // Update XML file associations - boolean fileAssociationsChanged = contentModelManager - .setFileAssociations(settings.getFileAssociations()); + boolean fileAssociationsChanged = contentModelManager.setFileAssociations(settings.getFileAssociations()); if (fileAssociationsChanged) { // Validate all opened XML files context.collectDocumentToValidate(d -> { @@ -119,6 +117,7 @@ private void updateSettings(ContentModelSettings settings, ISaveContext context) @Override public void start(InitializeParams params, XMLExtensionsRegistry registry) { + diagnosticsParticipant = new ContentModelDiagnosticsParticipant(registry); URIResolverExtensionManager resolverManager = registry.getComponent(URIResolverExtensionManager.class); contentModelManager = new ContentModelManager(resolverManager); registry.registerComponent(contentModelManager); @@ -140,8 +139,4 @@ public void stop(XMLExtensionsRegistry registry) { registry.unregisterCodeActionParticipant(codeActionParticipant); registry.unregisterDocumentLinkParticipant(documentLinkParticipant); } - - public ContentModelSettings getContentModelSettings() { - return cmSettings; - } } diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/contentmodel/model/ContentModelManager.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/contentmodel/model/ContentModelManager.java index af8f1bc923..f9dc53bc70 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/contentmodel/model/ContentModelManager.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/contentmodel/model/ContentModelManager.java @@ -19,6 +19,7 @@ import org.eclipse.lsp4xml.dom.DOMDocument; import org.eclipse.lsp4xml.dom.DOMElement; +import org.eclipse.lsp4xml.extensions.contentmodel.settings.ContentModelSettings; import org.eclipse.lsp4xml.extensions.contentmodel.settings.XMLFileAssociation; import org.eclipse.lsp4xml.extensions.contentmodel.uriresolver.XMLCacheResolverExtension; import org.eclipse.lsp4xml.extensions.contentmodel.uriresolver.XMLCatalogResolverExtension; @@ -42,6 +43,8 @@ public class ContentModelManager { private final XMLCatalogResolverExtension catalogResolverExtension; private final XMLFileAssociationResolverExtension fileAssociationResolver; + private ContentModelSettings settings; + public ContentModelManager(URIResolverExtensionManager resolverManager) { this.resolverManager = resolverManager; modelProviders = new ArrayList<>(); @@ -56,6 +59,14 @@ public ContentModelManager(URIResolverExtensionManager resolverManager) { setUseCache(true); } + public void setSettings(ContentModelSettings settings) { + this.settings = settings; + } + + public ContentModelSettings getSettings() { + return settings; + } + public CMElementDeclaration findCMElement(DOMElement element) throws Exception { return findCMElement(element, element.getNamespaceURI()); } diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/contentmodel/participants/diagnostics/ContentModelDiagnosticsParticipant.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/contentmodel/participants/diagnostics/ContentModelDiagnosticsParticipant.java index 8cdd01582f..75232bb2c3 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/contentmodel/participants/diagnostics/ContentModelDiagnosticsParticipant.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/contentmodel/participants/diagnostics/ContentModelDiagnosticsParticipant.java @@ -16,7 +16,8 @@ import org.eclipse.lsp4j.Diagnostic; import org.eclipse.lsp4j.jsonrpc.CancelChecker; import org.eclipse.lsp4xml.dom.DOMDocument; -import org.eclipse.lsp4xml.extensions.contentmodel.ContentModelPlugin; +import org.eclipse.lsp4xml.extensions.contentmodel.model.ContentModelManager; +import org.eclipse.lsp4xml.services.extensions.XMLExtensionsRegistry; import org.eclipse.lsp4xml.services.extensions.diagnostics.IDiagnosticsParticipant; import org.eclipse.lsp4xml.utils.DOMUtils; @@ -26,11 +27,10 @@ * */ public class ContentModelDiagnosticsParticipant implements IDiagnosticsParticipant { + private final XMLExtensionsRegistry registry; - private final ContentModelPlugin contentModelPlugin; - - public ContentModelDiagnosticsParticipant(ContentModelPlugin contentModelPlugin) { - this.contentModelPlugin = contentModelPlugin; + public ContentModelDiagnosticsParticipant(XMLExtensionsRegistry registry) { + this.registry = registry; } @Override @@ -43,8 +43,8 @@ public void doDiagnostics(DOMDocument xmlDocument, List diagnostics, // associations settings., ...) XMLEntityResolver entityResolver = xmlDocument.getResolverExtensionManager(); // Process validation - XMLValidator.doDiagnostics(xmlDocument, entityResolver, diagnostics, - contentModelPlugin.getContentModelSettings(), monitor); + ContentModelManager manager = registry.getComponent(ContentModelManager.class); + XMLValidator.doDiagnostics(xmlDocument, entityResolver, diagnostics, manager.getSettings(), monitor); } } diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/contentmodel/participants/diagnostics/LSPXMLParserConfiguration.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/contentmodel/participants/diagnostics/LSPXMLParserConfiguration.java new file mode 100644 index 0000000000..26cffec628 --- /dev/null +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/contentmodel/participants/diagnostics/LSPXMLParserConfiguration.java @@ -0,0 +1,55 @@ +/******************************************************************************* +* Copyright (c) 2019 Red Hat Inc. and others. +* All rights reserved. This program and the accompanying materials +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/epl-v20.html +* +* Contributors: +* Red Hat Inc. - initial API and implementation +*******************************************************************************/ +package org.eclipse.lsp4xml.extensions.contentmodel.participants.diagnostics; + +import org.apache.xerces.impl.Constants; +import org.apache.xerces.impl.xs.XMLSchemaValidator; +import org.apache.xerces.parsers.XIncludeAwareParserConfiguration; + +/** + * Custom Xerces configuration to configure XSD version. + * + */ +class LSPXMLParserConfiguration extends XIncludeAwareParserConfiguration { + + private static final String XML_SCHEMA_VERSION = Constants.XERCES_PROPERTY_PREFIX + + Constants.XML_SCHEMA_VERSION_PROPERTY; + + private static final String SCHEMA_VALIDATOR = Constants.XERCES_PROPERTY_PREFIX + + Constants.SCHEMA_VALIDATOR_PROPERTY; + + private final String namespaceSchemaVersion; + + public LSPXMLParserConfiguration(String namespaceSchemaVersion) { + this.namespaceSchemaVersion = namespaceSchemaVersion; + } + + @Override + protected void configurePipeline() { + super.configurePipeline(); + configureSchemaVersion(); + } + + @Override + protected void configureXML11Pipeline() { + super.configureXML11Pipeline(); + configureSchemaVersion(); + } + + private void configureSchemaVersion() { + if (namespaceSchemaVersion != null) { + XMLSchemaValidator validator = (XMLSchemaValidator) super.getProperty(SCHEMA_VALIDATOR); + if (validator != null) { + validator.setProperty(XML_SCHEMA_VERSION, namespaceSchemaVersion); + } + } + } + +} diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/contentmodel/participants/diagnostics/XMLValidator.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/contentmodel/participants/diagnostics/XMLValidator.java index f1a827f2ee..8d467cb444 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/contentmodel/participants/diagnostics/XMLValidator.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/contentmodel/participants/diagnostics/XMLValidator.java @@ -22,7 +22,6 @@ import org.apache.xerces.impl.XMLEntityManager; import org.apache.xerces.parsers.SAXParser; -import org.apache.xerces.parsers.XIncludeAwareParserConfiguration; import org.apache.xerces.xni.XNIException; import org.apache.xerces.xni.parser.XMLEntityResolver; import org.apache.xerces.xni.parser.XMLInputSource; @@ -59,15 +58,17 @@ public class XMLValidator { private static final String DTD_NOT_FOUND = "Cannot find DTD ''{0}''.\nCreate the DTD file or configure an XML catalog for this DTD."; public static void doDiagnostics(DOMDocument document, XMLEntityResolver entityResolver, - List diagnostics, ContentModelSettings contentModelSettings, CancelChecker monitor) { + List diagnostics, ContentModelSettings settings, CancelChecker monitor) { try { - // it should be better to cache XML Schema with XMLGrammarCachingConfiguration, + // It should be better to cache XML Schema with XMLGrammarCachingConfiguration, // but we cannot use // XMLGrammarCachingConfiguration because cache is done with target namespaces. // There are conflicts when // 2 XML Schemas don't define target namespaces. - XMLParserConfiguration configuration = new XIncludeAwareParserConfiguration(); // new - // XMLGrammarCachingConfiguration(); + + // Configure the XSD schema version + String namespaceSchemaVersion = XMLValidationSettings.getNamespaceSchemaVersion(settings); + XMLParserConfiguration configuration = new LSPXMLParserConfiguration(namespaceSchemaVersion); // XMLGrammarCachingConfiguration(); if (entityResolver != null) { configuration.setProperty("http://apache.org/xml/properties/internal/entity-resolver", entityResolver); //$NON-NLS-1$ @@ -89,9 +90,7 @@ public static void doDiagnostics(DOMDocument document, XMLEntityResolver entityR boolean hasGrammar = document.hasGrammar(); // If diagnostics for Schema preference is enabled - XMLValidationSettings validationSettings = contentModelSettings != null - ? contentModelSettings.getValidation() - : null; + XMLValidationSettings validationSettings = settings != null ? settings.getValidation() : null; if ((validationSettings == null) || validationSettings.isSchema()) { checkExternalSchema(document.getExternalSchemaLocation(), parser); @@ -99,7 +98,7 @@ public static void doDiagnostics(DOMDocument document, XMLEntityResolver entityR parser.setFeature("http://apache.org/xml/features/validation/schema", hasGrammar); //$NON-NLS-1$ // warn if XML document is not bound to a grammar according the settings - warnNoGrammar(document, diagnostics, contentModelSettings); + warnNoGrammar(document, diagnostics, settings); } else { hasGrammar = false; // validation for Schema was disabled } @@ -143,7 +142,7 @@ private static boolean checkExternalDTD(DOMDocument document, LSPErrorReporterFo if (docType.getKindNode() == null) { return true; } - + // When XML is bound with a DTD path which doesn't exist, Xerces throws an // IOException which breaks the validation of XML syntax instead of reporting it // (like XML Schema). Here we parse only the @@ -154,12 +153,10 @@ private static boolean checkExternalDTD(DOMDocument document, LSPErrorReporterFo // of DTD for validation) // Parse only the DOCTYPE of the DOM document - int end = document.getDoctype().getEnd(); String xml = document.getText().substring(0, end); xml += ""; try { - // Customize the entity manager to collect the error when DTD doesn't exist. XMLEntityManager entityManager = new XMLEntityManager() { @Override @@ -185,7 +182,7 @@ public String setupCurrentEntity(String name, XMLInputSource xmlInputSource, boo } }; entityManager.reset(configuration); - + SAXParser parser = new SAXParser(configuration); parser.setProperty("http://apache.org/xml/properties/internal/entity-manager", entityManager); InputSource inputSource = new InputSource(); diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/contentmodel/settings/XMLValidationSettings.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/contentmodel/settings/XMLValidationSettings.java index 345d3448fd..58f93e2a5a 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/contentmodel/settings/XMLValidationSettings.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/contentmodel/settings/XMLValidationSettings.java @@ -11,17 +11,37 @@ package org.eclipse.lsp4xml.extensions.contentmodel.settings; +import org.apache.xerces.impl.Constants; import org.eclipse.lsp4j.DiagnosticSeverity; +import org.eclipse.lsp4xml.utils.StringUtils; /** * XMLValidationSettings */ public class XMLValidationSettings { + public enum SchemaVersion { + + V10("1.0"), V11("1.1"), V10EX("1.0EX"); + + private final String version; + + private SchemaVersion(String version) { + this.version = version; + } + + public String getVersion() { + return version; + } + + } + private Boolean schema; private Boolean enabled; + private String schemaVersion; + /** * This severity preference to mark the root element of XML document which is * not bound to a XML Schema/DTD. @@ -31,7 +51,7 @@ public class XMLValidationSettings { private String noGrammar; public XMLValidationSettings() { - //set defaults + // set defaults schema = true; enabled = true; } @@ -64,6 +84,30 @@ public void setSchema(boolean schema) { this.schema = schema; } + /** + * Returns the schema version. + * + *

+ * Supported version by Xerces are 1.0, 1.1 and 1.0EX. + *

+ * + * @see https://github.com/apache/xerces2-j/blob/xml-schema-1.1-dev/src/org/apache/xerces/impl/Constants.java#L42 + * + * @return the schema version + */ + public String getSchemaVersion() { + return schemaVersion; + } + + /** + * Set the schema version + * + * @param schemaVersion the schema version + */ + public void setSchemaVersion(String schemaVersion) { + this.schemaVersion = schemaVersion; + } + public void setNoGrammar(String noGrammar) { this.noGrammar = noGrammar; } @@ -100,12 +144,35 @@ public static DiagnosticSeverity getNoGrammarSeverity(ContentModelSettings setti return defaultSeverity; } + /** + * Returns the Xerces namespace of the schema version to use and 1.0 otherwise. + * + * @param settings the settings + * @return the Xerces namespace of the schema version to use and 1.0 otherwise. + */ + public static String getNamespaceSchemaVersion(ContentModelSettings settings) { + if (settings == null || settings.getValidation() == null) { + return Constants.W3C_XML_SCHEMA10_NS_URI; + } + String schemaVersion = settings.getValidation().getSchemaVersion(); + if (StringUtils.isEmpty(schemaVersion)) { + return Constants.W3C_XML_SCHEMA10_NS_URI; + } + if (SchemaVersion.V11.getVersion().equals(schemaVersion)) { + return Constants.W3C_XML_SCHEMA11_NS_URI; + } + if (SchemaVersion.V10EX.getVersion().equals(schemaVersion)) { + return Constants.W3C_XML_SCHEMA10EX_NS_URI; + } + return Constants.W3C_XML_SCHEMA10_NS_URI; + } + public XMLValidationSettings merge(XMLValidationSettings settings) { - if(settings != null) { + if (settings != null) { this.schema = settings.schema; this.enabled = settings.enabled; } return this; } - + } \ No newline at end of file diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/xsd/XSDPlugin.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/xsd/XSDPlugin.java index 1abb7b6813..f3b0c30adb 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/xsd/XSDPlugin.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/xsd/XSDPlugin.java @@ -41,8 +41,7 @@ public class XSDPlugin implements IXMLExtension { private final IDefinitionParticipant definitionParticipant; - private final IDiagnosticsParticipant diagnosticsParticipant; - + private IDiagnosticsParticipant diagnosticsParticipant; private final IReferenceParticipant referenceParticipant; private final ICodeLensParticipant codeLensParticipant; private final IHighlightingParticipant highlightingParticipant; @@ -51,7 +50,6 @@ public class XSDPlugin implements IXMLExtension { public XSDPlugin() { completionParticipant = new XSDCompletionParticipant(); definitionParticipant = new XSDDefinitionParticipant(); - diagnosticsParticipant = new XSDDiagnosticsParticipant(); referenceParticipant = new XSDReferenceParticipant(); codeLensParticipant = new XSDCodeLensParticipant(); highlightingParticipant = new XSDHighlightingParticipant(); @@ -71,6 +69,7 @@ public void doSave(ISaveContext context) { @Override public void start(InitializeParams params, XMLExtensionsRegistry registry) { + diagnosticsParticipant = new XSDDiagnosticsParticipant(registry); // Register resolver uiResolver = new XSDURIResolverExtension(registry.getDocumentProvider()); registry.getResolverExtensionManager().registerResolver(uiResolver); diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/xsd/contentmodel/CMXSDElementDeclaration.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/xsd/contentmodel/CMXSDElementDeclaration.java index 37562dd0c0..b893ed0cd6 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/xsd/contentmodel/CMXSDElementDeclaration.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/xsd/contentmodel/CMXSDElementDeclaration.java @@ -138,7 +138,7 @@ public Collection getPossibleElements(DOMElement parentEle // Schema constraint int[] states = validator.startContentModel(); for (QName elementName : qNames) { - Object decl = validator.oneTransition(elementName, states, handler); + Object decl = validator.oneTransition(elementName, states, handler, document); if (decl == null) { return Collections.emptyList(); } diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/xsd/participants/diagnostics/XSDDiagnosticsParticipant.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/xsd/participants/diagnostics/XSDDiagnosticsParticipant.java index bf9b5ec5e1..164ca2fc10 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/xsd/participants/diagnostics/XSDDiagnosticsParticipant.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/xsd/participants/diagnostics/XSDDiagnosticsParticipant.java @@ -16,6 +16,8 @@ import org.eclipse.lsp4j.Diagnostic; import org.eclipse.lsp4j.jsonrpc.CancelChecker; import org.eclipse.lsp4xml.dom.DOMDocument; +import org.eclipse.lsp4xml.extensions.contentmodel.model.ContentModelManager; +import org.eclipse.lsp4xml.services.extensions.XMLExtensionsRegistry; import org.eclipse.lsp4xml.services.extensions.diagnostics.IDiagnosticsParticipant; import org.eclipse.lsp4xml.utils.DOMUtils; @@ -25,6 +27,12 @@ */ public class XSDDiagnosticsParticipant implements IDiagnosticsParticipant { + private final XMLExtensionsRegistry registry; + + public XSDDiagnosticsParticipant(XMLExtensionsRegistry registry) { + this.registry = registry; + } + @Override public void doDiagnostics(DOMDocument xmlDocument, List diagnostics, CancelChecker monitor) { if (!DOMUtils.isXSD(xmlDocument)) { @@ -35,7 +43,8 @@ public void doDiagnostics(DOMDocument xmlDocument, List diagnostics, // associations settings., ...) XMLEntityResolver entityResolver = xmlDocument.getResolverExtensionManager(); // Process validation - XSDValidator.doDiagnostics(xmlDocument, entityResolver, diagnostics, monitor); + ContentModelManager manager = registry.getComponent(ContentModelManager.class); + XSDValidator.doDiagnostics(xmlDocument, entityResolver, diagnostics, manager.getSettings(), monitor); } } diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/xsd/participants/diagnostics/XSDValidator.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/xsd/participants/diagnostics/XSDValidator.java index d1b797caa7..36b4338e55 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/xsd/participants/diagnostics/XSDValidator.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/xsd/participants/diagnostics/XSDValidator.java @@ -34,6 +34,8 @@ import org.eclipse.lsp4j.Diagnostic; import org.eclipse.lsp4j.jsonrpc.CancelChecker; import org.eclipse.lsp4xml.dom.DOMDocument; +import org.eclipse.lsp4xml.extensions.contentmodel.settings.ContentModelSettings; +import org.eclipse.lsp4xml.extensions.contentmodel.settings.XMLValidationSettings; /** * XSD validator utilities class. @@ -41,12 +43,15 @@ */ public class XSDValidator { + private static final String XML_SCHEMA_VERSION = Constants.XERCES_PROPERTY_PREFIX + + Constants.XML_SCHEMA_VERSION_PROPERTY; + private static final Logger LOGGER = Logger.getLogger(XSDValidator.class.getName()); private static boolean canCustomizeReporter = true; public static void doDiagnostics(DOMDocument document, XMLEntityResolver entityResolver, - List diagnostics, CancelChecker monitor) { + List diagnostics, ContentModelSettings settings, CancelChecker monitor) { try { XMLErrorReporter reporter = new LSPErrorReporterForXSD(document, diagnostics); @@ -82,6 +87,12 @@ public static void doDiagnostics(DOMDocument document, XMLEntityResolver entityR grammarPreparser.setEntityResolver(entityResolver); } + // Configure the XSD schema version + String namespaceSchemaVersion = XMLValidationSettings.getNamespaceSchemaVersion(settings); + if (namespaceSchemaVersion != null) { + grammarPreparser.setProperty(XML_SCHEMA_VERSION, namespaceSchemaVersion); + } + String content = document.getText(); String uri = document.getDocumentURI(); InputStream inputStream = new ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8)); @@ -90,6 +101,7 @@ public static void doDiagnostics(DOMDocument document, XMLEntityResolver entityR grammarPreparser.preparseGrammar(XMLGrammarDescription.XML_SCHEMA, is); } catch (IOException | CancellationException | XMLParseException exception) { // ignore error + exception.printStackTrace(); } catch (Exception e) { LOGGER.log(Level.SEVERE, "Unexpected XSDValidator error", e); } @@ -125,6 +137,7 @@ private static XMLSchemaLoader createSchemaLoader(XMLErrorReporter reporter) { SchemaDOMParser domParser = (SchemaDOMParser) g.get(handler); domParser.setProperty("http://apache.org/xml/properties/internal/error-reporter", reporter); } catch (Exception e) { + e.printStackTrace(); canCustomizeReporter = false; } } diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/services/extensions/diagnostics/LSPMessageFormatter.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/services/extensions/diagnostics/LSPMessageFormatter.java index 14eea7b156..2821a6de63 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/services/extensions/diagnostics/LSPMessageFormatter.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/services/extensions/diagnostics/LSPMessageFormatter.java @@ -150,7 +150,7 @@ private static String reformatElementNames(boolean hasNamespace, String names) { stream.advance(2); // Consume quotation and':' } sb.append(" - "); - while (stream.peekChar() != _CCB && stream.peekChar() != _CMA) { // } | , + while (stream.peekChar() != _CCB && stream.peekChar() != _CMA && !stream.eos()) { // } | , sb.append(Character.toString((char) stream.peekChar())); stream.advance(1); } @@ -176,7 +176,7 @@ private static String reformatArrayElementNames(String names) { while (!stream.eos()) { // ] stream.advance(1);// Consume ' ' or '[' if first item sb.append(" - "); - while (stream.peekChar() != _CSB && stream.peekChar() != _CMA) { // ] | , + while (stream.peekChar() != _CSB && stream.peekChar() != _CMA && !stream.eos()) { // ] | , sb.append(Character.toString((char) stream.peekChar())); stream.advance(1); } diff --git a/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/extensions/xsd/XSDValidationExtensionsTest.java b/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/extensions/xsd/XSDValidationExtensionsTest.java index 8c6040334e..627d12d7e2 100644 --- a/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/extensions/xsd/XSDValidationExtensionsTest.java +++ b/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/extensions/xsd/XSDValidationExtensionsTest.java @@ -18,6 +18,7 @@ import org.eclipse.lsp4j.Diagnostic; import org.eclipse.lsp4xml.XMLAssert; import org.eclipse.lsp4xml.commons.BadLocationException; +import org.eclipse.lsp4xml.extensions.contentmodel.participants.XMLSchemaErrorCode; import org.eclipse.lsp4xml.extensions.xsd.participants.XSDErrorCode; import org.eclipse.lsp4xml.extensions.xsd.participants.diagnostics.XSDValidator; import org.junit.Test; @@ -311,6 +312,37 @@ public void src_element_3() throws BadLocationException { testDiagnosticsFor(xml, d(1, 3, 1, 13, XSDErrorCode.src_element_3)); } + @Test + public void xsd1_1() throws BadLocationException { + // Test with XSD 1.0 -> error + String xmlWithXSD1_0 = getXMLForXSD1_1Test("1.0"); + testDiagnosticsFor(xmlWithXSD1_0, d(11, 54, 11, 65, XSDErrorCode.cos_all_limited_2)); + + // Test with XSD 1.1 -> No error + String xmlWithXSD1_1 = getXMLForXSD1_1Test("1.1"); + testDiagnosticsFor(xmlWithXSD1_1); + } + + private static String getXMLForXSD1_1Test(String minVersion) { + return "\r\n" + // + "\r\n" + // + " \r\n" + // + " \r\n" + // + " \r\n" + // <- error with XSD 1.0 but not with XSD 1.1 + " \r\n" + // + " \r\n" + // + " \r\n" + // + " \r\n" + // + " \r\n" + // + ""; + } + private static void testDiagnosticsFor(String xml, Diagnostic... expected) throws BadLocationException { XMLAssert.testDiagnosticsFor(xml, null, null, "test.xsd", expected); }