Skip to content

Commit

Permalink
Modifying schema validation messages
Browse files Browse the repository at this point in the history
Fixes eclipse-lemminx#181

Signed-off-by: Nikolas <nikolaskomonen@gmail.com>
  • Loading branch information
NikolasKomonen committed Feb 7, 2019
1 parent 39f9420 commit 03d2b15
Show file tree
Hide file tree
Showing 7 changed files with 597 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ public class Constants {
public final static int _CSB = "]".codePointAt(0);
public final static int _ORB = "(".codePointAt(0);
public final static int _CRB = ")".codePointAt(0);
public final static int _OCB = "{".codePointAt(0);
public final static int _CCB = "}".codePointAt(0);
public final static int _CVL = "C".codePointAt(0);
public final static int _DVL = "D".codePointAt(0);
public final static int _AVL = "A".codePointAt(0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
* Multi line stream.
*
*/
class MultiLineStream {
public class MultiLineStream {

private static final Predicate<Integer> WHITESPACE_PREDICATE = ch -> {
return ch == _WSP || ch == _TAB || ch == _NWL || ch == _LFD || ch == _CAR;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
*
*/
public enum XMLSchemaErrorCode implements IXMLErrorCode {

cvc_complex_type_2_3("cvc-complex-type.2.3"), // https://wiki.xmldation.com/Support/Validator/cvc-complex-type-2-3
cvc_complex_type_2_1("cvc-complex-type.2.1"), // https://wiki.xmldation.com/Support/Validator/cvc-complex-type-2-1
cvc_complex_type_2_4_a("cvc-complex-type.2.4.a"), // https://wiki.xmldation.com/Support/Validator/cvc-complex-type-2-4-a
Expand All @@ -57,7 +57,8 @@ public enum XMLSchemaErrorCode implements IXMLErrorCode {
cvc_maxExclusive_valid("cvc-maxExclusive-valid"), // https://wiki.xmldation.com/Support/validator/cvc-maxexclusive-valid
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
cvc_minInclusive_valid("cvc-minInclusive-valid"), // https://wiki.xmldation.com/Support/validator/cvc-mininclusive-valid
TargetNamespace_2("TargetNamespace.2"); //

private final String code;

Expand Down Expand Up @@ -117,6 +118,7 @@ public static Range toLSPRange(XMLLocator location, XMLSchemaErrorCode code, Obj
case cvc_complex_type_2_4_d:
case cvc_elt_1_a:
case cvc_complex_type_4:
case TargetNamespace_2:
return XMLPositionUtility.selectStartTag(offset, document);
case cvc_complex_type_3_2_2: {
String attrName = (String) arguments[1];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public AbstractLSPErrorReporter(String source, DOMDocument xmlDocument, List<Dia
XMLMessageFormatter xmft = new XMLMessageFormatter();
super.putMessageFormatter(XMLMessageFormatter.XML_DOMAIN, xmft);
super.putMessageFormatter(XMLMessageFormatter.XMLNS_DOMAIN, xmft);
super.putMessageFormatter(XSMessageFormatter.SCHEMA_DOMAIN, new XSMessageFormatter());
super.putMessageFormatter(XSMessageFormatter.SCHEMA_DOMAIN, new LSPMessageFormatter());
}

public String reportError(XMLLocator location, String domain, String key, Object[] arguments, short severity,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package org.eclipse.lsp4xml.services.extensions.diagnostics;

/**
* ErrorArgumentScanner
*/
public class ErrorArgumentScanner {


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,255 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.eclipse.lsp4xml.services.extensions.diagnostics;

import java.util.Locale;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.xerces.util.MessageFormatter;

import org.eclipse.lsp4xml.dom.parser.MultiLineStream;
import org.eclipse.lsp4xml.extensions.contentmodel.participants.XMLSchemaErrorCode;

import static org.eclipse.lsp4xml.dom.parser.Constants.*;

/**
* SchemaMessageProvider implements an XMLMessageProvider that provides
* localizable error messages for the W3C XML Schema Language
*
* @xerces.internal
*
* @author Elena Litani, IBM
* @version $Id: XSMessageFormatter.java 813087 2009-09-09 19:35:27Z mrglavas $
*/
public class LSPMessageFormatter implements MessageFormatter {
/**
* The domain of messages concerning the XML Schema: Structures specification.
*/
public static final String SCHEMA_DOMAIN = "http://www.w3.org/TR/xml-schema-1";

// private objects to cache the locale and resource bundle
private Locale fLocale = null;
private ResourceBundle fResourceBundle = null;

/**
* Formats a message with the specified arguments using the given locale
* information.
*
* @param locale The locale of the message.
* @param key The message key.
* @param arguments The message replacement text arguments. The order of the
* arguments must match that of the placeholders in the actual
* message.
*
* @return Returns the formatted message.
*
* @throws MissingResourceException Thrown if the message with the specified key
* cannot be found.
*/
public String formatMessage(Locale locale, String key, Object[] arguments) throws MissingResourceException {

if (locale == null) {
locale = Locale.getDefault();
}
if (locale != fLocale) {
fResourceBundle = ResourceBundle.getBundle("XMLSchemaMessages", locale); // XMLSchemaMessages in
// src/main/resources
// memorize the most-recent locale
fLocale = locale;
}

String msg = fResourceBundle.getString(key);
if (arguments != null) {
try {
Object[] newArguments = reformatSchemaArguments(XMLSchemaErrorCode.get(key), arguments);
if (newArguments != null) {
arguments = newArguments;
}
msg = java.text.MessageFormat.format(msg, arguments);
} catch (Exception e) {
msg = fResourceBundle.getString("FormatFailed");
msg += " " + fResourceBundle.getString(key);
}
}

if (msg == null) {
msg = fResourceBundle.getString("BadMessageKey");
throw new MissingResourceException(msg, "XMLSchemaMessages", key);
}

return msg;
}

/**
* Modifies the schema message arguments to a cleaned down format
*
* @param code
* @param message
* @return
*/
public static Object[] reformatSchemaArguments(XMLSchemaErrorCode code, Object[] arguments) {

switch (code) {

case cvc_complex_type_2_4_a:
return cvc_2_4_a_solution(arguments);
case cvc_complex_type_2_4_b:
return cvc_2_4_b_solution(arguments);
case cvc_enumeration_valid:

case cvc_complex_type_2_3:
case cvc_complex_type_2_4_c:
case cvc_complex_type_2_4_d:
case cvc_elt_1_a:
case cvc_complex_type_4:
case cvc_complex_type_3_2_2:
case cvc_elt_3_1:
case cvc_attribute_3:
case cvc_complex_type_3_1:
case cvc_elt_4_2:
case cvc_type_3_1_1:
case cvc_complex_type_2_1:
case cvc_type_3_1_3:

case cvc_datatype_valid_1_2_1:
case cvc_maxlength_valid:
case cvc_minlength_valid:
case cvc_maxExclusive_valid:
case cvc_maxInclusive_valid:
case cvc_minExclusive_valid:
case cvc_minInclusive_valid: {
return null;
}
default:
}
return null;
}

private static String parseElementNames(boolean hasNamespace, String names) {
StringBuilder sb = new StringBuilder();

MultiLineStream stream = new MultiLineStream(names, 0);

while (stream.peekChar() != _CCB) { // }
stream.advance(1);// Consume ' ' or '{' if first item
if(hasNamespace) {
stream.advance(1); // Consume "
stream.advanceUntilAnyOfChars(_DQO, _SQO, _SIQ); // " | " | '
stream.advance(2); // Consume quotation and':'
}
sb.append("\t\"");
while (stream.peekChar() != _CCB && stream.peekChar() != _CMA) { // } | ,
sb.append(Character.toString((char) stream.peekChar()));
stream.advance(1);
}
sb.append("\"\n");
if (stream.peekChar() == _CMA) {
stream.advance(1);
}
}
return sb.toString();
}

/**
* Returns a pattern matcher looking
* for a string that matches the format of:
* "{"http://maven.apache.org/POM/4.0.0":propertiesa}"
* @param name
* @return
*/
private static Matcher getNamespaceMatcher(String name) {
Pattern namespacePattern = Pattern.compile("^\\{\"(.*)\":(.*)(\\}|,)");
return namespacePattern.matcher(name);
}

private static boolean isNamespaceDefined(String name) {
Pattern namespacePattern = Pattern.compile("^\\{\"(.*)\":");
return namespacePattern.matcher(name).matches();
}

/**
* Parses the message for cvc.2.4.a and returns reformatted arguments
*
* With Namespace
*
* arguments[0]: {"http://maven.apache.org/POM/4.0.0":propertiesa}
* arguments[1]: {"http://maven.apache.org/POM/4.0.0":groupId, "http://maven.apache.org/POM/4.0.0":version}
*
* Without Namespace
*
* arguments[0]: propertiesa
* arguments[1]: {groupId, version}
*
* @param arguments
* @return
*/
private static Object[] cvc_2_4_a_solution(Object[] arguments) {
Matcher m = getNamespaceMatcher((String) arguments[0]);
String schema = null;
String name = null;
String validNames = null;

if (m.matches()) {
name = m.group(2);
schema = "{" + m.group(1) + "}";
validNames = parseElementNames(true, (String)arguments[1]);
} else { // No namespace, so just element name
name = (String) arguments[0];
schema = "{the schema}";
validNames = parseElementNames(false, (String)arguments[1]);
}
return new Object[] { name, validNames, schema };
}

/**
* Parses the message for cvc.2.4.b and returns reformatted arguments
*
* With Namespace
*
* arguments[0]: elementName
* arguments[1]: {"http://maven.apache.org/POM/4.0.0":groupId, "http://maven.apache.org/POM/4.0.0":version}
*
* Without Namespace
*
* arguments[0]: elementName
* arguments[1]: {groupId, version}
*
* @param arguments
* @return
*/
private static Object[] cvc_2_4_b_solution(Object[] arguments) {
Matcher m = getNamespaceMatcher((String) arguments[1]);

String element = null;
String missingChildElements = null;
String schema = null;

if (isNamespaceDefined((String) arguments[1])) {
element = m.group(2);
missingChildElements = parseElementNames(true, (String)arguments[1]);
schema = "{" + m.group(1) + "}";
} else { // No namespace, so just element name
element = (String) arguments[0];
schema = "{the schema}";
missingChildElements = parseElementNames(false, (String)arguments[1]);
}
return new Object[] { element, missingChildElements , schema };
}
}
Loading

0 comments on commit 03d2b15

Please sign in to comment.