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 Apr 1, 2019
1 parent 867b3ad commit f3aafd3
Show file tree
Hide file tree
Showing 7 changed files with 119 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,8 @@ public DOMElement getOwnerElement() {
}

/*
* (non-Javadoc)
*
* @see org.w3c.dom.Attr#getValue()
* Returns the attribute's value without quotes.
*/
@Override
public String getValue() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,17 +60,22 @@ public class Constants {

public static final Pattern ELEMENT_NAME_REGEX = Pattern.compile("^[_:\\w][_:\\w-.\\d]*");

public static final Pattern ATTRIBUTE_NAME_REGEX = Pattern.compile("^[^\\s\"'<>/=\\x00-\\x0F\\x7F\\x80-\\x9F]*");
public static final Pattern ATTRIBUTE_NAME_REGEX = Pattern.compile("^[^\\s\\?\"'<>/=\\x00-\\x0F\\x7F\\x80-\\x9F]*");

public static final Pattern ATTRIBUTE_VALUE_REGEX = Pattern.compile("^(\"[^\"]*\"?)|(\'[^\']*\'?)");

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 Expand Up @@ -296,7 +300,7 @@ TokenType internalScan() {
return finishToken(offset, TokenType.Whitespace);
}

if (stream.advanceIfChar(_EQS)) {
if (stream.advanceIfChar(_EQS)) { // =
state = ScannerState.BeforeAttributeValue;
return finishToken(offset, TokenType.DelimiterAssign);
}
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,18 @@ private static boolean isPreviousSiblingNodeType(DOMNode node, short nodeType) {
DOMNode previousNode = node.getPreviousSibling();
return previousNode != null && previousNode.getNodeType() == nodeType;
}

/**
* Will add all attributes, to the given builder, on a single line
*/
private static void addAttributes(DOMNode node, XMLBuilder xml) {
List<DOMAttr> attrs = node.getAttributeNodes();
if(attrs == null) {
return;
}
for (DOMAttr attr : attrs) {
xml.addAttributesOnSingleLine(attr, true);
}
xml.appendSpace();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ public XMLBuilder(XMLFormattingOptions formattingOptions, String whitespacesInde
this.xml = new StringBuilder();
}

public XMLBuilder appendSpace() {
xml.append(" ");
return this;
}

public XMLBuilder startElement(String prefix, String name, boolean close) {
xml.append("<");
if (prefix != null && !prefix.isEmpty()) {
Expand Down Expand Up @@ -113,6 +118,13 @@ public XMLBuilder addSingleAttribute(String name, String value, boolean surround
return this;
}

public XMLBuilder addAttributesOnSingleLine(DOMAttr attr, Boolean surroundWithQuotes) {
xml.append(" ");
addAttributeContents(attr.getName(), attr.hasDelimiter(), attr.getValue(), surroundWithQuotes);

return this;
}

public XMLBuilder addAttribute(String name, String value, int level) {
return addAttribute(name, value, level, false);
}
Expand Down Expand Up @@ -156,7 +168,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 @@ -16,6 +16,7 @@

import org.eclipse.lsp4xml.dom.DOMDocumentType.DocumentTypeKind;
import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test;

/**
Expand Down Expand Up @@ -292,6 +293,27 @@ public void testPI() {
assertDocument("<html><?m2e he haa?></html>", html);
}

@Ignore
@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 @@ -121,22 +121,32 @@ public void range2() throws BadLocationException {
@Test
public void testProlog() throws BadLocationException {
String content = "<?xml version= \"1.0\" encoding=\"UTF-8\" ?>" + lineSeparator();
String expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + lineSeparator();
String expected = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>" + lineSeparator();
format(content, expected);
}

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

@Test
public void testProlog3() throws BadLocationException {
String content = "<?xml version= \"1.0\" encoding=\"UTF-8\" ?><a><b>c</b></a>";
String expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + lineSeparator() + //
String expected = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>" + lineSeparator() + //
"<a>" + lineSeparator() + //
" <b>c</b>" + lineSeparator() + //
"</a>";
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>";
Expand All @@ -152,6 +162,38 @@ public void testPI() throws BadLocationException {
format(content, expected);
}

@Ignore
@Test
public void testDefinedPIWithVariables() 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);
}

@Ignore
@Test
public void testDefinedPIWithJustAttributeNames() throws BadLocationException {
String content = "<a><?xml-stylesheet href type = attName?></a>";
String expected =
"<a>" + lineSeparator() + //
" <?xml-stylesheet href type= attName ?>" + lineSeparator() + //
"</a>";
format(content, expected);
}

@Test
public void testPIWithVariables() throws BadLocationException {
String content = "<a><?xml-styleZZ href=\"my-style.css\" type= \"text/css\"?></a>";
String expected =
"<a>" + lineSeparator() + //
" <?xml-styleZZ 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 Expand Up @@ -204,7 +246,7 @@ public void testNestedAttributesNoSplit() throws BadLocationException {
@Test
public void testSplitAttributesProlog() throws BadLocationException {
String content = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
String expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + lineSeparator();
String expected = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>" + lineSeparator();
XMLFormattingOptions formattingOptions = createDefaultFormattingOptions();
formattingOptions.setSplitAttributes(true);
format(content, expected, formattingOptions);
Expand Down Expand Up @@ -1174,7 +1216,7 @@ public void testContentFormatting6() throws BadLocationException {
" </servlet>\r\n" +
"</web-app>";
String expected =
"<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\r\n" +
"<?xml version=\"1.0\" encoding=\"ISO-8859-1\" ?>\r\n" +
"<!DOCTYPE web-app PUBLIC \"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN\" \"http://java.sun.com/dtd/web-app_2_3.dtd\" [\r\n" +
" <!ELEMENT h1 %horiz.model;>\r\n" +
" <!ATTLIST h1 %all;>\r\n" +
Expand Down

0 comments on commit f3aafd3

Please sign in to comment.