Skip to content

Commit

Permalink
Fix processing instruction with attributes in formatting
Browse files Browse the repository at this point in the history
Fixes redhat-developer/vscode-xml/115

Signed-off-by: Nikolas <[email protected]>
  • Loading branch information
NikolasKomonen committed Mar 18, 2019
1 parent 3988871 commit 7c12eed
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,16 @@ public class Constants {

public static final Pattern URL_VALUE_REGEX = Pattern.compile("^(\"|\')[^<>\"]*(\"|\')");

public static final Pattern PROLOG_NAME_OPTIONS = Pattern.compile("^(xml|xml-stylesheet)");
public static final Pattern PROLOG_NAME_OPTIONS = Pattern.compile("^(xml)[\\s<>?]?");

public static final Pattern PI_TAG_NAME = Pattern.compile("^[a-zA-Z0-9]+");

//Add comming processing instructions that are defined to have attributes as content
public static final Pattern PI_WITH_VARIABLES = Pattern.compile("^(xml-stylesheet)[\\s<>?]?");

public static final Pattern DOCTYPE_KIND_OPTIONS = Pattern.compile("^(PUBLIC|SYSTEM)([\\s<>\"'])");

public static final Pattern PI_TAG_NAME = Pattern.compile("^[a-zA-Z0-9]+");


public static final Pattern DTD_ELEMENT_CATEGORY = Pattern.compile("^(EMPTY|ANY)([\\s<>\"'])");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,11 @@ TokenType internalScan() {
state = ScannerState.WithinTag;
return finishToken(offset, TokenType.PrologName);
}
if (PI_TAG_NAME.matcher(name).matches()) { // {name} eg: m2e
if(PI_WITH_VARIABLES.matcher(name).matches()) { // name eg: xml-stylesheet
state = ScannerState.WithinTag;
return finishToken(offset, TokenType.PIName);
}
if (ATTRIBUTE_NAME_REGEX.matcher(name).matches()) { // {name} eg: m2e
state = ScannerState.WithinPI;
return finishToken(offset, TokenType.PIName);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,11 +124,8 @@ private void format(DOMNode node, int level, int end, XMLBuilder xml) {
DOMAttr singleAttribute = attributes.get(0);
xml.addSingleAttribute(singleAttribute.getName(), singleAttribute.getOriginalValue());
} else {
int attributeIndex = 0;
for (DOMAttr attr : attributes) {
String attributeName = attr.getName();
xml.addAttribute(attr, level);
attributeIndex++;
}
}
}
Expand Down Expand Up @@ -188,7 +185,13 @@ private void format(DOMNode node, int level, int end, XMLBuilder xml) {
} else if (node.isProcessingInstruction()) {
DOMProcessingInstruction processingInstruction = (DOMProcessingInstruction) node;
xml.startPrologOrPI(processingInstruction.getTarget());
xml.addContentPI(processingInstruction.getData());
if(processingInstruction.hasAttributes()) {
addAttributes(processingInstruction, xml);
}
else {
xml.addContentPI(processingInstruction.getData());
}

xml.endPrologOrPI();
if (level == 0) {
xml.linefeed();
Expand All @@ -197,19 +200,7 @@ private void format(DOMNode node, int level, int end, XMLBuilder xml) {
DOMProcessingInstruction processingInstruction = (DOMProcessingInstruction) node;
xml.startPrologOrPI(processingInstruction.getTarget());
if (node.hasAttributes()) {
// generate attributes
String[] attributes = new String[3];
attributes[0] = "version";
attributes[1] = "encoding";
attributes[2] = "standalone";

for (String name : attributes) {
String value = node.getAttribute(name);
if (value == null) {
continue;
}
xml.addSingleAttribute(name, value, true);
}
addAttributes(node, xml);
}
xml.endPrologOrPI();
xml.linefeed();
Expand Down Expand Up @@ -354,4 +345,14 @@ private static boolean isPreviousSiblingNodeType(DOMNode node, short nodeType) {
DOMNode previousNode = node.getPreviousSibling();
return previousNode != null && previousNode.getNodeType() == nodeType;
}

private static void addAttributes(DOMNode node, XMLBuilder xml) {
List<DOMAttr> attrs = node.getAttributeNodes();
if(attrs == null) {
return;
}
for (DOMAttr attr : attrs) {
xml.addSingleAttribute(attr.getName(), attr.getValue(), true);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ public XMLBuilder addAttribute(DOMAttr attr, int level, boolean surroundWithQuot
}

/**
* Builds the attribute name, '=', and value.
* Builds the attribute {name, '=', and value}.
*
* Never puts quotes around unquoted values unless indicated to by 'surroundWithQuotes'
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,26 @@ public void testPI() {
assertDocument("<html><?m2e he haa?></html>", html);
}

@Test
public void testPIXMLStyleSheet() {
DOMNode processingInstruction = createPINode("xml-stylesheet", 6, 60, true, "");
insertIntoAttributes(processingInstruction, "href", "\"my-style.css\"");
insertIntoAttributes(processingInstruction, "type", "\"text/css\"");
DOMNode html = createElement("html", 0, 60, 67, true);
html.addChild(processingInstruction);

assertDocument("<html><?xml-stylesheet href=\"my-style.css\" type=\"text/css\"?></html>", html);
}

@Test
public void testPIXMLStyleSheetMispelled() {
// This PI name is not recognized by the regex and considers the attributes as content.
DOMNode processingInstruction = createPINode("xml-stylesheetBAD", 6, 63, true, "href=\"my-style.css\" type=\"text/css\"");
DOMNode html = createElement("html", 0, 63, 70, true);
html.addChild(processingInstruction);
assertDocument("<html><?xml-stylesheetBAD href=\"my-style.css\" type=\"text/css\"?></html>", html);
}

@Test
public void testPISpaces() {
DOMNode processingInstruction = createPINode("m2e", 6, 28, true, "he haa");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
import org.eclipse.lsp4xml.dom.DOMParser;
import org.eclipse.lsp4xml.settings.XMLFormattingOptions;
import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test;

/**
Expand Down Expand Up @@ -143,6 +142,16 @@ public void testProlog3() throws BadLocationException {
format(content, expected);
}

@Test
public void testProlog4WithUnknownVariable() throws BadLocationException {
String content = "<?xml version= \"1.0\" encoding=\"UTF-8\" unknown=\"unknownValue\" ?><a><b>c</b></a>";
String expected = "<?xml version=\"1.0\" encoding=\"UTF-8\" unknown=\"unknownValue\"?>" + lineSeparator() + //
"<a>" + lineSeparator() + //
" <b>c</b>" + lineSeparator() + //
"</a>";
format(content, expected);
}

@Test
public void testPI() throws BadLocationException {
String content = "<a><?m2e asd as das das ?></a>";
Expand All @@ -152,6 +161,16 @@ public void testPI() throws BadLocationException {
format(content, expected);
}

@Test
public void testPIWithVariables() throws BadLocationException {
String content = "<a><?xml-stylesheet href=\"my-style.css\" type= \"text/css\"?></a>";
String expected =
"<a>" + lineSeparator() + //
" <?xml-stylesheet href=\"my-style.css\" type=\"text/css\"?>" + lineSeparator() + //
"</a>";
format(content, expected);
}

@Test
public void testSplitAttributesSingle() throws BadLocationException {
String content = "<a k1=\"v1\"></a>";
Expand Down

0 comments on commit 7c12eed

Please sign in to comment.