diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DOMDocumentType.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DOMDocumentType.java index 0da0608ed3..4a5789dd04 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DOMDocumentType.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DOMDocumentType.java @@ -23,24 +23,20 @@ public enum DocumentTypeKind { } // Offset values relative to start of the XML Document - int nameStart = -1; - int nameEnd = -1; - int kindStart = -1; - int kindEnd = -1; - int publicIdStart = -1; - int publicIdEnd = -1; - int systemIdStart = -1; - int systemIdEnd = -1; - Integer startInternalSubset; - Integer endInternalSubset; + Integer nameStart, nameEnd; + Integer kindStart, kindEnd; + Integer publicIdStart, publicIdEnd; + Integer systemIdStart, systemIdEnd; + Integer internalSubsetStart, internalSubsetEnd; + private String name; - private String kind; + private String kind; // SYSTEM || PUBLIC private String publicId; private String systemId; private String internalSubset; - private String content; + private String content; // || public DOMDocumentType(int start, int end, DOMDocument ownerDocument) { super(start, end, ownerDocument); @@ -63,7 +59,7 @@ void setEnd(int end) { */ @Override public String getName() { - if (name == null && this.nameStart != -1 && this.nameEnd != -1) { + if (name == null && this.nameStart != null && this.nameEnd != null) { name = getSubstring(nameStart, nameEnd); } return name; @@ -78,7 +74,7 @@ void setName(int start, int end) { * @return the DocumentTypeKind */ public String getKind() { - if (kind == null && kindStart != -1 && kindEnd != -1) { + if (kind == null && kindStart != null && kindEnd != null) { kind = getSubstring(kindStart, kindEnd); } return kind; @@ -129,8 +125,8 @@ public NamedNodeMap getEntities() { */ @Override public String getInternalSubset() { - if (internalSubset == null && startInternalSubset != null && endInternalSubset != null) { - internalSubset = getSubstring(startInternalSubset + 1, endInternalSubset); + if (internalSubset == null && internalSubsetStart != null && internalSubsetEnd != null) { + internalSubset = getSubstring(internalSubsetStart + 1, internalSubsetEnd - 1); } return internalSubset; } @@ -141,7 +137,7 @@ public String getInternalSubset() { * @return the start offset of internal subset and null otherwise. */ public Integer getStartInternalSubset() { - return startInternalSubset; + return internalSubsetStart; } /** @@ -150,7 +146,7 @@ public Integer getStartInternalSubset() { * @return the end offset of internal subset and null otherwise. */ public Integer getEndInternalSubset() { - return endInternalSubset; + return internalSubsetEnd; } /* @@ -170,7 +166,7 @@ public NamedNodeMap getNotations() { */ @Override public String getPublicId() { - if (publicId == null && publicIdStart != -1 && publicIdEnd != -1) { + if (publicId == null && publicIdStart != null && publicIdEnd != null) { publicId = cleanURL(getSubstring(publicIdStart, publicIdEnd)); } return publicId; @@ -191,7 +187,7 @@ void setPublicId(int start, int end) { */ @Override public String getSystemId() { - if (systemId == null && systemIdStart != -1 && systemIdEnd != -1) { + if (systemId == null && systemIdStart != null && systemIdEnd != null) { systemId = cleanURL(getSubstring(systemIdStart, systemIdEnd)); } return systemId; @@ -220,7 +216,11 @@ private static String cleanURL(String url) { return url.substring(start, end); } - private String getSubstring(int start, int end) { + /** + * Since offset values are relative to 'this.start' we need to + * subtract getStart() to make them relative to 'content' + */ + public String getSubstring(int start, int end) { return getContent().substring(start - getStart(), end - getStart()); } diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DOMNode.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DOMNode.java index 8b77732615..acf6adf986 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DOMNode.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DOMNode.java @@ -37,6 +37,21 @@ public abstract class DOMNode implements Node { */ public static final short DTD_ATT_LIST_NODE = 102; + /** + * The node is a DTD Entity Declaraction. + */ + public static final short DTD_ENTITY_DECL_NODE = 103; + + /** + * The node is a DTD Notation Declaraction. + */ + public static final short DTD_NOTATION_DECL = 104; + + /** + * The node is a generic DTD Decl Node. + */ + public static final short DTD_DECL_NODE = 105; + boolean closed = false; private XMLNamedNodeMap attributeNodes; @@ -119,6 +134,7 @@ public DOMNode(int start, int end, DOMDocument ownerDocument) { this.start = start; this.end = end; this.ownerDocument = ownerDocument; + this.closed = false; } public DOMDocument getOwnerDocument() { @@ -341,7 +357,7 @@ public List getChildren() { } /** - * Add node child and set child.parent to this. + * Add node child and set child.parent to {@code this} * * @param child the node child to add. */ @@ -399,6 +415,11 @@ public boolean isDoctype() { return getNodeType() == DOMNode.DOCUMENT_TYPE_NODE; } + public boolean isGenericDTDDecl() { + return getNodeType() == DOMNode.DTD_DECL_NODE; + } + + public boolean isElement() { return getNodeType() == DOMNode.ELEMENT_NODE; } @@ -427,6 +448,10 @@ public boolean isDTDEntityDecl() { return getNodeType() == Node.ENTITY_NODE; } + public boolean isDTDNotationDecl() { + return getNodeType() == DOMNode.DTD_NOTATION_DECL; + } + public int getStart() { return start; } diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DOMParser.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DOMParser.java index accda2ee88..dd11a36511 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DOMParser.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DOMParser.java @@ -52,11 +52,16 @@ public DOMDocument parse(TextDocument document, URIResolverExtensionManager reso DOMNode curr = isDTD ? new DOMDocumentType(0, text.length(), xmlDocument) : xmlDocument; if (isDTD) { xmlDocument.addChild(curr); + + // This DOMDocumentType object is hidden, and just represents the DTD file + // nothing should affect it's closed status + curr.closed = true; } DOMNode lastClosed = curr; DOMAttr attr = null; int endTagOpenOffset = -1; String pendingAttribute = null; + boolean isInitialDeclaration = true; // A declaration can have multiple internal declarations TokenType token = scanner.scan(); while (token != TokenType.EOS) { switch (token) { @@ -64,6 +69,9 @@ public DOMDocument parse(TextDocument document, URIResolverExtensionManager reso if(curr.parent != null) { curr.end = scanner.getTokenOffset(); } + if(curr.isDoctype() && curr.parent != null) { + curr = curr.parent; + } DOMElement child = xmlDocument.createElement(scanner.getTokenOffset(), scanner.getTokenEnd()); child.startTagOpenOffset = scanner.getTokenOffset(); curr.addChild(child); @@ -240,6 +248,9 @@ public DOMDocument parse(TextDocument document, URIResolverExtensionManager reso case StartCommentTag: { DOMComment comment = xmlDocument.createComment(scanner.getTokenOffset(), text.length()); + if(curr.parent != null && curr.parent.isDoctype()) { + curr.parent.addChild(comment); + } curr.addChild(comment); curr = comment; try { @@ -275,6 +286,12 @@ public DOMDocument parse(TextDocument document, URIResolverExtensionManager reso if (content.trim().length() == 0) { // if string is only whitespaces break; } + if (curr instanceof DTDDeclNode) { + curr.end = scanner.getTokenOffset() - 1; + if(!curr.isDoctype()) { + curr = curr.getParentNode(); + } + } int start = scanner.getTokenOffset(); int end = scanner.getTokenEnd(); DOMText textNode = xmlDocument.createText(start, end); @@ -325,7 +342,7 @@ public DOMDocument parse(TextDocument document, URIResolverExtensionManager reso case DTDStartInternalSubset: { DOMDocumentType doctype = (DOMDocumentType) curr; - doctype.startInternalSubset = scanner.getTokenOffset(); + doctype.internalSubsetStart = scanner.getTokenOffset(); break; } @@ -336,11 +353,12 @@ public DOMDocument parse(TextDocument document, URIResolverExtensionManager reso } DOMDocumentType doctype = (DOMDocumentType) curr; - doctype.endInternalSubset = scanner.getTokenOffset(); + doctype.internalSubsetEnd = scanner.getTokenEnd(); break; } - case DTDStartElementDecl: { + case DTDStartElement: { + //If previous 'curr' was an unclosed ENTITY, ELEMENT, or ATTLIST if (!curr.isDoctype()) { curr.end = scanner.getTokenOffset() - 1; curr = curr.getParentNode(); @@ -355,56 +373,207 @@ public DOMDocument parse(TextDocument document, URIResolverExtensionManager reso case DTDElementDeclName: { DTDElementDecl element = (DTDElementDecl) curr; - element.name = scanner.getTokenText(); + element.nameStart = scanner.getTokenOffset(); + element.nameEnd = scanner.getTokenEnd(); break; } - case DTDStartAttlistDecl: { - if (!curr.isDoctype()) { + case DTDElementCategory: { + DTDElementDecl element = (DTDElementDecl) curr; + element.categoryStart = scanner.getTokenOffset(); + element.categoryEnd = scanner.getTokenEnd(); + break; + } + + case DTDStartElementContent: { + DTDElementDecl element = (DTDElementDecl) curr; + element.contentStart = scanner.getTokenOffset(); + break; + } + + case DTDElementContent: { + DTDElementDecl element = (DTDElementDecl) curr; + element.contentEnd = scanner.getTokenEnd(); + } + + case DTDEndElementContent: { + DTDElementDecl element = (DTDElementDecl) curr; + element.contentEnd = scanner.getTokenEnd(); + break; + } + + case DTDStartAttlist: { + if (!curr.isDoctype()) { // If previous DTD Decl was unclosed curr.end = scanner.getTokenOffset() - 1; - curr =curr.getParentNode(); + curr = curr.getParentNode(); } DTDAttlistDecl child = new DTDAttlistDecl(scanner.getTokenOffset(), text.length(), (DOMDocumentType) curr); + + isInitialDeclaration = true; curr.addChild(child); curr = child; + break; } case DTDAttlistElementName: { DTDAttlistDecl attribute = (DTDAttlistDecl) curr; - attribute.elementName = scanner.getTokenText(); + attribute.elementNameStart = scanner.getTokenOffset(); + attribute.elementNameEnd = scanner.getTokenEnd(); break; } + case DTDAttlistAttributeName: { DTDAttlistDecl attribute = (DTDAttlistDecl) curr; - attribute.name = scanner.getTokenText(); + if(isInitialDeclaration == false) { + // All additional declarations are created as new DTDAttlistDecl's + DTDAttlistDecl child = new DTDAttlistDecl(-1, -1, null); // Wont use these values + attribute.addAdditionalAttDecl(child); + child.parent = attribute; + + attribute = child; + curr = child; + } + + attribute.attributeNameStart = scanner.getTokenOffset(); + attribute.attributeNameEnd = scanner.getTokenEnd(); + break; + } + + case DTDAttlistAttributeType: { + DTDAttlistDecl attribute = (DTDAttlistDecl) curr; + attribute.attributeTypeStart = scanner.getTokenOffset(); + attribute.attributeTypeEnd = scanner.getTokenEnd(); break; } + + case DTDAttlistAttributeValue: { + DTDAttlistDecl attribute = (DTDAttlistDecl) curr; + attribute.attributeValueStart = scanner.getTokenOffset(); + attribute.attributeValueEnd = scanner.getTokenEnd(); + + if(attribute.parent.isDTDAttListDecl()) { // Is not the root/main ATTLIST node + curr = attribute.parent; + } + else { + isInitialDeclaration = false; + } + break; + } + case DTDStartEntity: { + if (!curr.isDoctype()) { // If previous DTD Decl was unclosed + curr.end = scanner.getTokenOffset() - 1; + curr = curr.getParentNode(); + } DTDEntityDecl child = new DTDEntityDecl(scanner.getTokenOffset(), text.length(), (DOMDocumentType) curr); curr.addChild(child); curr = child; break; } + case DTDEntityPercent: { + DTDEntityDecl entity = (DTDEntityDecl) curr; + entity.percentStart = scanner.getTokenOffset(); + entity.percentEnd = scanner.getTokenEnd(); + break; + } + case DTDEntityName : { DTDEntityDecl entity = (DTDEntityDecl) curr; - entity.name = scanner.getTokenText(); + entity.nameStart = scanner.getTokenOffset(); + entity.nameEnd = scanner.getTokenEnd(); + break; + } + + case DTDEntityValue : { + DTDEntityDecl entity = (DTDEntityDecl) curr; + entity.valueStart = scanner.getTokenOffset(); + entity.valueEnd = scanner.getTokenEnd(); + break; + } + + case DTDEntityKindPUBLIC: + case DTDEntityKindSYSTEM: { + DTDEntityDecl entity = (DTDEntityDecl) curr; + entity.kindStart = scanner.getTokenOffset(); + entity.kindEnd = scanner.getTokenEnd(); + break; + } + + case DTDEntityPublicId: { + DTDEntityDecl entity = (DTDEntityDecl) curr; + entity.publicIdStart = scanner.getTokenOffset(); + entity.publicIdEnd = scanner.getTokenEnd(); + break; + } + + case DTDEntitySystemId: { + DTDEntityDecl entity = (DTDEntityDecl) curr; + entity.systemIdStart = scanner.getTokenOffset(); + entity.systemIdEnd = scanner.getTokenEnd(); break; } + + + case DTDStartNotation: { + if (!curr.isDoctype()) { // If previous DTD Decl was unclosed + curr.end = scanner.getTokenOffset() - 1; + curr = curr.getParentNode(); + } + DTDNotationDecl child = new DTDNotationDecl(scanner.getTokenOffset(), text.length(), (DOMDocumentType) curr); + curr.addChild(child); + curr = child; + isInitialDeclaration = true; + break; + } + + case DTDNotationName: { + DTDNotationDecl notation = (DTDNotationDecl) curr; + notation.setName(scanner.getTokenOffset(), scanner.getTokenEnd()); + break; + } + + case DTDNotationKindPUBLIC: { + DTDNotationDecl notation = (DTDNotationDecl) curr; + notation.setKind(scanner.getTokenOffset(), scanner.getTokenEnd()); + break; + } + + case DTDNotationKindSYSTEM: { + DTDNotationDecl notation = (DTDNotationDecl) curr; + notation.setKind(scanner.getTokenOffset(), scanner.getTokenEnd()); + break; + } + + case DTDNotationPublicId: { + DTDNotationDecl notation = (DTDNotationDecl) curr; + notation.setPublicId(scanner.getTokenOffset(), scanner.getTokenEnd()); + break; + } + + case DTDNotationSystemId: { + DTDNotationDecl notation = (DTDNotationDecl) curr; + notation.setSystemId(scanner.getTokenOffset(), scanner.getTokenEnd()); + break; + } + case DTDEndTag: { - if ((curr.isDTDElementDecl() || curr.isDTDAttListDecl() || curr.isDTDEntityDecl()) && curr.parent != null) { + if ((curr.isDTDElementDecl() || curr.isDTDAttListDecl() || curr.isDTDEntityDecl() || curr.isDTDNotationDecl()) && curr.parent != null) { + if(curr.isDTDNotationDecl() && curr.parent.isDoctype() == false) { + curr = curr.parent; + } curr.end = scanner.getTokenEnd(); curr.closed = true; curr = curr.parent; } break; } - + case DTDEndDoctypeTag: { ((DOMDocumentType) curr).setEnd(scanner.getTokenEnd()); curr.closed = true; @@ -412,6 +581,13 @@ public DOMDocument parse(TextDocument document, URIResolverExtensionManager reso break; } + case DTDUnrecognizedParameters: { + DTDDeclNode node = (DTDDeclNode) curr; + node.unrecognizedStart = scanner.getTokenOffset(); + node.unrecognizedEnd = scanner.getTokenEnd(); + break; + } + default: } token = scanner.scan(); diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DTDAttlistDecl.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DTDAttlistDecl.java index 6439ebaf7b..519b80fb6b 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DTDAttlistDecl.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DTDAttlistDecl.java @@ -10,54 +10,117 @@ */ package org.eclipse.lsp4xml.dom; +import java.util.ArrayList; + /** * DTD Attribute List declaration "" + * + * or + * + * + */ - private final DOMDocumentType ownerDTDDocument; + Integer elementNameStart, elementNameEnd; + Integer attributeNameStart, attributeNameEnd; + Integer attributeTypeStart, attributeTypeEnd; + Integer attributeValueStart, attributeValueEnd; - String name; String elementName; + String attributeName; + String attributeType; + String attributeValue; + + ArrayList internalChildren; - public DTDAttlistDecl(int start, int end, DOMDocumentType ownerDTDDocument) { - super(start, end, ownerDTDDocument.getOwnerDocument()); - this.ownerDTDDocument = ownerDTDDocument; + public DTDAttlistDecl(int start, int end, DOMDocumentType parentDocumentType) { + super(start, end, parentDocumentType); } - public DOMDocumentType getOwnerDocumentType() { - return ownerDTDDocument; + public DOMDocumentType getParentDocumentType() { + return parentDocumentType; } @Override public String getNodeName() { - return getName(); + return getAttributeName(); } - /** - * Returns the attribute name - * - * @return the attribute name - */ - public String getName() { - return name; - } - /** * Returns the element name * * @return the element name */ public String getElementName() { + elementName = getValueFromOffsets(parentDocumentType, elementName, elementNameStart, elementNameEnd); return elementName; } + /** + * Returns the attribute name + * + * @return the attribute name + */ + public String getAttributeName() { + attributeName = getValueFromOffsets(parentDocumentType, attributeName, attributeNameStart, attributeNameEnd); + return attributeName; + } + + public String getAttributeType() { + attributeType = getValueFromOffsets(parentDocumentType, attributeType, attributeTypeStart, attributeTypeEnd); + return attributeType; + } + + public String getAttributeValue() { + attributeValue = getValueFromOffsets(parentDocumentType, attributeValue, attributeValueStart, attributeValueEnd); + return attributeValue; + } + @Override public short getNodeType() { return DOMNode.DTD_ATT_LIST_NODE; } + /** + * Add another internal attlist declaration to the list of children. + * + * An ATTLIST decl can internally declare multiple declarations, see top of file. + * This will add another one to its list of additional declarations. + */ + void addAdditionalAttDecl(DTDAttlistDecl child) { + if(internalChildren == null) { + internalChildren = new ArrayList(); + } + internalChildren.add(child); + } + + public ArrayList getInternalChildren() { + return internalChildren; + } + + /** + * Returns true if this node's parent is the Doctype node. + * + * + * This is used because an Attlist declaration can have multiple + * attribute declarations within a tag that are each represented + * by this class. + */ + public boolean isRootAttlist() { + return this.parent.isDoctype(); + } + } diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DTDDeclNode.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DTDDeclNode.java new file mode 100644 index 0000000000..12c3103baf --- /dev/null +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DTDDeclNode.java @@ -0,0 +1,61 @@ +/******************************************************************************* + * Copyright (c) 2018 Red Hat Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Red Hat Inc. - initial API and implementation + * + *******************************************************************************/ + +package org.eclipse.lsp4xml.dom; + +/** + * DTDNode + */ +public class DTDDeclNode extends DOMNode{ + + /** + * This class is the base for all declaration nodes for DTD's. + * + * It can also be used to represent an undefined tag, meaning + * it is not any of: ELEMENT, ATTLIST, ENTITY, or NOTATION + */ + + protected final DOMDocumentType parentDocumentType; + + Integer unrecognizedStart, unrecognizedEnd; + + String unrecognized; // holds all content after parsing goes wrong in a DTD declaration (ENTITY, ATTLIST, ELEMENT). + + public DTDDeclNode(int start, int end, DOMDocumentType parentDocumentType) { + super(start, end, parentDocumentType != null ? parentDocumentType.getOwnerDocument() : null); + this.parentDocumentType = parentDocumentType; + } + + @Override + public String getNodeName() { + return null; + } + + @Override + public short getNodeType() { + return DOMNode.DTD_DECL_NODE; + } + + public String getUnrecognized() { + unrecognized = getValueFromOffsets(parentDocumentType, unrecognized, unrecognizedStart, unrecognizedEnd); + return unrecognized; + } + + public static String getValueFromOffsets(DOMDocumentType document, String value, Integer start, Integer end) { + if(value == null && start != null && end != null) { + return document.getSubstring(start, end); + } + return value; + } + + +} \ No newline at end of file diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DTDElementDecl.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DTDElementDecl.java index a97bfa3abb..7d9673288b 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DTDElementDecl.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DTDElementDecl.java @@ -16,18 +16,32 @@ * @see https://www.w3.org/TR/REC-xml/#dt-eldecl * */ -public class DTDElementDecl extends DOMNode { +public class DTDElementDecl extends DTDDeclNode { + + /** + Formats: + + + or + + + */ + + Integer nameStart, nameEnd; // + Integer categoryStart, categoryEnd; // + Integer contentStart,contentEnd; // - private final DOMDocumentType ownerDTDDocument; String name; + String category; + String content; + - public DTDElementDecl(int start, int end, DOMDocumentType ownerDTDDocument) { - super(start, end, ownerDTDDocument.getOwnerDocument()); - this.ownerDTDDocument = ownerDTDDocument; + public DTDElementDecl(int start, int end, DOMDocumentType parentDocumentType) { + super(start, end, parentDocumentType); } - public DOMDocumentType getOwnerDocumentType() { - return ownerDTDDocument; + public DOMDocumentType getParentDocumentType() { + return parentDocumentType; } @Override @@ -36,9 +50,20 @@ public String getNodeName() { } public String getName() { + name = getValueFromOffsets(parentDocumentType, name, nameStart, nameEnd); return name; } + public String getCategory() { + category = getValueFromOffsets(parentDocumentType, category, categoryStart, categoryEnd); + return category; + } + + public String getContent() { + content = getValueFromOffsets(parentDocumentType, content, contentStart, contentEnd); + return content; + } + @Override public short getNodeType() { return DOMNode.DTD_ELEMENT_DECL_NODE; diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DTDEntityDecl.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DTDEntityDecl.java index 4c39c2c293..809ce6a2ed 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DTDEntityDecl.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DTDEntityDecl.java @@ -18,12 +18,58 @@ * * @see https://www.w3.org/TR/REC-xml/#dt-entdecl */ -public class DTDEntityDecl extends DOMNode implements Entity { +public class DTDEntityDecl extends DTDDeclNode implements Entity { + + + /** + * Formats: + * + * + * + * or + * + * + * + * or + * + * + * + * or + * + * + * + * or + * + * + * + * or + * + * + */ String name; + String value; + String kind; + String publicId; + String systemId; + + Integer percentStart, percentEnd; + Integer nameStart, nameEnd; + Integer valueStart, valueEnd; + Integer kindStart, kindEnd; + Integer publicIdStart, publicIdEnd; + Integer systemIdStart, systemIdEnd; + - public DTDEntityDecl(int start, int end, DOMDocumentType documentType) { - super(start, end, documentType != null ? documentType.getOwnerDocument() : null); + public DTDEntityDecl(int start, int end, DOMDocumentType parentDocumentType) { + super(start, end, parentDocumentType); + } + + public String getPercent() { + if(percentStart != null && percentEnd != null) { + return "%"; + } + return null; } /* @@ -33,9 +79,20 @@ public DTDEntityDecl(int start, int end, DOMDocumentType documentType) { */ @Override public String getNodeName() { + name = getValueFromOffsets(parentDocumentType, name, nameStart, nameEnd); return name; } + public String getValue() { + value = getValueFromOffsets(parentDocumentType, value, valueStart, valueEnd); + return value; + } + + public String getKind() { + kind = getValueFromOffsets(parentDocumentType, kind, kindStart, kindEnd); + return kind; + } + @Override public short getNodeType() { return Node.ENTITY_NODE; @@ -68,7 +125,8 @@ public String getNotationName() { */ @Override public String getPublicId() { - throw new UnsupportedOperationException(); + publicId = getValueFromOffsets(parentDocumentType, publicId, publicIdStart, publicIdEnd); + return publicId; } /* @@ -78,7 +136,8 @@ public String getPublicId() { */ @Override public String getSystemId() { - throw new UnsupportedOperationException(); + systemId = getValueFromOffsets(parentDocumentType, systemId, systemIdStart, systemIdEnd); + return systemId; } /* diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DTDNotationDecl.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DTDNotationDecl.java new file mode 100644 index 0000000000..f8b1aaa041 --- /dev/null +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DTDNotationDecl.java @@ -0,0 +1,94 @@ +/******************************************************************************* + * Copyright (c) 2018 Red Hat Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Red Hat Inc. - initial API and implementation + * + *******************************************************************************/ + +package org.eclipse.lsp4xml.dom; + +import java.util.ArrayList; + +/** + * DTDNotationDecl + */ +public class DTDNotationDecl extends DTDDeclNode { + + /** + * Format: + * + * + * + * or + * + * + * + * or + * + * + */ + + Integer nameStart, nameEnd; + Integer kindStart, kindEnd; + Integer publicIdStart, publicIdEnd; + Integer systemIdStart, systemIdEnd; + + String name; + String kind; + String publicId; + String systemId; + + public DTDNotationDecl(int start, int end, DOMDocumentType parentDocumentType) { + super(start, end, parentDocumentType); + } + + void setName(int start, int end) { + nameStart = start; + nameEnd = end; + } + + public String getName() { + name = getValueFromOffsets(parentDocumentType, name, nameStart, nameEnd); + return name; + } + + void setKind(int start, int end) { + kindStart = start; + kindEnd = end; + } + + public String getKind() { + kind = getValueFromOffsets(parentDocumentType, kind, kindStart, kindEnd); + return kind; + } + + void setPublicId(int start, int end) { + publicIdStart = start; + publicIdEnd = end; + } + + public String getPublicId() { + publicId = getValueFromOffsets(parentDocumentType, publicId, publicIdStart, publicIdEnd); + return publicId; + } + + void setSystemId(int start, int end) { + systemIdStart = start; + systemIdEnd = end; + } + + public String getSystemId() { + systemId = getValueFromOffsets(parentDocumentType, systemId, systemIdStart, systemIdEnd); + return systemId; + } + + @Override + public short getNodeType() { + return DOMNode.DTD_NOTATION_DECL; + } +} \ No newline at end of file diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/parser/Constants.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/parser/Constants.java index 9ea6da3d6d..a223578343 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/parser/Constants.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/parser/Constants.java @@ -50,6 +50,9 @@ public class Constants { public final static int _XVL = "x".codePointAt(0); public final static int _mVL = "m".codePointAt(0); public final static int _lVL = "l".codePointAt(0); + public final static int _PCT = "%".codePointAt(0); + + public static final Pattern ENTITY_NAME_REGEX = Pattern.compile(""); public static final Pattern ELEMENT_NAME_REGEX = Pattern.compile("^[_:\\w][_:\\w-.\\d]*"); @@ -57,21 +60,23 @@ public class Constants { public static final Pattern ATTRIBUTE_VALUE_REGEX = Pattern.compile("^[^\\s\"'`=<>\\/]+"); - public static final Pattern URL_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 DOCTYPE_KIND_OPTIONS = Pattern.compile("^(PUBLIC|SYSTEM)"); + 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)"); + public static final Pattern DTD_ELEMENT_CATEGORY = Pattern.compile("^(EMPTY|ANY)([\\s<>\"'])"); + + public static final Pattern DTD_ELEMENT_CONTENT = Pattern.compile("^(\\(((\\S,)*(\\S))\\)|\\(\\))"); public static final Pattern DTD_PCDATA = Pattern.compile("^#PCDATA"); - public static final Pattern DTD_ATTLIST_ATTRIBUTE_TYPE = Pattern.compile("^(CDATA|IDREFS|IDREF|ID|NMTOKENS|NMTOKEN|ENTITY|ENTITIES|NOTATION|xml:|\\(.*\\))"); + public static final Pattern DTD_ATTLIST_ATTRIBUTE_TYPE = Pattern.compile("^(CDATA|IDREFS|IDREF|ID|NMTOKENS|NMTOKEN|ENTITIES|ENTITY|NOTATION|xml:|\\(.*\\))([\\s<>\"'])"); - public static final Pattern DTD_ATTLIST_ATTRIBUTE_VALUE = Pattern.compile("^(#REQUIRED|#IMPLIED|\".*\"|#FIXED \".*\")"); + public static final Pattern DTD_ATTLIST_ATTRIBUTE_VALUE = Pattern.compile("^(#REQUIRED|#IMPLIED|\".*\"|#FIXED \".*\")([\\s<>\"'])"); public static final Pattern DTD_ENTITY_VALUE = Pattern.compile("^\".*\""); diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/parser/MultiLineStream.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/parser/MultiLineStream.java index 56cf6e2dd3..7f5d13629e 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/parser/MultiLineStream.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/parser/MultiLineStream.java @@ -133,6 +133,22 @@ public String advanceIfRegExp(Pattern regex) { return ""; } + /** + * Advances stream on regex, but will grab the first group + * @param regex + * @return + */ + public String advanceIfRegExpGroup1(Pattern regex) { + Matcher match = getCachedMatcher(regex); + // Initialize start region where search must be started. + match.region(this.position, this.len); + if (match.find()) { + this.position = match.end(1); + return match.group(1); + } + return ""; + } + public String advanceUntilRegExp(Pattern regex) { String str = this.source.substring(this.position); /* diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/parser/ScannerState.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/parser/ScannerState.java index 1777a9a53f..ef95578b65 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/parser/ScannerState.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/parser/ScannerState.java @@ -22,10 +22,10 @@ public enum ScannerState { // DTD DTDWithinDoctype, DTDAfterDoctypeName, DTDAfterDoctypePUBLIC, DTDAfterDoctypeSYSTEM, - DTDAfterDoctypePublicId, DTDAfterDoctypeSystemId, DTDAfterInternalStartBracket, - - DTDWithinContent, DTDWithinElement, DTDWithinAttlist, DTDWithinEntity, DTDAfterElementName, DTDWithinElementContent, - DTDAfterAttlistName, DTDAfterAttlistDeclName, DTDAfterAttlistElementName, DTDAfterAttlistAttributeName, - DTDAfterAttlistAttributeType, DTDAfterEntityName, DTDAfterEntityKind, DTDWithinTag; + DTDAfterDoctypePublicId,DTDWithinContent, DTDWithinElement, DTDWithinAttlist, DTDWithinEntity, + DTDElementAfterName, DTDElementWithinContent, DTDAfterAttlistName, DTDAfterAttlistElementName, + DTDAfterAttlistAttributeName, DTDAfterAttlistAttributeType, DTDAfterEntityName, DTDUnrecognizedParameters, + DTDWithinNotation, DTDAfterNotationName, DTDAfterNotationPUBLIC, DTDAfterNotationSYSTEM, + DTDAfterNotationPublicId, DTDAfterEntityPUBLIC, DTDAfterEntitySYSTEM; } \ No newline at end of file diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/parser/TokenType.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/parser/TokenType.java index 04dda9a6b1..acabb03426 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/parser/TokenType.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/parser/TokenType.java @@ -53,26 +53,43 @@ public enum TokenType { DTDStartInternalSubset, DTDEndInternalSubset, // DTD Element declaration - DTDStartElementDecl, - DTDElementDeclName, - DTDStartElementContent, + DTDStartElement, + DTDElementDeclName, DTDElementCategory, + DTDStartElementContent, + DTDElementContent, DTDEndElementContent, // DTD AttrList declaration - DTDStartAttlistDecl, + DTDStartAttlist, DTDAttlistElementName, - DTDAttlistDeclName, DTDAttlistAttributeValue, - DTDAttlistType, + DTDAttlistAttributeType, DTDAttlistAttributeName, // DTD Entity DTDStartEntity, + DTDEntityPercent, + DTDEntityKindPUBLIC, + DTDEntityKindSYSTEM, + DTDEntityPublicId, + DTDEntitySystemId, DTDEntityName, DTDEntityValue, - DTDEntityKind, - DTDEntityURL, + + // DTD Notation + DTDStartNotation, + DTDNotationName, + DTDNotationKindPUBLIC, + DTDNotationKindSYSTEM, + DTDNotationPublicId, + DTDNotationSystemId, + //For any DTD Decl Tag that has an unrecognized parameter + DTDUnrecognizedParameters, + + //End of any DTD Decl Tag DTDEndTag; + + } diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/parser/XMLScanner.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/parser/XMLScanner.java index 33d5238f3a..fd3f563ef1 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/parser/XMLScanner.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/parser/XMLScanner.java @@ -10,43 +10,7 @@ */ package org.eclipse.lsp4xml.dom.parser; -import static org.eclipse.lsp4xml.dom.parser.Constants.ATTRIBUTE_NAME_REGEX; -import static org.eclipse.lsp4xml.dom.parser.Constants.ATTRIBUTE_VALUE_REGEX; -import static org.eclipse.lsp4xml.dom.parser.Constants.DOCTYPE_KIND_OPTIONS; -import static org.eclipse.lsp4xml.dom.parser.Constants.DTD_ELEMENT_CATEGORY; -import static org.eclipse.lsp4xml.dom.parser.Constants.ELEMENT_NAME_REGEX; -import static org.eclipse.lsp4xml.dom.parser.Constants.PI_TAG_NAME; -import static org.eclipse.lsp4xml.dom.parser.Constants.PROLOG_NAME_OPTIONS; -import static org.eclipse.lsp4xml.dom.parser.Constants.URL_VALUE_REGEX; -import static org.eclipse.lsp4xml.dom.parser.Constants._AVL; -import static org.eclipse.lsp4xml.dom.parser.Constants._CAR; -import static org.eclipse.lsp4xml.dom.parser.Constants._CSB; -import static org.eclipse.lsp4xml.dom.parser.Constants._CVL; -import static org.eclipse.lsp4xml.dom.parser.Constants._DQO; -import static org.eclipse.lsp4xml.dom.parser.Constants._DVL; -import static org.eclipse.lsp4xml.dom.parser.Constants._EQS; -import static org.eclipse.lsp4xml.dom.parser.Constants._EVL; -import static org.eclipse.lsp4xml.dom.parser.Constants._EXL; -import static org.eclipse.lsp4xml.dom.parser.Constants._FSL; -import static org.eclipse.lsp4xml.dom.parser.Constants._IVL; -import static org.eclipse.lsp4xml.dom.parser.Constants._LAN; -import static org.eclipse.lsp4xml.dom.parser.Constants._LVL; -import static org.eclipse.lsp4xml.dom.parser.Constants._MIN; -import static org.eclipse.lsp4xml.dom.parser.Constants._MVL; -import static org.eclipse.lsp4xml.dom.parser.Constants._NVL; -import static org.eclipse.lsp4xml.dom.parser.Constants._NWL; -import static org.eclipse.lsp4xml.dom.parser.Constants._ORB; -import static org.eclipse.lsp4xml.dom.parser.Constants._OSB; -import static org.eclipse.lsp4xml.dom.parser.Constants._OVL; -import static org.eclipse.lsp4xml.dom.parser.Constants._PVL; -import static org.eclipse.lsp4xml.dom.parser.Constants._QMA; -import static org.eclipse.lsp4xml.dom.parser.Constants._RAN; -import static org.eclipse.lsp4xml.dom.parser.Constants._SIQ; -import static org.eclipse.lsp4xml.dom.parser.Constants._SQO; -import static org.eclipse.lsp4xml.dom.parser.Constants._SVL; -import static org.eclipse.lsp4xml.dom.parser.Constants._TVL; -import static org.eclipse.lsp4xml.dom.parser.Constants._WSP; -import static org.eclipse.lsp4xml.dom.parser.Constants._YVL; +import static org.eclipse.lsp4xml.dom.parser.Constants.*; import org.eclipse.lsp4xml.dom.DOMDocumentType.DocumentTypeKind;; @@ -69,6 +33,19 @@ public class XMLScanner implements Scanner { String lastDoctypeKind; String url; boolean isInsideDTDContent = false; // Either internal dtd in xml file OR external dtd in dtd file + boolean isDeclCompleted = false; // If any type of DTD declaration was supplied with all the required properties + + /** + * boolean completedInitialAttDef; + * + * If the first attribute definition was completed in an ATTLIST declaration + * eg: + * + */ + boolean isInitialAttlistDeclCompleted = false; private int nbBraceOpened; public XMLScanner(String input, int initialOffset, ScannerState initialState) { @@ -91,8 +68,13 @@ String doctypeName() { return stream.advanceIfRegExp(ATTRIBUTE_NAME_REGEX).toLowerCase(); } + /** + * Tries to advance off the regex for either 'PUBLIC' or 'SYSTEM' + * + * @return "PUBLIC" or "SYSTEM" or "" otherwise + */ String doctypeKind() { - return stream.advanceIfRegExp(DOCTYPE_KIND_OPTIONS); + return stream.advanceIfRegExpGroup1(DOCTYPE_KIND_OPTIONS); } TokenType finishToken(int offset, TokenType type) { @@ -194,6 +176,7 @@ TokenType internalScan() { } if (stream.advanceIfChars(_EXL, _DVL, _OVL, _CVL, _TVL, _YVL, _PVL, _EVL)) { // !DOCTYPE + isDeclCompleted = false; state = ScannerState.DTDWithinDoctype; return finishToken(offset, TokenType.DTDStartDoctypeTag); } @@ -355,7 +338,7 @@ TokenType internalScan() { case DTDWithinDoctype: // Possible formats: // https://en.wikipedia.org/wiki/Document_type_declaration#Syntax - lastDoctypeKind = null; + if (stream.skipWhitespace()) { return finishToken(offset, TokenType.Whitespace); } @@ -369,6 +352,7 @@ TokenType internalScan() { if (stream.advanceIfChar(_CSB)) { // ] state = ScannerState.DTDWithinDoctype; isInsideDTDContent = false; + isDeclCompleted = true; return finishToken(offset, TokenType.DTDEndInternalSubset); } @@ -377,13 +361,21 @@ TokenType internalScan() { return finishToken(offset, TokenType.DTDEndDoctypeTag); } - String doctypeName = doctypeName(); - if (!doctypeName.equals("")) { - state = ScannerState.DTDAfterDoctypeName; - return finishToken(offset, TokenType.DTDDoctypeName); + if(stream.peekChar() == _LAN) { // < + state = ScannerState.WithinContent; + return internalScan(); } - stream.advanceUntilChar(_RAN); // > - return finishToken(offset, TokenType.Content); + + + if (isDeclCompleted == false) { + String doctypeName = doctypeName(); + if(!doctypeName.equals("")) { + state = ScannerState.DTDAfterDoctypeName; + return finishToken(offset, TokenType.DTDDoctypeName); + } + } + stream.advanceUntilCharOrNewTag(_RAN); // > || < + return finishToken(offset, TokenType.DTDUnrecognizedParameters); case DTDAfterDoctypeName: if (stream.skipWhitespace()) { @@ -443,10 +435,6 @@ TokenType internalScan() { return internalScan(); case DTDWithinContent: - if (stream.skipWhitespace()) { - return finishToken(offset, TokenType.Whitespace); - } - if (stream.advanceIfChar(_CSB)) { // ] state = ScannerState.DTDWithinDoctype; isInsideDTDContent = false; @@ -454,44 +442,75 @@ TokenType internalScan() { } if (stream.advanceIfChar(_LAN)) { // < + if (!stream.eos() && stream.peekChar() == _EXL) { // ! + isDeclCompleted = false; if (stream.advanceIfChars(_EXL, _EVL, _LVL, _EVL, _MVL, _EVL, _NVL, _TVL)) { // !ELEMENT state = ScannerState.DTDWithinElement; - return finishToken(offset, TokenType.DTDStartElementDecl); + return finishToken(offset, TokenType.DTDStartElement); } else if (stream.advanceIfChars(_EXL, _AVL, _TVL, _TVL, _LVL, _IVL, _SVL, _TVL)) { // !ATTLIST + isInitialAttlistDeclCompleted = false; state = ScannerState.DTDWithinAttlist; - return finishToken(offset, TokenType.DTDStartAttlistDecl); + return finishToken(offset, TokenType.DTDStartAttlist); } else if (stream.advanceIfChars(_EXL, _EVL, _NVL, _TVL, _IVL, _TVL, _YVL)) { // !ENTITY state = ScannerState.DTDWithinEntity; return finishToken(offset, TokenType.DTDStartEntity); + } else if (stream.advanceIfChars(_EXL, _NVL, _OVL, _TVL, _AVL, _TVL, _IVL, _OVL, _NVL)) { // !NOTATION + state = ScannerState.DTDWithinNotation; + return finishToken(offset, TokenType.DTDStartNotation); } else if (stream.advanceIfChars(_EXL, _MIN, _MIN)) { // !-- (for comment) state = ScannerState.WithinComment; return finishToken(offset, TokenType.StartCommentTag); } } + if (stream.advanceUntilCharOrNewTag(_RAN)) { // > + stream.advanceIfChar(_RAN); // > + return finishToken(offset, TokenType.Content); + } } - if (stream.advanceUntilChar(_CSB)) { // ] + if (stream.advanceIfChar(_CSB)) { // ] state = ScannerState.DTDWithinDoctype; isInsideDTDContent = false; return finishToken(offset, TokenType.DTDEndInternalSubset); } - stream.advanceUntilChar(_LAN); // < + + stream.advanceUntilAnyOfChars(_LAN, _CSB); // < || ] return finishToken(offset, TokenType.Content); + + + case DTDUnrecognizedParameters: - case DTDWithinElement: if (stream.skipWhitespace()) { return finishToken(offset, TokenType.Whitespace); } - if (stream.advanceIfChar(_RAN)) { // > + if(stream.advanceIfChar(_RAN)) { // > state = ScannerState.DTDWithinContent; return finishToken(offset, TokenType.DTDEndTag); } - if (!stream.advanceIfRegExp(Constants.ELEMENT_NAME_REGEX).equals("")) { - state = ScannerState.DTDAfterElementName; - return finishToken(offset, TokenType.DTDElementDeclName); + if(stream.peekChar() == _LAN) { // < + state = ScannerState.DTDWithinContent; + return internalScan(); + } + + if(stream.peekChar() == _CSB && isInsideDTDContent) { // ] + state = ScannerState.DTDWithinDoctype; + return internalScan(); + } + + if(stream.advanceUntilCharOrNewTag(_RAN)) { // > + if(stream.peekChar() == _LAN) { // < + state = ScannerState.DTDWithinContent; + } + } + return finishToken(offset, TokenType.DTDUnrecognizedParameters); + + + case DTDWithinElement: + if (stream.skipWhitespace()) { + return finishToken(offset, TokenType.Whitespace); } if (stream.advanceIfChar(_RAN)) { // > @@ -499,56 +518,75 @@ TokenType internalScan() { return finishToken(offset, TokenType.DTDEndTag); } - state = ScannerState.DTDWithinContent; + if(isDeclCompleted == true) { + state = ScannerState.DTDUnrecognizedParameters; + return internalScan(); + } + + if (!stream.advanceIfRegExp(Constants.ELEMENT_NAME_REGEX).equals("")) { + state = ScannerState.DTDElementAfterName; + return finishToken(offset, TokenType.DTDElementDeclName); + } + + state = ScannerState.DTDUnrecognizedParameters; return internalScan(); - case DTDAfterElementName: - nbBraceOpened = 0; + case DTDElementAfterName: if (stream.skipWhitespace()) { return finishToken(offset, TokenType.Whitespace); } if (stream.advanceIfChar(_ORB)) { // ( - nbBraceOpened++; - state = ScannerState.DTDWithinElementContent; + nbBraceOpened = 1; + state = ScannerState.DTDElementWithinContent; return finishToken(offset, TokenType.DTDStartElementContent); } - if (!stream.advanceIfRegExp(DTD_ELEMENT_CATEGORY).equals("")) { + if (!stream.advanceIfRegExpGroup1(DTD_ELEMENT_CATEGORY).equals("")) { + isDeclCompleted = true; state = ScannerState.DTDWithinElement; return finishToken(offset, TokenType.DTDElementCategory); } - if (stream.advanceIfChar(_RAN)) { // > - state = ScannerState.DTDWithinContent; - return finishToken(offset, TokenType.DTDEndTag); - } - - state = ScannerState.DTDWithinContent; + state = ScannerState.DTDUnrecognizedParameters; return internalScan(); - case DTDWithinElementContent: - if (stream.skipWhitespace()) { - return finishToken(offset, TokenType.Whitespace); + case DTDElementWithinContent: // + + if(stream.advanceIfChar(_CRB)) { // ) + isDeclCompleted = true; + state = ScannerState.DTDWithinElement; + return finishToken(offset, TokenType.DTDEndElementContent); } - if (stream.advanceUntilCharOrNewTag(_RAN)) { // > - if (stream.peekChar() == _LAN) { // < - state = ScannerState.DTDWithinContent; - return internalScan(); - } else { - // current character is '>' - if (stream.peekChar(-1) == _CSB) { - // previous character is ']', we can consider we are in the end of doctype. - stream.advance(-1); - state = ScannerState.DTDWithinContent; - return finishToken(offset, TokenType.DTDEndElementContent); + while(nbBraceOpened > 0) { + int c = stream.peekChar(); + + if(c == _ORB) { // ( + nbBraceOpened++; + } + else if(c == _CRB) { // ) + nbBraceOpened--; + if(nbBraceOpened == 0) { + return finishToken(offset, TokenType.DTDElementContent); } + } + else if(c == _RAN) { // > state = ScannerState.DTDWithinElement; - return finishToken(offset, TokenType.DTDEndElementContent); + return finishToken(offset, TokenType.DTDElementContent); + } + else if(c == _LAN) { // < + state = ScannerState.DTDWithinContent; + return finishToken(offset, TokenType.DTDElementContent); } + else if(c == -1) { + return finishToken(offset, TokenType.DTDElementContent); + } + stream.advance(1); } - return finishToken(offset, TokenType.Unknown); + + state = ScannerState.DTDUnrecognizedParameters; + return internalScan(); case DTDWithinAttlist: if (stream.skipWhitespace()) { @@ -560,17 +598,17 @@ TokenType internalScan() { return finishToken(offset, TokenType.DTDEndTag); } - if (!stream.advanceIfRegExp(Constants.ELEMENT_NAME_REGEX).equals("")) { - state = ScannerState.DTDAfterAttlistElementName; - return finishToken(offset, TokenType.DTDAttlistElementName); + if(isDeclCompleted == true) { + state = ScannerState.DTDUnrecognizedParameters; + return internalScan(); } - if (stream.advanceIfChar(_RAN)) { // > - state = ScannerState.DTDWithinContent; - return finishToken(offset, TokenType.DTDEndTag); + if (isInitialAttlistDeclCompleted == false && !stream.advanceIfRegExp(Constants.ELEMENT_NAME_REGEX).equals("")) { + state = ScannerState.DTDAfterAttlistElementName; + return finishToken(offset, TokenType.DTDAttlistElementName); } - state = ScannerState.DTDWithinContent; + state = ScannerState.DTDUnrecognizedParameters; return internalScan(); case DTDAfterAttlistElementName: @@ -588,7 +626,7 @@ TokenType internalScan() { return finishToken(offset, TokenType.DTDEndTag); } - state = ScannerState.DTDWithinContent; + state = ScannerState.DTDUnrecognizedParameters; return internalScan(); case DTDAfterAttlistAttributeName: @@ -596,9 +634,9 @@ TokenType internalScan() { return finishToken(offset, TokenType.Whitespace); } - if (!stream.advanceIfRegExp(Constants.DTD_ATTLIST_ATTRIBUTE_TYPE).equals("")) { + if (!stream.advanceIfRegExpGroup1(Constants.DTD_ATTLIST_ATTRIBUTE_TYPE).equals("")) { state = ScannerState.DTDAfterAttlistAttributeType; - return finishToken(offset, TokenType.DTDAttlistType); + return finishToken(offset, TokenType.DTDAttlistAttributeType); } if (stream.advanceIfChar(_RAN)) { // > @@ -606,7 +644,7 @@ TokenType internalScan() { return finishToken(offset, TokenType.DTDEndTag); } - state = ScannerState.DTDWithinContent; + state = ScannerState.DTDUnrecognizedParameters; return internalScan(); case DTDAfterAttlistAttributeType: @@ -614,8 +652,10 @@ TokenType internalScan() { return finishToken(offset, TokenType.Whitespace); } - if (!stream.advanceIfRegExp(Constants.DTD_ATTLIST_ATTRIBUTE_VALUE).equals("")) { - state = ScannerState.DTDWithinAttlist; + if (!stream.advanceIfRegExpGroup1(Constants.DTD_ATTLIST_ATTRIBUTE_VALUE).equals("")) { + isInitialAttlistDeclCompleted = true; //we completed the initial attribute declaration + isDeclCompleted = true; + state = ScannerState.DTDAfterAttlistElementName; return finishToken(offset, TokenType.DTDAttlistAttributeValue); } @@ -624,7 +664,7 @@ TokenType internalScan() { return finishToken(offset, TokenType.DTDEndTag); } - state = ScannerState.DTDWithinContent; + state = ScannerState.DTDUnrecognizedParameters; return internalScan(); case DTDWithinEntity: @@ -637,17 +677,21 @@ TokenType internalScan() { return finishToken(offset, TokenType.DTDEndTag); } + if(isDeclCompleted == true) { + state = ScannerState.DTDUnrecognizedParameters; + return internalScan(); + } + if (!stream.advanceIfRegExp(Constants.ELEMENT_NAME_REGEX).equals("")) { state = ScannerState.DTDAfterEntityName; return finishToken(offset, TokenType.DTDEntityName); } - if (stream.advanceIfChar(_RAN)) { // > - state = ScannerState.DTDWithinContent; - return finishToken(offset, TokenType.DTDEndTag); + if (stream.advanceIfChar(_PCT)) { // % + return finishToken(offset, TokenType.DTDEntityPercent); } - state = ScannerState.DTDWithinContent; + state = ScannerState.DTDUnrecognizedParameters; return internalScan(); case DTDAfterEntityName: @@ -656,13 +700,36 @@ TokenType internalScan() { } if (!stream.advanceIfRegExp(Constants.DTD_ENTITY_VALUE).equals("")) { + isDeclCompleted = true; state = ScannerState.DTDWithinEntity; return finishToken(offset, TokenType.DTDEntityValue); } - if (stream.advanceIfChars(_SVL, _YVL, _SVL, _TVL, _EVL, _MVL)) { // SYSTEM - state = ScannerState.DTDAfterEntityKind; - return finishToken(offset, TokenType.DTDEntityKind); + lastDoctypeKind = doctypeKind(); // eg: PUBLIC || SYSTEM, will advance the stream if either of these + if (lastDoctypeKind.equals(DocumentTypeKind.PUBLIC.name())) { + state = ScannerState.DTDAfterEntityPUBLIC; + return finishToken(offset, TokenType.DTDEntityKindPUBLIC); + } else if (lastDoctypeKind.equals(DocumentTypeKind.SYSTEM.name())) { + state = ScannerState.DTDAfterEntitySYSTEM; + return finishToken(offset, TokenType.DTDEntityKindSYSTEM); + } + + if (stream.advanceIfChar(_RAN)) { // > + state = ScannerState.DTDWithinContent; + return finishToken(offset, TokenType.DTDEndTag); + } + + state = ScannerState.DTDUnrecognizedParameters; + return internalScan(); + + case DTDAfterEntityPUBLIC: + if (stream.skipWhitespace()) { + return finishToken(offset, TokenType.Whitespace); + } + + if (!stream.advanceIfRegExp(URL_VALUE_REGEX).equals("")) { + state = ScannerState.DTDAfterEntitySYSTEM; + return finishToken(offset, TokenType.DTDEntityPublicId); } if (stream.advanceIfChar(_RAN)) { // > @@ -670,17 +737,18 @@ TokenType internalScan() { return finishToken(offset, TokenType.DTDEndTag); } - state = ScannerState.DTDWithinContent; + state = ScannerState.DTDUnrecognizedParameters; return internalScan(); - case DTDAfterEntityKind: + case DTDAfterEntitySYSTEM: if (stream.skipWhitespace()) { return finishToken(offset, TokenType.Whitespace); } if (!stream.advanceIfRegExp(URL_VALUE_REGEX).equals("")) { + isDeclCompleted = true; state = ScannerState.DTDWithinEntity; - return finishToken(offset, TokenType.DTDEntityURL); + return finishToken(offset, TokenType.DTDEntitySystemId); } if (stream.advanceIfChar(_RAN)) { // > @@ -688,10 +756,96 @@ TokenType internalScan() { return finishToken(offset, TokenType.DTDEndTag); } - state = ScannerState.DTDWithinContent; + state = ScannerState.DTDUnrecognizedParameters; + return internalScan(); + + case DTDWithinNotation: + if (stream.skipWhitespace()) { + return finishToken(offset, TokenType.Whitespace); + } + + if(stream.advanceIfChar(_RAN)) { // > + state = ScannerState.DTDWithinContent; + return finishToken(offset, TokenType.DTDEndTag); + } + + if(isDeclCompleted == true) { + state = ScannerState.DTDUnrecognizedParameters; + return internalScan(); + } + + if (!stream.advanceIfRegExp(ELEMENT_NAME_REGEX).equals("")) { + state = ScannerState.DTDAfterNotationName; + return finishToken(offset, TokenType.DTDNotationName); + } + + state = ScannerState.DTDUnrecognizedParameters; + return internalScan(); + + case DTDAfterNotationName: + if (stream.skipWhitespace()) { + return finishToken(offset, TokenType.Whitespace); + } + + lastDoctypeKind = doctypeKind(); // eg: PUBLIC || SYSTEM, will advance the stream if either of these + if (lastDoctypeKind.equals(DocumentTypeKind.PUBLIC.name())) { + state = ScannerState.DTDAfterNotationPUBLIC; + return finishToken(offset, TokenType.DTDNotationKindPUBLIC); + } else if (lastDoctypeKind.equals(DocumentTypeKind.SYSTEM.name())) { + state = ScannerState.DTDAfterNotationSYSTEM; + return finishToken(offset, TokenType.DTDNotationKindSYSTEM); + } + + state = ScannerState.DTDUnrecognizedParameters; + return internalScan(); + + case DTDAfterNotationPUBLIC: + if (stream.skipWhitespace()) { + return finishToken(offset, TokenType.Whitespace); + } + url = stream.advanceIfRegExp(URL_VALUE_REGEX); + if (!url.equals("")) { + isDeclCompleted = true; + state = ScannerState.DTDAfterNotationPublicId; + return finishToken(offset, TokenType.DTDNotationPublicId); + } + + state = ScannerState.DTDUnrecognizedParameters; + return internalScan(); + + case DTDAfterNotationSYSTEM: + if (stream.skipWhitespace()) { + return finishToken(offset, TokenType.Whitespace); + } + + state = ScannerState.DTDWithinNotation; + url = stream.advanceIfRegExp(URL_VALUE_REGEX); + if (!url.equals("")) { + isDeclCompleted = true; + state = ScannerState.DTDAfterNotationName; + return finishToken(offset, TokenType.DTDNotationSystemId); + } + state = ScannerState.DTDWithinNotation; + return internalScan(); + + case DTDAfterNotationPublicId: + if (stream.skipWhitespace()) { + return finishToken(offset, TokenType.Whitespace); + } + + state = ScannerState.DTDAfterNotationName; + url = stream.advanceIfRegExp(URL_VALUE_REGEX); // scan the System Identifier URL + if (!url.equals("")) { + isDeclCompleted = true; + return finishToken(offset, TokenType.DTDNotationSystemId); + } return internalScan(); } + + + + stream.advance(1); state = isInsideDTDContent ? ScannerState.DTDWithinContent : ScannerState.WithinContent; return finishToken(offset, TokenType.Unknown, errorMessage); diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/services/XMLSymbolsProvider.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/services/XMLSymbolsProvider.java index 3446ae196d..66233e3860 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/services/XMLSymbolsProvider.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/services/XMLSymbolsProvider.java @@ -28,6 +28,7 @@ import org.eclipse.lsp4xml.dom.DOMNode; import org.eclipse.lsp4xml.dom.DTDAttlistDecl; import org.eclipse.lsp4xml.dom.DTDElementDecl; +import org.eclipse.lsp4xml.dom.DTDNotationDecl; import org.eclipse.lsp4xml.services.extensions.XMLExtensionsRegistry; import org.w3c.dom.DocumentType; import org.w3c.dom.Element; @@ -92,6 +93,7 @@ private void findDocumentSymbols(DOMNode node, List symbols, Lis children = hasChildNodes || node.isDTDElementDecl() ? new ArrayList<>() : Collections.emptyList(); DocumentSymbol symbol = new DocumentSymbol(name, getSymbolKind(node), range, selectionRange, null, children); + symbols.add(symbol); if (node.isDTDElementDecl()) { // In the case of DTD ELEMENT we try to add in the children the DTD ATTLIST @@ -155,7 +157,7 @@ private static SymbolKind getSymbolKind(DOMNode node) { return SymbolKind.Property; } else if (node.isDoctype()) { return SymbolKind.Struct; - } else if (node.isDTDElementDecl() || node.isDTDEntityDecl()) { + } else if (node.isDTDElementDecl() || node.isDTDEntityDecl() || node.isDTDNotationDecl()) { return SymbolKind.Property; } else if (node.isDTDAttListDecl()) { return SymbolKind.Key; @@ -165,7 +167,7 @@ private static SymbolKind getSymbolKind(DOMNode node) { private static boolean isNodeSymbol(DOMNode node) { return node.isElement() || node.isDoctype() || node.isProcessingInstruction() || node.isProlog() - || node.isDTDElementDecl() || node.isDTDAttListDecl() || node.isDTDEntityDecl(); + || node.isDTDElementDecl() || node.isDTDAttListDecl() || node.isDTDEntityDecl() || node.isDTDNotationDecl(); } private static String nodeToName(DOMNode node) { @@ -180,9 +182,12 @@ private static String nodeToName(DOMNode node) { name = ((DTDElementDecl) node).getName(); } else if (node.isDTDAttListDecl()) { DTDAttlistDecl attr = (DTDAttlistDecl) node; - name = attr.getName(); + name = attr.getAttributeName(); } else if (node.isDTDEntityDecl()) { name = node.getNodeName(); + } else if (node.isDTDNotationDecl()) { + DTDNotationDecl notation = (DTDNotationDecl) node; + name = notation.getName(); } if (node.hasAttributes()) { diff --git a/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/dom/DOMParserForInternalDTDTest.java b/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/dom/DOMParserForInternalDTDTest.java index e4d569ac09..e088c8f902 100644 --- a/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/dom/DOMParserForInternalDTDTest.java +++ b/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/dom/DOMParserForInternalDTDTest.java @@ -89,14 +89,13 @@ public void docTypeNotClosedAndElement() { String xml = ""; DOMDocument actual = createDOMDocument(xml); - Assert.assertEquals(1, actual.getChildren().size()); + Assert.assertEquals(2, actual.getChildren().size()); Assert.assertTrue(actual.getChild(0).isDoctype()); DOMDocumentType documentType = (DOMDocumentType) actual.getChild(0); Assert.assertEquals(0, documentType.getStart()); - Assert.assertEquals(22, documentType.getEnd()); + Assert.assertEquals(16, documentType.getEnd()); Assert.assertEquals("foo", documentType.getName()); - Assert.assertTrue(documentType.isClosed()); // here close comes from the '>' of - + Assert.assertTrue(actual.getChild(1).isClosed()); // here close comes from the '>' of } @Test @@ -328,6 +327,7 @@ public void attListDeclNotClosed() { Assert.assertTrue(actual.getChild(1).isElement()); } + //This will fail because the Attribute name regex in Constants.java considers the ']' after 'a' a valid attribute name @Ignore @Test public void attListDeclWithNameNotClosed() { diff --git a/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/dom/DOMParserTest.java b/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/dom/DOMParserTest.java index c3faa30f3c..1a1dcae1e5 100644 --- a/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/dom/DOMParserTest.java +++ b/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/dom/DOMParserTest.java @@ -12,6 +12,8 @@ import static org.junit.Assert.assertEquals; +import java.util.ArrayList; + import org.eclipse.lsp4xml.dom.DOMDocumentType.DocumentTypeKind; import org.junit.Assert; import org.junit.Test; @@ -414,6 +416,288 @@ public void testDoctype2() { assertDoctype((DOMDocumentType)(document.getChild(0)), 0, 212, "html", DocumentTypeKind.SYSTEM.name(), null, "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd", internal); } + + @Test + public void testDTDEntity() { + String xml = + "\n" + + "]>"; + + DOMNode doctype = createDoctypeNode(0, 86, 10, 14, null, null, null, null, null, null, 15, 85); + doctype.closed = true; + DOMNode entity = createEntityDecl(19, 83, 28, 34, null, null, 35, 41, null, null, 42, 82, null, null); + entity.closed = true; + doctype.addChild(entity); + + DOMDocument document = DOMParser.getInstance().parse(xml, null, null); + compareTrees(doctype, document.getChild(0)); + + } + + @Test + public void testDTDAllTypes() { + String xml = + "\n" + + " \n" + + " \n" + + "] >"; + + DOMNode doctype = createDoctypeNode(0, 155, 10, 14, null, null, null, null, null, null, 15, 153); + doctype.closed = true; + DOMNode entity = createEntityDecl(19, 83, 28, 34, null, null, 35, 41, null, null, 42, 82, null, null); + entity.closed = true; + DOMNode element = createElementDecl(86, 111, 96, 100, null, null, 101, 110, null, null); + element.closed = true; + DOMNode attlist = createAttlistDecl(114, 151, 124, 131, 132, 136, 137, 142, 143, 150, null, null); + attlist.closed = true; + + doctype.addChild(entity); + doctype.addChild(element); + doctype.addChild(attlist); + + DOMDocument document = DOMParser.getInstance().parse(xml, null, null); + compareTrees(doctype, document.getChild(0)); + + } + + @Test + public void testDTDExternal() { + String dtd = + "\n" + + "\n" + + ""; + + DOMNode doctype = createDoctypeNode(0, 128, null, null, null, null, null, null, null, null, null, null); + doctype.closed = true; + DOMNode entity = createEntityDecl(0, 64, 9, 15, null, null, 16, 22, null, null, 23, 63, null, null); + entity.closed = true; + DOMNode element = createElementDecl(65, 90, 75, 79, null, null, 80, 89, null, null); + element.closed = true; + DOMNode attlist = createAttlistDecl(91, 128, 101, 108, 109, 113, 114, 119, 120, 127, null, null); + attlist.closed = true; + + doctype.addChild(entity); + doctype.addChild(element); + doctype.addChild(attlist); + + DOMDocument document = DOMParser.getInstance().parse(dtd, "name.dtd", null); + compareTrees(doctype, document.getChild(0)); + + } + + @Test + public void testDTDExternal2() { + String dtd = + "\n" + + ""; + + DOMNode doctype = createDoctypeNode(0, 95, null, null, null, null, null, null, null, null, null, null); + doctype.closed = true; + DOMNode attlist = createAttlistDecl(0, 41, 10, 25, 26, 28, 29, 31, 32, 40, null, null); + attlist.closed = true; + DOMNode element = createElementDecl(42, 95, 52, 67, null, null, 68, 94, null, null); + element.closed = true; + + + doctype.addChild(attlist); + doctype.addChild(element); + + DOMDocument document = DOMParser.getInstance().parse(dtd, "name.dtd", null); + compareTrees(doctype, document.getChild(0)); + + } + + @Test + public void testDTDExternalUnrecognizedParameters() { + String dtd = + "\n" + + ""; + + DOMNode doctype = createDoctypeNode(0, 81, null, null, null, null, null, null, null, null, null, null); + doctype.closed = true; + DOMNode entity = createEntityDecl(0, 24, 9, 15, null, null, 16, 22, null, null, null, null, null, null); + entity.closed = true; + DOMNode element = createElementDecl(25, 49, 35, 39, null, null, 40, 49, null, null); + element.closed = false; + DOMNode attlist = createAttlistDecl(50, 81, 60, 67, 68, 72, null, null, null, null, 73, 80); + attlist.closed = true; + + doctype.addChild(entity); + doctype.addChild(element); + doctype.addChild(attlist); + + DOMDocument document = DOMParser.getInstance().parse(dtd, "name.dtd", null); + compareTrees(doctype, document.getChild(0)); + + } + + @Test + public void testDTDExternalUnrecognizedParameters2() { + String dtd = + ""; + + DOMNode doctype = createDoctypeNode(0, 81, null, null, null, null, null, null, null, null, null, null); + doctype.closed = true; + DOMNode entity = createEntityDecl(0, 24, 9, 15, null, null, 16, 22, null, null, null, null, null, null); + entity.closed = false; + DOMNode element = createElementDecl(25, 49, 35, 39, null, null, 40, 49, null, null); + element.closed = false; + DOMNode attlist = createAttlistDecl(50, 81, 60, 67, 68, 72, null, null, null, null, 73, 80); + attlist.closed = true; + + doctype.addChild(entity); + doctype.addChild(element); + doctype.addChild(attlist); + + DOMDocument document = DOMParser.getInstance().parse(dtd, "name.dtd", null); + compareTrees(doctype, document.getChild(0)); + + } + + @Test + public void testDTDExternalUnrecognizedParameters3() { + String dtd = + ""; + + DOMNode doctype = createDoctypeNode(0, 32, null, null, null, null, null, null, null, null, null, null); + doctype.closed = true; + DOMNode attlist = createAttlistDecl(0, 15, 10, 14, null, null, null, null, null, null, null, null); + attlist.closed = false; + DOMNode element = createElementDecl(16, 32, 26, 30, null, null, null, null, null, null); + element.closed = true; + + + doctype.addChild(attlist); + doctype.addChild(element); + + DOMDocument document = DOMParser.getInstance().parse(dtd, "name.dtd", null); + compareTrees(doctype, document.getChild(0)); + + } + + @Test + public void testDTDExternalElementContentUnclosed() { + String dtd = + ""; + + DOMNode doctype = createDoctypeNode(0, 23, null, null, null, null, null, null, null, null, null, null); + doctype.closed = true; + + DOMNode element = createElementDecl(0, 23, 10, 14, null, null, 15, 22, null, null); + element.closed = true; + + doctype.addChild(element); + + DOMDocument document = DOMParser.getInstance().parse(dtd, "name.dtd", null); + compareTrees(doctype, document.getChild(0)); + + } + + @Test + public void testATTLISTMultipleInternal() { + String dtd = + ""; + + DOMNode doctype = createDoctypeNode(0, 70, null, null, null, null, null, null, null, null, null, null); + doctype.closed = true; + DTDAttlistDecl attlist = createAttlistDecl(0, 70, 10, 21, 26, 28, 29, 34, 35, 44, null, null); + attlist.closed = true; + DTDAttlistDecl attlistInternal = createAttlistDecl(-1, -1, null, null, 49, 53, 54, 59, 60, 69, null, null); + attlistInternal.closed = true; + + doctype.addChild(attlist); + attlist.addAdditionalAttDecl(attlistInternal); + + DOMDocument document = DOMParser.getInstance().parse(dtd, "name.dtd", null); + compareTrees(doctype, document.getChild(0)); + } + + @Test + public void testNotation() { + String dtd = + "\n" + + "\n" + + ""; + + DOMNode doctype = createDoctypeNode(0, 112, null, null, null, null, null, null, null, null, null, null); + doctype.closed = true; + DTDNotationDecl notation1 = createNotationDecl(0, 32, 11, 14, 15, 21, 22, 31, null, null, null, null); + notation1.closed = true; + DTDNotationDecl notation2 = createNotationDecl(33, 77, 44, 47, 48, 54, 55, 64, 65, 76, null, null); + notation2.closed = true; + DTDNotationDecl notation3 = createNotationDecl(78, 112, 89, 92, 93, 99, null, null, 100, 111, null, null); + notation3.closed = true; + + doctype.addChild(notation1); + doctype.addChild(notation2); + doctype.addChild(notation3); + + DOMDocument document = DOMParser.getInstance().parse(dtd, "name.dtd", null); + compareTrees(doctype, document.getChild(0)); + } + + @Test + public void testNotationMissingEndTag() { + String dtd = + ""; + + DOMNode doctype = createDoctypeNode(0, 77, null, null, null, null, null, null, null, null, null, null); + doctype.closed = true; + DTDNotationDecl notation1 = createNotationDecl(0, 32, 11, 14, 15, 21, 22, 32, null, null, null, null); + notation1.closed = false; + DTDNotationDecl notation2 = createNotationDecl(33, 77, 44, 47, 48, 54, 55, 64, 65, 76, null, null); + notation2.closed = true; + + doctype.addChild(notation1); + doctype.addChild(notation2); + + DOMDocument document = DOMParser.getInstance().parse(dtd, "name.dtd", null); + compareTrees(doctype, document.getChild(0)); + } + + @Test + public void testNotationMissingEndTagMissingAndExtraValues() { + String dtd = + ""; + + DOMNode doctype = createDoctypeNode(0, 81, null, null, null, null, null, null, null, null, null, null); + doctype.closed = true; + DTDNotationDecl notation1 = createNotationDecl(0, 32, 11, 14, 15, 21, 22, 32, null, null, null, null); + notation1.closed = false; + DTDNotationDecl notation2 = createNotationDecl(33, 81, 44, 47, 48, 54, 55, 64, 65, 76, 77, 80); + notation2.closed = true; + + doctype.addChild(notation1); + doctype.addChild(notation2); + + DOMDocument document = DOMParser.getInstance().parse(dtd, "name.dtd", null); + compareTrees(doctype, document.getChild(0)); + } + + @Test + public void testUnrecognizedDTDTagName() { + String dtd = ""; + + DOMNode doctype = createDoctypeNode(0, 48, null, null, null, null, null, null, null, null, null, null); + doctype.closed = true; + DOMText text = createTextNode("", 0, 48, true); + + doctype.addChild(text); + + DOMDocument document = DOMParser.getInstance().parse(dtd, "name.dtd", null); + compareTrees(doctype, document.getChild(0)); + } + // -------------------------------------------------------------------------------- // Tools @@ -454,6 +738,89 @@ private static DOMElement createElement(String tag, int start, Integer endTagSta return (DOMElement) createNode(DOMNode.ELEMENT_NODE, tag, start, endTagStart, end, closed); } + private static DTDAttlistDecl createAttlistDecl(int start, int end, Integer elementNameStart, Integer elementNameEnd, Integer attributeNameStart, + Integer attributeNameEnd, Integer attributeTypeStart, Integer attributeTypeEnd, Integer attributeValueStart, Integer attributeValueEnd, + Integer unrecognizedStart, Integer unrecognizedEnd) { + DTDAttlistDecl attlist = new DTDAttlistDecl(start, end, null); + attlist.elementNameStart = elementNameStart; + attlist.elementNameEnd = elementNameEnd; + attlist.attributeNameStart = attributeNameStart; + attlist.attributeNameEnd = attributeNameEnd; + attlist.attributeTypeStart = attributeTypeStart; + attlist.attributeTypeEnd = attributeTypeEnd; + attlist.attributeValueStart = attributeValueStart; + attlist.attributeValueEnd = attributeValueEnd; + attlist.unrecognizedStart = unrecognizedStart; + attlist.unrecognizedEnd = unrecognizedEnd; + return attlist; + } + + private static DTDElementDecl createElementDecl(int start, int end, Integer nameStart, Integer nameEnd, Integer categoryStart, + Integer categoryEnd, Integer contentStart, Integer contentEnd, Integer unrecognizedStart, Integer unrecognizedEnd) { + DTDElementDecl element = new DTDElementDecl(start, end, null); + element.nameStart = nameStart; + element.nameEnd = nameEnd; + element.categoryStart = categoryStart; + element.categoryEnd = categoryEnd; + element.contentStart = contentStart; + element.contentEnd = contentEnd; + element.unrecognizedStart = unrecognizedStart; + element.unrecognizedEnd = unrecognizedEnd; + return element; + } + + private static DTDEntityDecl createEntityDecl(int start, int end, Integer nameStart, Integer nameEnd, Integer valueStart, + Integer valueEnd, Integer kindStart, Integer kindEnd, Integer publicIdStart, Integer publicIdEnd, Integer systemIdStart, + Integer systemIdEnd, Integer unrecognizedStart, Integer unrecognizedEnd) { + DTDEntityDecl entity = new DTDEntityDecl(start, end, null); + entity.nameStart = nameStart; + entity.nameEnd = nameEnd; + entity.valueStart = valueStart; + entity.valueEnd = valueEnd; + entity.kindStart = kindStart; + entity.kindEnd = kindEnd; + entity.publicIdStart = publicIdStart; + entity.publicIdEnd = publicIdEnd; + entity.systemIdStart = systemIdStart; + entity.systemIdEnd = systemIdEnd; + entity.unrecognizedStart = unrecognizedStart; + entity.unrecognizedEnd = unrecognizedEnd; + return entity; + } + + private static DTDNotationDecl createNotationDecl(int start, int end, Integer nameStart, Integer nameEnd, Integer kindStart, Integer kindEnd, + Integer publicIdStart, Integer publicIdEnd, Integer systemIdStart, Integer systemIdEnd, Integer unrecognizedStart, Integer unrecognizedEnd) { + DTDNotationDecl notation = new DTDNotationDecl(start, end, null); + notation.nameStart = nameStart; + notation.nameEnd = nameEnd; + notation.kindStart = kindStart; + notation.kindEnd = kindEnd; + notation.publicIdStart = publicIdStart; + notation.publicIdEnd = publicIdEnd; + notation.systemIdStart = systemIdStart; + notation.systemIdEnd = systemIdEnd; + notation.unrecognizedStart = unrecognizedStart; + notation.unrecognizedEnd = unrecognizedEnd; + return notation; + } + + private static DOMDocumentType createDoctypeNode(int start, int end, Integer nameStart, Integer nameEnd, Integer kindStart, + Integer kindEnd, Integer publicIdStart, Integer publicIdEnd, Integer systemIdStart, Integer systemIdEnd, + Integer internalSubsetStart, Integer internalSubsetEnd) { + DOMDocumentType doctype = new DOMDocumentType(start, end, null); + doctype.nameStart = nameStart; + doctype.nameEnd = nameEnd; + doctype.kindStart = kindStart; + doctype.kindEnd = kindEnd; + doctype.publicIdStart = publicIdStart; + doctype.publicIdEnd = publicIdEnd; + doctype.systemIdStart = systemIdStart; + doctype.systemIdEnd = systemIdEnd; + doctype.internalSubsetStart = internalSubsetStart; + doctype.internalSubsetEnd = internalSubsetEnd; + return doctype; + } + private static DOMNode createNode(short nodeType, String tag, int start, Integer endTagStart, int end, boolean closed) { DOMNode n = createNode(nodeType, start, end); @@ -595,6 +962,105 @@ private static void compareTrees(DOMNode expectedNode, DOMNode actualNode) { if (expectedNode.isCharacterData()) { assertEquals(((DOMCharacterData) expectedNode).getData(), ((DOMCharacterData) actualNode).getData()); } + + if (expectedNode.isDTDAttListDecl()) { + assertEquals(true, actualNode.isDTDAttListDecl()); + DTDAttlistDecl expectedTemp = (DTDAttlistDecl) expectedNode; + DTDAttlistDecl actualTemp = (DTDAttlistDecl) actualNode; + assertEquals(expectedTemp.elementNameStart, actualTemp.elementNameStart); + assertEquals(expectedTemp.elementNameEnd, actualTemp.elementNameEnd); + assertEquals(expectedTemp.attributeNameStart, actualTemp.attributeNameStart); + assertEquals(expectedTemp.attributeNameEnd, actualTemp.attributeNameEnd); + assertEquals(expectedTemp.attributeTypeStart, actualTemp.attributeTypeStart); + assertEquals(expectedTemp.attributeTypeEnd, actualTemp.attributeTypeEnd); + assertEquals(expectedTemp.attributeValueStart, actualTemp.attributeValueStart); + assertEquals(expectedTemp.attributeValueEnd, actualTemp.attributeValueEnd); + assertEquals(expectedTemp.unrecognizedStart, actualTemp.unrecognizedStart); + assertEquals(expectedTemp.unrecognizedEnd, actualTemp.unrecognizedEnd); + + ArrayList expectedInternalChildren = expectedTemp.getInternalChildren(); + ArrayList actualInternalChildren = actualTemp.getInternalChildren(); + assertEquals(expectedInternalChildren == null, actualInternalChildren == null); + if(expectedInternalChildren != null) { + assertEquals(expectedInternalChildren.size(), actualInternalChildren.size()); + for (int i = 0; i < expectedTemp.getInternalChildren().size(); i++) { + assertInternalAttlist(expectedInternalChildren.get(i), actualInternalChildren.get(i)); + } + } + } + + if(expectedNode.isDTDElementDecl()) { + assertEquals(true, actualNode.isDTDElementDecl()); + DTDElementDecl expectedTemp = (DTDElementDecl) expectedNode; + DTDElementDecl actualTemp = (DTDElementDecl) actualNode; + assertEquals(expectedTemp.nameStart, actualTemp.nameStart); + assertEquals(expectedTemp.nameEnd, actualTemp.nameEnd); + assertEquals(expectedTemp.categoryStart, actualTemp.categoryStart); + assertEquals(expectedTemp.categoryEnd, actualTemp.categoryEnd); + assertEquals(expectedTemp.contentStart, actualTemp.contentStart); + assertEquals(expectedTemp.contentEnd, actualTemp.contentEnd); + assertEquals(expectedTemp.unrecognizedStart, actualTemp.unrecognizedStart); + assertEquals(expectedTemp.unrecognizedEnd, actualTemp.unrecognizedEnd); + } + + else if(expectedNode.isDTDEntityDecl()) { + assertEquals(true, actualNode.isDTDEntityDecl()); + DTDEntityDecl expectedTemp = (DTDEntityDecl) expectedNode; + DTDEntityDecl actualTemp = (DTDEntityDecl) actualNode; + assertEquals(expectedTemp.nameStart, actualTemp.nameStart); + assertEquals(expectedTemp.nameEnd, actualTemp.nameEnd); + assertEquals(expectedTemp.valueStart, actualTemp.valueStart); + assertEquals(expectedTemp.valueEnd, actualTemp.valueEnd); + assertEquals(expectedTemp.kindStart, actualTemp.kindStart); + assertEquals(expectedTemp.kindEnd, actualTemp.kindEnd); + assertEquals(expectedTemp.publicIdStart, actualTemp.publicIdStart); + assertEquals(expectedTemp.publicIdEnd, actualTemp.publicIdEnd); + assertEquals(expectedTemp.systemIdStart, actualTemp.systemIdStart); + assertEquals(expectedTemp.systemIdEnd, actualTemp.systemIdEnd); + assertEquals(expectedTemp.unrecognizedStart, actualTemp.unrecognizedStart); + assertEquals(expectedTemp.unrecognizedEnd, actualTemp.unrecognizedEnd); + } + + else if(expectedNode.isDTDNotationDecl()) { + assertEquals(true, actualNode.isDTDNotationDecl()); + DTDNotationDecl expectedTemp = (DTDNotationDecl) expectedNode; + DTDNotationDecl actualTemp = (DTDNotationDecl) actualNode; + assertEquals(expectedTemp.nameStart, actualTemp.nameStart); + assertEquals(expectedTemp.nameEnd, actualTemp.nameEnd); + assertEquals(expectedTemp.kindStart, actualTemp.kindStart); + assertEquals(expectedTemp.kindEnd, actualTemp.kindEnd); + assertEquals(expectedTemp.publicIdStart, actualTemp.publicIdStart); + assertEquals(expectedTemp.publicIdEnd, actualTemp.publicIdEnd); + assertEquals(expectedTemp.systemIdStart, actualTemp.systemIdStart); + assertEquals(expectedTemp.systemIdEnd, actualTemp.systemIdEnd); + assertEquals(expectedTemp.unrecognizedStart, actualTemp.unrecognizedStart); + assertEquals(expectedTemp.unrecognizedEnd, actualTemp.unrecognizedEnd); + } + + else if(expectedNode.isDoctype()) { + assertEquals(true, actualNode.isDoctype()); + DOMDocumentType expectedTemp = (DOMDocumentType) expectedNode; + DOMDocumentType actualTemp = (DOMDocumentType) actualNode; + assertEquals(expectedTemp.nameStart, actualTemp.nameStart); + assertEquals(expectedTemp.nameEnd, actualTemp.nameEnd); + assertEquals(expectedTemp.kindStart, actualTemp.kindStart); + assertEquals(expectedTemp.kindEnd, actualTemp.kindEnd); + assertEquals(expectedTemp.publicIdStart, actualTemp.publicIdStart); + assertEquals(expectedTemp.publicIdEnd, actualTemp.publicIdEnd); + assertEquals(expectedTemp.systemIdStart, actualTemp.systemIdStart); + assertEquals(expectedTemp.systemIdEnd, actualTemp.systemIdEnd); + assertEquals(expectedTemp.internalSubsetStart, actualTemp.internalSubsetStart); + assertEquals(expectedTemp.internalSubsetEnd, actualTemp.internalSubsetEnd); + } + + else if(expectedNode.isGenericDTDDecl()) { + DTDDeclNode expectedTemp = (DTDDeclNode) expectedNode; + DTDDeclNode actualTemp = (DTDDeclNode) actualNode; + + assertEquals(expectedTemp.unrecognizedStart, actualTemp.unrecognizedStart); + assertEquals(expectedTemp.unrecognizedEnd, actualTemp.unrecognizedEnd); + } + assertEquals(expectedNode.isClosed(), actualNode.isClosed()); assertEquals(expectedNode.isCDATA(), actualNode.isCDATA()); assertEquals(expectedNode.isProcessingInstruction(), actualNode.isProcessingInstruction()); @@ -606,6 +1072,26 @@ private static void compareTrees(DOMNode expectedNode, DOMNode actualNode) { } } + public static void assertInternalAttlist(DTDAttlistDecl expected, DTDAttlistDecl actual) { + assertEquals(expected.attributeNameStart, actual.attributeNameStart); + assertEquals(expected.attributeNameEnd, actual.attributeNameEnd); + assertEquals(expected.attributeTypeStart, actual.attributeTypeStart); + assertEquals(expected.attributeTypeEnd, actual.attributeTypeEnd); + assertEquals(expected.attributeValueStart, actual.attributeValueStart); + assertEquals(expected.attributeValueEnd, actual.attributeValueEnd); + } + + public static void assertInternalNotation(DTDNotationDecl expected, DTDNotationDecl actual) { + assertEquals(expected.nameStart, actual.nameStart); + assertEquals(expected.nameEnd, actual.nameEnd); + assertEquals(expected.kindStart, actual.kindStart); + assertEquals(expected.kindEnd, actual.kindEnd); + assertEquals(expected.publicIdStart, actual.publicIdStart); + assertEquals(expected.publicIdEnd, actual.publicIdEnd); + assertEquals(expected.systemIdStart, actual.systemIdStart); + assertEquals(expected.systemIdEnd, actual.systemIdEnd); + } + public void insertIntoAttributes(DOMNode n, String key, String value) { n.setAttribute(key, value); } diff --git a/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/dom/parser/XMLScannerForExternalDTDTest.java b/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/dom/parser/XMLScannerForExternalDTDTest.java index 73f5bc8805..fb9857c005 100644 --- a/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/dom/parser/XMLScannerForExternalDTDTest.java +++ b/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/dom/parser/XMLScannerForExternalDTDTest.java @@ -30,7 +30,7 @@ public void testDocumentTypeExternalOnly() { ""; scanner = XMLScanner.createScanner(dtd, true); // assertOffsetAndToken(0, TokenType.DTDStartDoctypeTag); - assertOffsetAndToken(0, TokenType.Whitespace); + assertOffsetAndToken(0, TokenType.Content); // assertOffsetAndToken(19, TokenType.DTDDoctypeName); // assertOffsetAndToken(14, TokenType.Whitespace); // assertOffsetAndToken(15, TokenType.DTDStartInternalSubset); @@ -41,21 +41,21 @@ public void testDocumentTypeExternalOnly() { assertOffsetAndToken(32, TokenType.Whitespace); assertOffsetAndToken(33, TokenType.DTDEntityValue); assertOffsetAndToken(41, TokenType.DTDEndTag); - assertOffsetAndToken(42, TokenType.Whitespace); + assertOffsetAndToken(42, TokenType.Content); assertOffsetAndToken(46, TokenType.DTDStartEntity); assertOffsetAndToken(54, TokenType.Whitespace); assertOffsetAndToken(55, TokenType.DTDEntityName); assertOffsetAndToken(61, TokenType.Whitespace); assertOffsetAndToken(62, TokenType.DTDEntityValue); assertOffsetAndToken(84, TokenType.DTDEndTag); - assertOffsetAndToken(85, TokenType.Whitespace); + assertOffsetAndToken(85, TokenType.Content); // assertOffsetAndToken(86, TokenType.DTDEndInternalSubset); // assertOffsetAndToken(87, TokenType.DTDEndDoctypeTag); } @Test - public void elementDeclWithServeralBraces() { + public void elementDeclWithSeveralBraces() { String dtd = ""; scanner = XMLScanner.createScanner(dtd, true); // assertOffsetAndToken(0, TokenType.DTDStartDoctypeTag); @@ -64,12 +64,13 @@ public void elementDeclWithServeralBraces() { // assertOffsetAndToken(14, TokenType.Whitespace); // assertOffsetAndToken(15, TokenType.DTDStartInternalSubset); // assertOffsetAndToken(16, TokenType.Whitespace); - assertOffsetAndToken(0, TokenType.DTDStartElementDecl); + assertOffsetAndToken(0, TokenType.DTDStartElement); assertOffsetAndToken(9, TokenType.Whitespace); assertOffsetAndToken(10, TokenType.DTDElementDeclName); assertOffsetAndToken(20, TokenType.Whitespace); assertOffsetAndToken(21, TokenType.DTDStartElementContent); - assertOffsetAndToken(22, TokenType.DTDEndElementContent); + assertOffsetAndToken(22, TokenType.DTDElementContent); + assertOffsetAndToken(61, TokenType.DTDEndElementContent); assertOffsetAndToken(62, TokenType.DTDEndTag); assertOffsetAndToken(63, TokenType.EOS); @@ -78,6 +79,651 @@ public void elementDeclWithServeralBraces() { } + @Test + public void notationDeclNormal() { + String dtd = ""; + scanner = XMLScanner.createScanner(dtd, true); + assertOffsetAndToken(0, TokenType.DTDStartNotation); + assertOffsetAndToken(10, TokenType.Whitespace); + assertOffsetAndToken(11, TokenType.DTDNotationName); + assertOffsetAndToken(14, TokenType.Whitespace); + assertOffsetAndToken(15, TokenType.DTDNotationKindPUBLIC); + assertOffsetAndToken(21, TokenType.Whitespace); + assertOffsetAndToken(22, TokenType.DTDNotationPublicId); + assertOffsetAndToken(31, TokenType.Whitespace); + assertOffsetAndToken(32, TokenType.DTDNotationSystemId); + assertOffsetAndToken(43, TokenType.DTDEndTag); + assertOffsetAndToken(44, TokenType.EOS); + } + + @Test + public void notationDeclMissingSystemId() { + String dtd = ""; + scanner = XMLScanner.createScanner(dtd, true); + assertOffsetAndToken(0, TokenType.DTDStartNotation); + assertOffsetAndToken(10, TokenType.Whitespace); + assertOffsetAndToken(11, TokenType.DTDNotationName); + assertOffsetAndToken(14, TokenType.Whitespace); + assertOffsetAndToken(15, TokenType.DTDNotationKindPUBLIC); + assertOffsetAndToken(21, TokenType.Whitespace); + assertOffsetAndToken(22, TokenType.DTDNotationPublicId); + assertOffsetAndToken(31, TokenType.DTDEndTag); + assertOffsetAndToken(32, TokenType.EOS); + } + + @Test + public void notationDeclMissingKind() { + String dtd = ""; + scanner = XMLScanner.createScanner(dtd, true); + assertOffsetAndToken(0, TokenType.DTDStartNotation); + assertOffsetAndToken(10, TokenType.Whitespace); + assertOffsetAndToken(11, TokenType.DTDNotationName); + assertOffsetAndToken(14, TokenType.Whitespace); + assertOffsetAndToken(15, TokenType.DTDUnrecognizedParameters); + assertOffsetAndToken(36, TokenType.DTDEndTag); + assertOffsetAndToken(37, TokenType.EOS); + } + + @Test + public void notationDeclIncorrectURLParameter() { + String dtd = ""; + scanner = XMLScanner.createScanner(dtd, true); + assertOffsetAndToken(0, TokenType.DTDStartNotation); + assertOffsetAndToken(10, TokenType.Whitespace); + assertOffsetAndToken(11, TokenType.DTDNotationName); + assertOffsetAndToken(14, TokenType.Whitespace); + assertOffsetAndToken(15, TokenType.DTDNotationKindPUBLIC); + assertOffsetAndToken(21, TokenType.Whitespace); + assertOffsetAndToken(22, TokenType.DTDUnrecognizedParameters); + assertOffsetAndToken(30, TokenType.DTDEndTag); + assertOffsetAndToken(31, TokenType.EOS); + } + + @Test + public void notationDeclUnclosed() { + String dtd = ""; + scanner = XMLScanner.createScanner(dtd, true); + assertOffsetAndToken(0, TokenType.DTDStartNotation); + assertOffsetAndToken(10, TokenType.Whitespace); + assertOffsetAndToken(11, TokenType.DTDNotationName); + assertOffsetAndToken(14, TokenType.Whitespace); + assertOffsetAndToken(15, TokenType.DTDNotationKindPUBLIC); + assertOffsetAndToken(21, TokenType.Whitespace); + assertOffsetAndToken(22, TokenType.DTDUnrecognizedParameters); + assertOffsetAndToken(30, TokenType.DTDStartElement); + assertOffsetAndToken(39, TokenType.DTDEndTag); + assertOffsetAndToken(40, TokenType.EOS); + } + + @Test + public void notationDeclUnclosed2() { + String dtd = ""; + scanner = XMLScanner.createScanner(dtd, true); + assertOffsetAndToken(0, TokenType.DTDStartNotation); + assertOffsetAndToken(10, TokenType.Whitespace); + assertOffsetAndToken(11, TokenType.DTDNotationName); + assertOffsetAndToken(14, TokenType.Whitespace); + assertOffsetAndToken(15, TokenType.DTDNotationKindPUBLIC); + assertOffsetAndToken(21, TokenType.Whitespace); + assertOffsetAndToken(22, TokenType.DTDStartElement); + assertOffsetAndToken(31, TokenType.DTDEndTag); + assertOffsetAndToken(32, TokenType.EOS); + } + + @Test + public void notationDeclUnclosed3() { + String dtd = ""; + scanner = XMLScanner.createScanner(dtd, true); + assertOffsetAndToken(0, TokenType.DTDStartNotation); + assertOffsetAndToken(10, TokenType.Whitespace); + assertOffsetAndToken(11, TokenType.DTDNotationName); + assertOffsetAndToken(14, TokenType.Whitespace); + assertOffsetAndToken(15, TokenType.DTDStartElement); + assertOffsetAndToken(24, TokenType.DTDEndTag); + assertOffsetAndToken(25, TokenType.EOS); + } + + @Test + public void notationDeclUnclosed4() { + String dtd = ""; + scanner = XMLScanner.createScanner(dtd, true); + assertOffsetAndToken(0, TokenType.DTDStartNotation); + assertOffsetAndToken(10, TokenType.Whitespace); + assertOffsetAndToken(11, TokenType.DTDNotationName); + assertOffsetAndToken(14, TokenType.Whitespace); + assertOffsetAndToken(15, TokenType.DTDNotationKindPUBLIC); + assertOffsetAndToken(21, TokenType.Whitespace); + assertOffsetAndToken(22, TokenType.DTDNotationPublicId); + assertOffsetAndToken(31, TokenType.Whitespace); + assertOffsetAndToken(32, TokenType.DTDNotationSystemId); + assertOffsetAndToken(43, TokenType.DTDStartElement); + assertOffsetAndToken(52, TokenType.DTDEndTag); + assertOffsetAndToken(53, TokenType.EOS); + } + + @Test + public void notationDeclNormalMoreSpaces() { + String dtd = ""; + scanner = XMLScanner.createScanner(dtd, true); + assertOffsetAndToken(0, TokenType.DTDStartNotation); + assertOffsetAndToken(10, TokenType.Whitespace); + assertOffsetAndToken(11, TokenType.DTDNotationName); + assertOffsetAndToken(14, TokenType.Whitespace); + assertOffsetAndToken(17, TokenType.DTDNotationKindPUBLIC); + assertOffsetAndToken(23, TokenType.Whitespace); + assertOffsetAndToken(24, TokenType.DTDNotationPublicId); + assertOffsetAndToken(33, TokenType.Whitespace); + assertOffsetAndToken(36, TokenType.DTDNotationSystemId); + assertOffsetAndToken(47, TokenType.Whitespace); + assertOffsetAndToken(48, TokenType.DTDEndTag); + assertOffsetAndToken(49, TokenType.EOS); + } + + @Test + public void notationDeclUnrecognizedContent() { + String dtd = ""; + scanner = XMLScanner.createScanner(dtd, true); + assertOffsetAndToken(0, TokenType.DTDStartNotation); + assertOffsetAndToken(10, TokenType.Whitespace); + assertOffsetAndToken(11, TokenType.DTDNotationName); + assertOffsetAndToken(14, TokenType.Whitespace); + assertOffsetAndToken(17, TokenType.DTDNotationKindPUBLIC); + assertOffsetAndToken(23, TokenType.Whitespace); + assertOffsetAndToken(24, TokenType.DTDNotationPublicId); + assertOffsetAndToken(33, TokenType.Whitespace); + assertOffsetAndToken(36, TokenType.DTDUnrecognizedParameters); + assertOffsetAndToken(38, TokenType.DTDEndTag); + assertOffsetAndToken(39, TokenType.EOS); + } + + @Test + public void notationNoParameters() { + String dtd = ""; + scanner = XMLScanner.createScanner(dtd, true); + assertOffsetAndToken(0, TokenType.DTDStartNotation); + assertOffsetAndToken(10, TokenType.Whitespace); + assertOffsetAndToken(11, TokenType.DTDStartElement); + assertOffsetAndToken(20, TokenType.Whitespace); + assertOffsetAndToken(21, TokenType.DTDEndTag); + assertOffsetAndToken(22, TokenType.EOS); + } + + @Test + public void elementDeclContent() { + String dtd = ""; + scanner = XMLScanner.createScanner(dtd, true); + assertOffsetAndToken(0, TokenType.DTDStartElement); + assertOffsetAndToken(9, TokenType.Whitespace); + assertOffsetAndToken(10, TokenType.DTDElementDeclName); + assertOffsetAndToken(14, TokenType.Whitespace); + assertOffsetAndToken(15, TokenType.DTDStartElementContent); + assertOffsetAndToken(16, TokenType.DTDElementContent); + assertOffsetAndToken(36, TokenType.DTDEndElementContent); + assertOffsetAndToken(37, TokenType.DTDEndTag); + assertOffsetAndToken(38, TokenType.EOS); + } + + @Test + public void elementOnlyName() { + String dtd = " "; + scanner = XMLScanner.createScanner(dtd, true); + assertOffsetAndToken(0, TokenType.DTDStartElement); + assertOffsetAndToken(9, TokenType.Whitespace); + assertOffsetAndToken(10, TokenType.DTDElementDeclName); + assertOffsetAndToken(14, TokenType.Whitespace); + assertOffsetAndToken(15, TokenType.DTDEndTag); + assertOffsetAndToken(16, TokenType.Content); + assertOffsetAndToken(17, TokenType.DTDStartEntity); + assertOffsetAndToken(25, TokenType.DTDEndTag); + assertOffsetAndToken(26, TokenType.EOS); + } + + @Test + public void elementUnclosed() { + String dtd = " "; + scanner = XMLScanner.createScanner(dtd, true); + assertOffsetAndToken(0, TokenType.DTDStartElement); + assertOffsetAndToken(9, TokenType.Whitespace); + assertOffsetAndToken(10, TokenType.DTDElementDeclName); + assertOffsetAndToken(14, TokenType.Whitespace); + assertOffsetAndToken(15, TokenType.DTDElementCategory); + assertOffsetAndToken(20, TokenType.DTDEndTag); + assertOffsetAndToken(21, TokenType.Content); + assertOffsetAndToken(22, TokenType.DTDStartEntity); + assertOffsetAndToken(30, TokenType.DTDEndTag); + assertOffsetAndToken(31, TokenType.EOS); + } + + @Test + public void elementDeclCategory() { + String dtd = ""; + scanner = XMLScanner.createScanner(dtd, true); + assertOffsetAndToken(0, TokenType.DTDStartElement); + assertOffsetAndToken(9, TokenType.Whitespace); + assertOffsetAndToken(10, TokenType.DTDElementDeclName); + assertOffsetAndToken(14, TokenType.Whitespace); + assertOffsetAndToken(15, TokenType.DTDElementCategory); + assertOffsetAndToken(18, TokenType.DTDEndTag); + assertOffsetAndToken(19, TokenType.EOS); + } + + @Test + public void elementDeclContentIncomplete() { + String dtd = ""; + scanner = XMLScanner.createScanner(dtd, true); + assertOffsetAndToken(0, TokenType.DTDStartElement); + assertOffsetAndToken(9, TokenType.Whitespace); + assertOffsetAndToken(10, TokenType.DTDElementDeclName); + assertOffsetAndToken(14, TokenType.Whitespace); + assertOffsetAndToken(15, TokenType.DTDStartElementContent); + assertOffsetAndToken(16, TokenType.DTDElementContent); + assertOffsetAndToken(32, TokenType.DTDEndTag); + assertOffsetAndToken(33, TokenType.EOS); + } + + @Test + public void elementDeclContentIncompleteAndUnclosed() { + String dtd = ""; + scanner = XMLScanner.createScanner(dtd, true); + assertOffsetAndToken(0, TokenType.DTDStartElement); + assertOffsetAndToken(9, TokenType.Whitespace); + assertOffsetAndToken(10, TokenType.DTDElementDeclName); + assertOffsetAndToken(14, TokenType.Whitespace); + assertOffsetAndToken(15, TokenType.DTDStartElementContent); + assertOffsetAndToken(16, TokenType.DTDElementContent); + assertOffsetAndToken(32, TokenType.DTDStartAttlist); + assertOffsetAndToken(41, TokenType.Whitespace); + assertOffsetAndToken(42, TokenType.DTDEndTag); + assertOffsetAndToken(43, TokenType.EOS); + } + + @Test + public void elementNoParameters() { + String dtd = ""; + scanner = XMLScanner.createScanner(dtd, true); + assertOffsetAndToken(0, TokenType.DTDStartElement); + assertOffsetAndToken(9, TokenType.Whitespace); + assertOffsetAndToken(12, TokenType.DTDStartAttlist); + assertOffsetAndToken(21, TokenType.Whitespace); + assertOffsetAndToken(22, TokenType.DTDEndTag); + assertOffsetAndToken(23, TokenType.EOS); + } + + @Test + public void attlistDecl() { + String dtd = ""; + scanner = XMLScanner.createScanner(dtd, true); + assertOffsetAndToken(0, TokenType.DTDStartAttlist); + assertOffsetAndToken(9, TokenType.Whitespace); + assertOffsetAndToken(10, TokenType.DTDAttlistElementName); + assertOffsetAndToken(16, TokenType.Whitespace); + assertOffsetAndToken(17, TokenType.DTDAttlistAttributeName); + assertOffsetAndToken(24, TokenType.Whitespace); + assertOffsetAndToken(25, TokenType.DTDAttlistAttributeType); + assertOffsetAndToken(30, TokenType.Whitespace); + assertOffsetAndToken(31, TokenType.DTDAttlistAttributeValue); + assertOffsetAndToken(43, TokenType.DTDEndTag); + assertOffsetAndToken(44, TokenType.EOS); + } + + @Test + public void attlistMultipleDecls() { + String dtd = + ""; + scanner = XMLScanner.createScanner(dtd, true); + assertOffsetAndToken(0, TokenType.DTDStartAttlist); + assertOffsetAndToken(9, TokenType.Whitespace); + assertOffsetAndToken(10, TokenType.DTDAttlistElementName); + assertOffsetAndToken(16, TokenType.Whitespace); + assertOffsetAndToken(22, TokenType.DTDAttlistAttributeName); + assertOffsetAndToken(30, TokenType.Whitespace); + assertOffsetAndToken(31, TokenType.DTDAttlistAttributeType); + assertOffsetAndToken(36, TokenType.Whitespace); + assertOffsetAndToken(37, TokenType.DTDAttlistAttributeValue); + assertOffsetAndToken(50, TokenType.Whitespace); + assertOffsetAndToken(55, TokenType.DTDAttlistAttributeName); + assertOffsetAndToken(63, TokenType.Whitespace); + assertOffsetAndToken(64, TokenType.DTDAttlistAttributeType); + assertOffsetAndToken(69, TokenType.Whitespace); + assertOffsetAndToken(70, TokenType.DTDAttlistAttributeValue); + assertOffsetAndToken(83, TokenType.DTDEndTag); + assertOffsetAndToken(84, TokenType.EOS); + } + + @Test + public void attlistIncompleteDecl() { + String dtd = + ""; + scanner = XMLScanner.createScanner(dtd, true); + assertOffsetAndToken(0, TokenType.DTDStartAttlist); + assertOffsetAndToken(9, TokenType.Whitespace); + assertOffsetAndToken(10, TokenType.DTDAttlistElementName); + assertOffsetAndToken(16, TokenType.Whitespace); + assertOffsetAndToken(22, TokenType.DTDAttlistAttributeName); + assertOffsetAndToken(30, TokenType.Whitespace); + assertOffsetAndToken(31, TokenType.DTDAttlistAttributeType); + assertOffsetAndToken(36, TokenType.Whitespace); + assertOffsetAndToken(42, TokenType.DTDUnrecognizedParameters); + assertOffsetAndToken(70, TokenType.DTDEndTag); + assertOffsetAndToken(71, TokenType.EOS); + } + + @Test + public void attlistMissingAttributeName() { + String dtd = + ""; + scanner = XMLScanner.createScanner(dtd, true); + assertOffsetAndToken(0, TokenType.DTDStartAttlist); + assertOffsetAndToken(9, TokenType.Whitespace); + assertOffsetAndToken(10, TokenType.DTDAttlistElementName); + assertOffsetAndToken(16, TokenType.Whitespace); + assertOffsetAndToken(17, TokenType.DTDAttlistAttributeName); + assertOffsetAndToken(22, TokenType.Whitespace); + assertOffsetAndToken(23, TokenType.DTDUnrecognizedParameters); + assertOffsetAndToken(31, TokenType.DTDEndTag); + assertOffsetAndToken(32, TokenType.EOS); + } + + @Test + public void attlistMissingAttributeType() { + String dtd = + ""; + scanner = XMLScanner.createScanner(dtd, true); + assertOffsetAndToken(0, TokenType.DTDStartAttlist); + assertOffsetAndToken(9, TokenType.Whitespace); + assertOffsetAndToken(10, TokenType.DTDAttlistElementName); + assertOffsetAndToken(16, TokenType.Whitespace); + assertOffsetAndToken(17, TokenType.DTDAttlistAttributeName); + assertOffsetAndToken(24, TokenType.Whitespace); + assertOffsetAndToken(25, TokenType.DTDUnrecognizedParameters); + assertOffsetAndToken(33, TokenType.DTDEndTag); + assertOffsetAndToken(34, TokenType.EOS); + } + + @Test + public void attlistMissingAttributeValue() { + String dtd = + ""; + scanner = XMLScanner.createScanner(dtd, true); + assertOffsetAndToken(0, TokenType.DTDStartAttlist); + assertOffsetAndToken(9, TokenType.Whitespace); + assertOffsetAndToken(10, TokenType.DTDAttlistElementName); + assertOffsetAndToken(16, TokenType.Whitespace); + assertOffsetAndToken(17, TokenType.DTDAttlistAttributeName); + assertOffsetAndToken(24, TokenType.Whitespace); + assertOffsetAndToken(25, TokenType.DTDAttlistAttributeType); + assertOffsetAndToken(30, TokenType.Whitespace); + assertOffsetAndToken(31, TokenType.DTDEndTag); + assertOffsetAndToken(32, TokenType.EOS); + } + + @Test + public void attlistNoParameters() { + String dtd = ""; + scanner = XMLScanner.createScanner(dtd, true); + assertOffsetAndToken(0, TokenType.DTDStartAttlist); + assertOffsetAndToken(9, TokenType.Whitespace); + assertOffsetAndToken(10, TokenType.DTDStartElement); + assertOffsetAndToken(19, TokenType.Whitespace); + assertOffsetAndToken(20, TokenType.DTDEndTag); + assertOffsetAndToken(21, TokenType.EOS); + } + + @Test + public void attlistMissingAttributeNameAndEndBracket() { + String dtd = + ""; + scanner = XMLScanner.createScanner(dtd, true); + assertOffsetAndToken(0, TokenType.DTDStartAttlist); + assertOffsetAndToken(9, TokenType.Whitespace); + assertOffsetAndToken(10, TokenType.DTDAttlistElementName); + assertOffsetAndToken(16, TokenType.Whitespace); + assertOffsetAndToken(17, TokenType.DTDAttlistAttributeName); + assertOffsetAndToken(24, TokenType.Whitespace); + assertOffsetAndToken(25, TokenType.DTDAttlistAttributeType); + assertOffsetAndToken(30, TokenType.Whitespace); + assertOffsetAndToken(31, TokenType.DTDAttlistAttributeValue); + assertOffsetAndToken(43, TokenType.Whitespace); + assertOffsetAndToken(44, TokenType.DTDStartElement); + assertOffsetAndToken(53, TokenType.DTDEndTag); + assertOffsetAndToken(54, TokenType.EOS); + } + + @Test + public void entityPUBLIC() { + String dtd = + ""; + scanner = XMLScanner.createScanner(dtd, true); + assertOffsetAndToken(0, TokenType.DTDStartEntity); + assertOffsetAndToken(8, TokenType.Whitespace); + assertOffsetAndToken(9, TokenType.DTDEntityName); + assertOffsetAndToken(14, TokenType.Whitespace); + assertOffsetAndToken(15, TokenType.DTDEntityKindPUBLIC); + assertOffsetAndToken(21, TokenType.Whitespace); + assertOffsetAndToken(22, TokenType.DTDEntityPublicId); + assertOffsetAndToken(33, TokenType.Whitespace); + assertOffsetAndToken(34, TokenType.DTDEntitySystemId); + assertOffsetAndToken(45, TokenType.Whitespace); + assertOffsetAndToken(46, TokenType.DTDEndTag); + assertOffsetAndToken(47, TokenType.EOS); + } + + @Test + public void entitySYSTEM() { + String dtd = + ""; + scanner = XMLScanner.createScanner(dtd, true); + assertOffsetAndToken(0, TokenType.DTDStartEntity); + assertOffsetAndToken(8, TokenType.Whitespace); + assertOffsetAndToken(9, TokenType.DTDEntityName); + assertOffsetAndToken(14, TokenType.Whitespace); + assertOffsetAndToken(15, TokenType.DTDEntityKindSYSTEM); + assertOffsetAndToken(21, TokenType.Whitespace); + assertOffsetAndToken(24, TokenType.DTDEntitySystemId); + assertOffsetAndToken(35, TokenType.Whitespace); + assertOffsetAndToken(36, TokenType.DTDEndTag); + assertOffsetAndToken(37, TokenType.EOS); + } + + @Test + public void entityCorrect() { + String dtd = + ""; + scanner = XMLScanner.createScanner(dtd, true); + assertOffsetAndToken(0, TokenType.DTDStartEntity); + assertOffsetAndToken(8, TokenType.Whitespace); + assertOffsetAndToken(9, TokenType.DTDEntityName); + assertOffsetAndToken(14, TokenType.Whitespace); + assertOffsetAndToken(15, TokenType.DTDEntityValue); + assertOffsetAndToken(23, TokenType.Whitespace); + assertOffsetAndToken(24, TokenType.DTDEndTag); + assertOffsetAndToken(25, TokenType.EOS); + } + + @Test + public void entityCorrectWithPercent() { + String dtd = + ""; + scanner = XMLScanner.createScanner(dtd, true); + assertOffsetAndToken(0, TokenType.DTDStartEntity); + assertOffsetAndToken(8, TokenType.Whitespace); + assertOffsetAndToken(9, TokenType.DTDEntityPercent); + assertOffsetAndToken(10, TokenType.Whitespace); + assertOffsetAndToken(11, TokenType.DTDEntityName); + assertOffsetAndToken(16, TokenType.Whitespace); + assertOffsetAndToken(17, TokenType.DTDEntityValue); + assertOffsetAndToken(25, TokenType.Whitespace); + assertOffsetAndToken(26, TokenType.DTDEndTag); + assertOffsetAndToken(27, TokenType.EOS); + } + + @Test + public void entityCorrectWithPercentAndPublic() { + String dtd = + ""; + scanner = XMLScanner.createScanner(dtd, true); + assertOffsetAndToken(0, TokenType.DTDStartEntity); + assertOffsetAndToken(8, TokenType.Whitespace); + assertOffsetAndToken(9, TokenType.DTDEntityPercent); + assertOffsetAndToken(10, TokenType.Whitespace); + assertOffsetAndToken(11, TokenType.DTDEntityName); + assertOffsetAndToken(16, TokenType.Whitespace); + assertOffsetAndToken(17, TokenType.DTDEntityKindPUBLIC); + assertOffsetAndToken(23, TokenType.Whitespace); + assertOffsetAndToken(24, TokenType.DTDEntityPublicId); + assertOffsetAndToken(34, TokenType.Whitespace); + assertOffsetAndToken(35, TokenType.DTDEntitySystemId); + assertOffsetAndToken(45, TokenType.Whitespace); + assertOffsetAndToken(46, TokenType.DTDEndTag); + assertOffsetAndToken(47, TokenType.EOS); + } + + @Test + public void entityIncorrectWithPercentAndPublic() { + String dtd = + ""; + scanner = XMLScanner.createScanner(dtd, true); + assertOffsetAndToken(0, TokenType.DTDStartEntity); + assertOffsetAndToken(8, TokenType.Whitespace); + assertOffsetAndToken(9, TokenType.DTDEntityPercent); + assertOffsetAndToken(10, TokenType.Whitespace); + assertOffsetAndToken(11, TokenType.DTDEntityName); + assertOffsetAndToken(16, TokenType.Whitespace); + assertOffsetAndToken(17, TokenType.DTDEntityKindPUBLIC); + assertOffsetAndToken(23, TokenType.Whitespace); + assertOffsetAndToken(24, TokenType.DTDEntityPublicId); + assertOffsetAndToken(34, TokenType.Whitespace); + assertOffsetAndToken(35, TokenType.DTDEntitySystemId); + assertOffsetAndToken(45, TokenType.Whitespace); + assertOffsetAndToken(46, TokenType.DTDUnrecognizedParameters); + assertOffsetAndToken(53, TokenType.DTDEndTag); + assertOffsetAndToken(54, TokenType.EOS); + } + + @Test + public void entityIncorrectMissingSystemId() { + String dtd = + ""; + scanner = XMLScanner.createScanner(dtd, true); + assertOffsetAndToken(0, TokenType.DTDStartEntity); + assertOffsetAndToken(8, TokenType.Whitespace); + assertOffsetAndToken(9, TokenType.DTDEntityName); + assertOffsetAndToken(14, TokenType.Whitespace); + assertOffsetAndToken(15, TokenType.DTDEntityKindPUBLIC); + assertOffsetAndToken(21, TokenType.Whitespace); + assertOffsetAndToken(22, TokenType.DTDEntityPublicId); + assertOffsetAndToken(32, TokenType.Whitespace); + assertOffsetAndToken(33, TokenType.DTDUnrecognizedParameters); + assertOffsetAndToken(35, TokenType.DTDEndTag); + assertOffsetAndToken(36, TokenType.EOS); + } + + @Test + public void entityIncorrectMissingSystemIdUnclosed() { + String dtd = + ""; + scanner = XMLScanner.createScanner(dtd, true); + assertOffsetAndToken(0, TokenType.DTDStartEntity); + assertOffsetAndToken(8, TokenType.Whitespace); + assertOffsetAndToken(9, TokenType.DTDEntityName); + assertOffsetAndToken(14, TokenType.Whitespace); + assertOffsetAndToken(15, TokenType.DTDEntityKindPUBLIC); + assertOffsetAndToken(21, TokenType.Whitespace); + assertOffsetAndToken(22, TokenType.DTDEntityPublicId); + assertOffsetAndToken(32, TokenType.Whitespace); + assertOffsetAndToken(33, TokenType.DTDStartElement); + assertOffsetAndToken(42, TokenType.DTDEndTag); + assertOffsetAndToken(43, TokenType.EOS); + } + + @Test + public void entityIncorrectMissingIDs() { + String dtd = + ""; + scanner = XMLScanner.createScanner(dtd, true); + assertOffsetAndToken(0, TokenType.DTDStartEntity); + assertOffsetAndToken(8, TokenType.Whitespace); + assertOffsetAndToken(9, TokenType.DTDEntityName); + assertOffsetAndToken(14, TokenType.Whitespace); + assertOffsetAndToken(15, TokenType.DTDEntityKindPUBLIC); + assertOffsetAndToken(21, TokenType.Whitespace); + assertOffsetAndToken(22, TokenType.DTDUnrecognizedParameters); + assertOffsetAndToken(24, TokenType.DTDEndTag); + assertOffsetAndToken(25, TokenType.EOS); + } + + @Test + public void entityIncorrect() { + String dtd = + ""; + scanner = XMLScanner.createScanner(dtd, true); + assertOffsetAndToken(0, TokenType.DTDStartEntity); + assertOffsetAndToken(8, TokenType.Whitespace); + assertOffsetAndToken(9, TokenType.DTDEntityName); + assertOffsetAndToken(14, TokenType.Whitespace); + assertOffsetAndToken(15, TokenType.DTDEntityKindPUBLIC); + assertOffsetAndToken(21, TokenType.Whitespace); + assertOffsetAndToken(22, TokenType.DTDUnrecognizedParameters); + assertOffsetAndToken(25, TokenType.DTDStartAttlist); + assertOffsetAndToken(34, TokenType.DTDEndTag); + assertOffsetAndToken(35, TokenType.EOS); + } + + + @Test + public void dtdUnrecognizedTagName() { + String dtd = + ""; + scanner = XMLScanner.createScanner(dtd, true); + assertOffsetAndToken(0, TokenType.Content); + assertOffsetAndToken(25, TokenType.EOS); + } + + @Test + public void dtdUnrecognizedTagName2() { + String dtd = + " "; + scanner = XMLScanner.createScanner(dtd, true); + assertOffsetAndToken(0, TokenType.Content); + assertOffsetAndToken(25, TokenType.Content); + assertOffsetAndToken(26, TokenType.DTDStartElement); + assertOffsetAndToken(35, TokenType.Whitespace); + assertOffsetAndToken(36, TokenType.DTDEndTag); + assertOffsetAndToken(37, TokenType.EOS); + } + + @Test + public void dtdUnrecognizedContent() { + String dtd = " aaa gf "; + + scanner = XMLScanner.createScanner(dtd, true); + + assertOffsetAndToken(0, TokenType.DTDStartElement); + assertOffsetAndToken(9, TokenType.DTDEndTag); + assertOffsetAndToken(10, TokenType.Content); + assertOffsetAndToken(22, TokenType.DTDStartAttlist); + assertOffsetAndToken(31, TokenType.DTDEndTag); + assertOffsetAndToken(32, TokenType.EOS); + } + public void assertOffsetAndToken(int tokenOffset, TokenType tokenType) { TokenType token = scanner.scan(); // System.err.println("assertOffsetAndToken(" + scanner.getTokenOffset() + ", TokenType." + scanner.getTokenType() + ");"); diff --git a/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/dom/parser/XMLScannerForInternalDTDTest.java b/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/dom/parser/XMLScannerForInternalDTDTest.java index 242bf93623..801a22679e 100644 --- a/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/dom/parser/XMLScannerForInternalDTDTest.java +++ b/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/dom/parser/XMLScannerForInternalDTDTest.java @@ -34,21 +34,21 @@ public void testDocumentTypeInternalOnly() { assertOffsetAndToken(10, TokenType.DTDDoctypeName); assertOffsetAndToken(14, TokenType.Whitespace); assertOffsetAndToken(15, TokenType.DTDStartInternalSubset); - assertOffsetAndToken(16, TokenType.Whitespace); + assertOffsetAndToken(16, TokenType.Content); assertOffsetAndToken(19, TokenType.DTDStartEntity); assertOffsetAndToken(27, TokenType.Whitespace); assertOffsetAndToken(28, TokenType.DTDEntityName); assertOffsetAndToken(32, TokenType.Whitespace); assertOffsetAndToken(33, TokenType.DTDEntityValue); assertOffsetAndToken(41, TokenType.DTDEndTag); - assertOffsetAndToken(42, TokenType.Whitespace); + assertOffsetAndToken(42, TokenType.Content); assertOffsetAndToken(46, TokenType.DTDStartEntity); assertOffsetAndToken(54, TokenType.Whitespace); assertOffsetAndToken(55, TokenType.DTDEntityName); assertOffsetAndToken(61, TokenType.Whitespace); assertOffsetAndToken(62, TokenType.DTDEntityValue); assertOffsetAndToken(84, TokenType.DTDEndTag); - assertOffsetAndToken(85, TokenType.Whitespace); + assertOffsetAndToken(85, TokenType.Content); assertOffsetAndToken(86, TokenType.DTDEndInternalSubset); assertOffsetAndToken(87, TokenType.DTDEndDoctypeTag); @@ -76,14 +76,14 @@ public void testDocumentTypePublicAndInternal() { assertOffsetAndToken(67, TokenType.DTDDoctypeSystemId); assertOffsetAndToken(124, TokenType.Whitespace); assertOffsetAndToken(127, TokenType.DTDStartInternalSubset); - assertOffsetAndToken(128, TokenType.Whitespace); + assertOffsetAndToken(128, TokenType.Content); assertOffsetAndToken(133, TokenType.DTDStartEntity); assertOffsetAndToken(141, TokenType.Whitespace); assertOffsetAndToken(142, TokenType.DTDEntityName); assertOffsetAndToken(146, TokenType.Whitespace); assertOffsetAndToken(147, TokenType.DTDEntityValue); assertOffsetAndToken(155, TokenType.DTDEndTag); - assertOffsetAndToken(156, TokenType.Whitespace); + assertOffsetAndToken(156, TokenType.Content); assertOffsetAndToken(160, TokenType.DTDEndInternalSubset); assertOffsetAndToken(161, TokenType.Whitespace); assertOffsetAndToken(162, TokenType.DTDEndDoctypeTag); @@ -109,15 +109,16 @@ public void testDocumentTypeSystemAndInternal() { assertOffsetAndToken(24, TokenType.DTDDoctypeSystemId); assertOffsetAndToken(81, TokenType.Whitespace); assertOffsetAndToken(84, TokenType.DTDStartInternalSubset); - assertOffsetAndToken(85, TokenType.Whitespace); - assertOffsetAndToken(90, TokenType.DTDStartElementDecl); + assertOffsetAndToken(85, TokenType.Content); + assertOffsetAndToken(90, TokenType.DTDStartElement); assertOffsetAndToken(99, TokenType.Whitespace); assertOffsetAndToken(100, TokenType.DTDElementDeclName); assertOffsetAndToken(104, TokenType.Whitespace); assertOffsetAndToken(105, TokenType.DTDStartElementContent); - assertOffsetAndToken(106, TokenType.DTDEndElementContent); + assertOffsetAndToken(106, TokenType.DTDElementContent); + assertOffsetAndToken(107, TokenType.DTDEndElementContent); assertOffsetAndToken(108, TokenType.DTDEndTag); - assertOffsetAndToken(109, TokenType.Whitespace); + assertOffsetAndToken(109, TokenType.Content); assertOffsetAndToken(113, TokenType.DTDEndInternalSubset); assertOffsetAndToken(114, TokenType.Whitespace); assertOffsetAndToken(115, TokenType.DTDEndDoctypeTag); @@ -143,18 +144,18 @@ public void testDocumentTypeSystemAndInternalAttlist() { assertOffsetAndToken(24, TokenType.DTDDoctypeSystemId); assertOffsetAndToken(81, TokenType.Whitespace); assertOffsetAndToken(84, TokenType.DTDStartInternalSubset); - assertOffsetAndToken(85, TokenType.Whitespace); - assertOffsetAndToken(90, TokenType.DTDStartAttlistDecl); + assertOffsetAndToken(85, TokenType.Content); + assertOffsetAndToken(90, TokenType.DTDStartAttlist); assertOffsetAndToken(99, TokenType.Whitespace); assertOffsetAndToken(100, TokenType.DTDAttlistElementName); assertOffsetAndToken(107, TokenType.Whitespace); assertOffsetAndToken(108, TokenType.DTDAttlistAttributeName); assertOffsetAndToken(112, TokenType.Whitespace); - assertOffsetAndToken(113, TokenType.DTDAttlistType); + assertOffsetAndToken(113, TokenType.DTDAttlistAttributeType); assertOffsetAndToken(118, TokenType.Whitespace); assertOffsetAndToken(119, TokenType.DTDAttlistAttributeValue); assertOffsetAndToken(127, TokenType.DTDEndTag); - assertOffsetAndToken(128, TokenType.Whitespace); + assertOffsetAndToken(128, TokenType.Content); assertOffsetAndToken(132, TokenType.DTDEndInternalSubset); assertOffsetAndToken(133, TokenType.Whitespace); assertOffsetAndToken(134, TokenType.DTDEndDoctypeTag); @@ -180,18 +181,18 @@ public void testDocumentTypeSystemAndInternalAttlist2() { assertOffsetAndToken(24, TokenType.DTDDoctypeSystemId); assertOffsetAndToken(81, TokenType.Whitespace); assertOffsetAndToken(84, TokenType.DTDStartInternalSubset); - assertOffsetAndToken(85, TokenType.Whitespace); - assertOffsetAndToken(90, TokenType.DTDStartAttlistDecl); + assertOffsetAndToken(85, TokenType.Content); + assertOffsetAndToken(90, TokenType.DTDStartAttlist); assertOffsetAndToken(99, TokenType.Whitespace); assertOffsetAndToken(100, TokenType.DTDAttlistElementName); assertOffsetAndToken(107, TokenType.Whitespace); assertOffsetAndToken(108, TokenType.DTDAttlistAttributeName); assertOffsetAndToken(112, TokenType.Whitespace); - assertOffsetAndToken(113, TokenType.DTDAttlistType); + assertOffsetAndToken(113, TokenType.DTDAttlistAttributeType); assertOffsetAndToken(127, TokenType.Whitespace); assertOffsetAndToken(128, TokenType.DTDAttlistAttributeValue); assertOffsetAndToken(135, TokenType.DTDEndTag); - assertOffsetAndToken(136, TokenType.Whitespace); + assertOffsetAndToken(136, TokenType.Content); assertOffsetAndToken(140, TokenType.DTDEndInternalSubset); assertOffsetAndToken(141, TokenType.Whitespace); assertOffsetAndToken(142, TokenType.DTDEndDoctypeTag); @@ -216,7 +217,7 @@ public void testDocumentTypeSystemAndEmptyInternalDTD() { assertOffsetAndToken(24, TokenType.DTDDoctypeSystemId); assertOffsetAndToken(81, TokenType.Whitespace); assertOffsetAndToken(84, TokenType.DTDStartInternalSubset); - assertOffsetAndToken(85, TokenType.Whitespace); + assertOffsetAndToken(85, TokenType.Content); assertOffsetAndToken(88, TokenType.DTDEndInternalSubset); assertOffsetAndToken(89, TokenType.Whitespace); assertOffsetAndToken(90, TokenType.DTDEndDoctypeTag); @@ -251,8 +252,8 @@ public void oneElementDeclNotClosed () { assertOffsetAndToken(10, TokenType.DTDDoctypeName); assertOffsetAndToken(13, TokenType.Whitespace); assertOffsetAndToken(14, TokenType.DTDStartInternalSubset); - assertOffsetAndToken(15, TokenType.Whitespace); - assertOffsetAndToken(17, TokenType.DTDStartElementDecl); + assertOffsetAndToken(15, TokenType.Content); + assertOffsetAndToken(17, TokenType.DTDStartElement); assertOffsetAndToken(26, TokenType.Whitespace); assertOffsetAndToken(27, TokenType.DTDElementDeclName); assertOffsetAndToken(28, TokenType.DTDEndInternalSubset); @@ -277,12 +278,12 @@ public void startWithElementDeclNotClosed () { assertOffsetAndToken(10, TokenType.DTDDoctypeName); assertOffsetAndToken(13, TokenType.Whitespace); assertOffsetAndToken(14, TokenType.DTDStartInternalSubset); - assertOffsetAndToken(15, TokenType.Whitespace); - assertOffsetAndToken(17, TokenType.DTDStartElementDecl); + assertOffsetAndToken(15, TokenType.Content); + assertOffsetAndToken(17, TokenType.DTDStartElement); assertOffsetAndToken(26, TokenType.Whitespace); assertOffsetAndToken(27, TokenType.DTDElementDeclName); assertOffsetAndToken(28, TokenType.Whitespace); - assertOffsetAndToken(30, TokenType.DTDStartElementDecl); + assertOffsetAndToken(30, TokenType.DTDStartElement); assertOffsetAndToken(39, TokenType.Whitespace); assertOffsetAndToken(40, TokenType.DTDElementDeclName); assertOffsetAndToken(41, TokenType.DTDEndInternalSubset); @@ -295,6 +296,139 @@ public void startWithElementDeclNotClosed () { assertOffsetAndToken(55, TokenType.EOS); } + @Test + public void startWithNotationDeclNotClosed () { + String xml = + ""; + scanner = XMLScanner.createScanner(xml); + assertOffsetAndToken(0, TokenType.DTDStartDoctypeTag); + assertOffsetAndToken(9, TokenType.Whitespace); + assertOffsetAndToken(10, TokenType.DTDDoctypeName); + assertOffsetAndToken(13, TokenType.Whitespace); + assertOffsetAndToken(14, TokenType.DTDStartInternalSubset); + assertOffsetAndToken(15, TokenType.Content); + assertOffsetAndToken(19, TokenType.DTDStartNotation); + assertOffsetAndToken(29, TokenType.Whitespace); + assertOffsetAndToken(30, TokenType.DTDNotationName); + assertOffsetAndToken(31, TokenType.Whitespace); + assertOffsetAndToken(33, TokenType.DTDEndInternalSubset); + assertOffsetAndToken(34, TokenType.Whitespace); + assertOffsetAndToken(36, TokenType.StartTagOpen); + assertOffsetAndToken(37, TokenType.StartTag); + assertOffsetAndToken(40, TokenType.Whitespace); + assertOffsetAndToken(41, TokenType.StartTagSelfClose); + assertOffsetAndToken(43, TokenType.EOS); + } + + @Test + public void startWithNotationDeclNotClosedWithContent () { + String xml = + ""; + scanner = XMLScanner.createScanner(xml); + assertOffsetAndToken(0, TokenType.DTDStartDoctypeTag); + assertOffsetAndToken(9, TokenType.Whitespace); + assertOffsetAndToken(10, TokenType.DTDDoctypeName); + assertOffsetAndToken(13, TokenType.Whitespace); + assertOffsetAndToken(14, TokenType.DTDStartInternalSubset); + assertOffsetAndToken(15, TokenType.Content); + assertOffsetAndToken(19, TokenType.DTDStartNotation); + assertOffsetAndToken(29, TokenType.Whitespace); + assertOffsetAndToken(30, TokenType.DTDNotationName); + assertOffsetAndToken(31, TokenType.Whitespace); + assertOffsetAndToken(33, TokenType.DTDEndInternalSubset); + assertOffsetAndToken(34, TokenType.Whitespace); + assertOffsetAndToken(35, TokenType.DTDUnrecognizedParameters); + assertOffsetAndToken(44, TokenType.StartTagOpen); + assertOffsetAndToken(45, TokenType.StartTag); + assertOffsetAndToken(48, TokenType.Whitespace); + assertOffsetAndToken(49, TokenType.StartTagSelfClose); + assertOffsetAndToken(51, TokenType.EOS); + } + + @Test + public void startWithEntityDeclNotClosedWithContent () { + String xml = + ""; + scanner = XMLScanner.createScanner(xml); + assertOffsetAndToken(0, TokenType.DTDStartDoctypeTag); + assertOffsetAndToken(9, TokenType.Whitespace); + assertOffsetAndToken(10, TokenType.DTDDoctypeName); + assertOffsetAndToken(13, TokenType.Whitespace); + assertOffsetAndToken(14, TokenType.DTDStartInternalSubset); + assertOffsetAndToken(15, TokenType.Content); + assertOffsetAndToken(19, TokenType.DTDStartEntity); + assertOffsetAndToken(27, TokenType.Whitespace); + assertOffsetAndToken(28, TokenType.DTDEntityName); + assertOffsetAndToken(29, TokenType.Whitespace); + assertOffsetAndToken(31, TokenType.DTDEndInternalSubset); + assertOffsetAndToken(32, TokenType.Whitespace); + assertOffsetAndToken(33, TokenType.DTDUnrecognizedParameters); + assertOffsetAndToken(42, TokenType.StartTagOpen); + assertOffsetAndToken(43, TokenType.StartTag); + assertOffsetAndToken(46, TokenType.Whitespace); + assertOffsetAndToken(47, TokenType.StartTagSelfClose); + assertOffsetAndToken(49, TokenType.EOS); + } + + @Test + public void startWithAttlistDeclNotClosed() { + String xml = + ""; + scanner = XMLScanner.createScanner(xml); + assertOffsetAndToken(0, TokenType.DTDStartDoctypeTag); + assertOffsetAndToken(9, TokenType.Whitespace); + assertOffsetAndToken(10, TokenType.DTDDoctypeName); + assertOffsetAndToken(13, TokenType.Whitespace); + assertOffsetAndToken(14, TokenType.DTDStartInternalSubset); + + assertOffsetAndToken(15, TokenType.Content); + assertOffsetAndToken(19, TokenType.DTDStartAttlist); + assertOffsetAndToken(28, TokenType.Whitespace); + + assertOffsetAndToken(31, TokenType.DTDEndInternalSubset); + assertOffsetAndToken(32, TokenType.Whitespace); + + assertOffsetAndToken(34, TokenType.StartTagOpen); + assertOffsetAndToken(35, TokenType.StartTag); + assertOffsetAndToken(38, TokenType.Whitespace); + assertOffsetAndToken(39, TokenType.StartTagSelfClose); + assertOffsetAndToken(41, TokenType.EOS); + } + + @Test + public void startWithAttlistDeclNotClosedAndMissingEndInternalSubset() { + String xml = + ""; + scanner = XMLScanner.createScanner(xml); + assertOffsetAndToken(0, TokenType.DTDStartDoctypeTag); + assertOffsetAndToken(9, TokenType.Whitespace); + assertOffsetAndToken(10, TokenType.DTDDoctypeName); + assertOffsetAndToken(13, TokenType.Whitespace); + assertOffsetAndToken(14, TokenType.DTDStartInternalSubset); + + assertOffsetAndToken(15, TokenType.Content); + assertOffsetAndToken(19, TokenType.DTDStartAttlist); + assertOffsetAndToken(28, TokenType.Whitespace); + + assertOffsetAndToken(33, TokenType.Content); + assertOffsetAndToken(40, TokenType.EOS); + } + public void assertOffsetAndToken(int tokenOffset, TokenType tokenType) { TokenType token = scanner.scan(); // System.err.println("assertOffsetAndToken(" + scanner.getTokenOffset() + ", TokenType." + scanner.getTokenType() + ");"); @@ -309,3 +443,4 @@ public void assertOffsetAndToken(int tokenOffset, TokenType tokenType, String to assertEquals(tokenText, scanner.getTokenText()); } } + diff --git a/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/services/XMLDocumentSymbolsTest.java b/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/services/XMLDocumentSymbolsTest.java index cc8aa89d55..a337de5528 100644 --- a/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/services/XMLDocumentSymbolsTest.java +++ b/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/services/XMLDocumentSymbolsTest.java @@ -30,7 +30,8 @@ public void externalDTD() { @Test public void internalDTD() { - String xml = "\r\n" + // + String xml = + "\r\n" + // "\r\n" + // " \r\n" + //