Skip to content

Commit

Permalink
Handles single quotes in targetNamespace
Browse files Browse the repository at this point in the history
It doesn't handle it well. The snippet doesn't actually make the related issue go away.

Signed-off-by: David Thompson <davthomp@redhat.com>
  • Loading branch information
datho7561 committed Jun 8, 2020
1 parent ba4c1b9 commit f2dfe80
Show file tree
Hide file tree
Showing 7 changed files with 98 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import org.apache.xerces.xni.XMLLocator;
import org.eclipse.lemminx.commons.BadLocationException;
import org.eclipse.lemminx.dom.DOMAttr;
import org.eclipse.lemminx.dom.DOMDocument;
import org.eclipse.lemminx.dom.DOMElement;
import org.eclipse.lemminx.dom.DOMNode;
Expand Down Expand Up @@ -248,7 +249,7 @@ 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);
return XMLPositionUtility.selectRootAttributeValue(DOMAttr.XMLNS_ATTR, document);
case TargetNamespace_2:
return XMLPositionUtility.selectRootStartTag(document);
default:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
*/
public class TargetNamespace_1CodeAction implements ICodeActionParticipant {

private static final Pattern NAMESPACE_EXTRACTOR = Pattern.compile("'([^']+)'\\.");
private static final Pattern NAMESPACE_EXTRACTOR = Pattern.compile("'([^\\s]+)'\\.");

@Override
public void doCodeAction(Diagnostic diagnostic, Range range, DOMDocument document, List<CodeAction> codeActions,
Expand Down Expand Up @@ -62,7 +62,10 @@ private static String extractNamespace(String diagnosticMessage) {
// schema document is 'http://two-letter-name'.
Matcher nsMatcher = NAMESPACE_EXTRACTOR.matcher(diagnosticMessage);
if (nsMatcher.find()) {
return nsMatcher.group(1);
String namespace = nsMatcher.group(1);
if (namespace != null) {
return StringUtils.escapeSingleQuotes(namespace);
}
}
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
*/
public class TargetNamespace_2CodeAction implements ICodeActionParticipant {

private static final Pattern NAMESPACE_EXTRACTOR = Pattern.compile("'([^']+)'\\.");
private static final Pattern NAMESPACE_EXTRACTOR = Pattern.compile("'([^\\s]+)'\\.");

@Override
public void doCodeAction(Diagnostic diagnostic, Range range, DOMDocument document, List<CodeAction> codeActions,
Expand Down Expand Up @@ -71,7 +71,10 @@ private static String extractNamespace(String diagnosticMessage) {
// target namespace of 'http://docbook.org/ns/docbook'.
Matcher nsMatcher = NAMESPACE_EXTRACTOR.matcher(diagnosticMessage);
if (nsMatcher.find()) {
return nsMatcher.group(1);
String namespace = nsMatcher.group(1);
if (namespace != null) {
return StringUtils.escapeSingleQuotes(namespace);
}
}
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -490,4 +490,33 @@ public static boolean isQuoted(String value) {
char quoteValueEnd = value.charAt(value.length() - 1);
return quoteValueEnd == quoteValueStart;
}

/**
* Takes a string and puts a '\' before each single quote
* where there isn't already a '\' before it.
*
* @param value The string to escape the single quotes in
* @return The string with all
*/
public static String escapeSingleQuotes(String value) {
if (isBlank(value)) {
return value;
}
StringBuilder builder = new StringBuilder("");
boolean escaped = value.charAt(0) == '\\';
if (value.charAt(0) == '\'') {
builder.append("\\'");
} else {
builder.append(value.charAt(0));
}
for (int i = 1 ; i < value.length(); i++) {
if (!escaped && value.charAt(i) == '\'') {
builder.append("\\'");
} else {
builder.append(value.charAt(i));
}
escaped = value.charAt(i) == '\\';
}
return builder.toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -618,6 +618,15 @@ public void testTargetNamespace_1SingleQuotes() throws Exception {
testCodeActionsFor(xml, targetNamespace, settings, ca(targetNamespace, te(2, 23, 2, 26, "'http://two-letter-name'")));
}

@Test
public void testTargetNamespace_1SingleQuotesInNamespace() throws Exception {
String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" + //
"<?xml-model href=\"src/test/resources/xsd/namespaceWithQuotes.xsd\"?>\n" + //
"<fraction xmlns=\"BAD_NS\" numerator=\"7\" denominator=\"4\" />";
Diagnostic targetNamespace = d(2, 16, 2, 24, XMLSchemaErrorCode.TargetNamespace_1, "TargetNamespace.1: Expecting namespace 'BAD_NS', but the target namespace of the schema document is 'http://f'raction'.");
testCodeActionsFor(xml, targetNamespace, ca(targetNamespace, te(2, 16, 2, 24, "\"http://f\\'raction\"")));
}

@Test
public void testTargetNamespace_2() throws Exception {
String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" + //
Expand All @@ -643,6 +652,15 @@ public void testTargetNamespace_2SingleQuotes() throws Exception {
testCodeActionsFor(xml, targetNamespace, settings, ca(targetNamespace, te(2, 16, 2, 16, " xmlns='http://two-letter-name'")));
}

@Test
public void testTargetNamespace_2SingleQuotesInNamespace() throws Exception {
String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" + //
"<?xml-model href=\"src/test/resources/xsd/namespaceWithQuotes.xsd\"?>\n" + //
"<fraction numerator=\"7\" denominator=\"4\" />";
Diagnostic targetNamespace = d(2, 16, 2, 24, XMLSchemaErrorCode.TargetNamespace_2, "TargetNamespace.2: Expecting no namespace, but the schema document has a target namespace of 'http://f'raction'.");
testCodeActionsFor(xml, targetNamespace, ca(targetNamespace, te(2, 9, 2, 9, " xmlns=\"http://f\\'raction\"")));
}

private static void testDiagnosticsFor(String xml, Diagnostic... expected) {
XMLAssert.testDiagnosticsFor(xml, "src/test/resources/catalogs/catalog.xml", expected);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,28 @@ public void testGetString() {
assertEquals(regularText, StringUtils.getString(regularText));
}

@Test
public void testEscapeSingleQuotesBlankString() {
assertEquals("", StringUtils.escapeSingleQuotes(""));
assertEquals(null, StringUtils.escapeSingleQuotes(null));
}

@Test
public void testEscapeSingleQuotesShortStringsa() {
assertEquals("\\'", StringUtils.escapeSingleQuotes("\\'"));
assertEquals("\\'", StringUtils.escapeSingleQuotes("'"));
}

@Test
public void testEscapeSingleQuotesComplexStrings() {
assertEquals("a\\'", StringUtils.escapeSingleQuotes("a'"));
assertEquals("a\\'", StringUtils.escapeSingleQuotes("a\\'"));
assertEquals("aaa", StringUtils.escapeSingleQuotes("aaa"));
assertEquals("a\\'\\'\\'\\'", StringUtils.escapeSingleQuotes("a'\\'''"));
assertEquals("\\\\", StringUtils.escapeSingleQuotes("\\\\"));
assertEquals("\\'a\\'a", StringUtils.escapeSingleQuotes("'a'a"));
}

private static void assertTrimNewLines(String valueToTrim, String expected) {
String actual = trimNewLines(valueToTrim);
assertEquals(expected, actual);
Expand Down
17 changes: 17 additions & 0 deletions org.eclipse.lemminx/src/test/resources/xsd/namespaceWithQuotes.xsd
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://f'raction" xmlns="http://f'raction">
<xs:element name="fraction">
<xs:complexType>
<xs:attribute name="numerator">
<xs:simpleType>
<xs:restriction base="xs:integer" />
</xs:simpleType>
</xs:attribute>
<xs:attribute name="denominator">
<xs:simpleType>
<xs:restriction base="xs:positiveInteger" />
</xs:simpleType>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>

0 comments on commit f2dfe80

Please sign in to comment.