Skip to content

Commit

Permalink
Improved namespace renaming for XML/XSD documents
Browse files Browse the repository at this point in the history
Fixes eclipse-lemminx#366

Can rename namespace declaration and all will change, renaming element with namespace does not wipe
namespace, attribute values referencing a namespace will update if necessary

Signed-off-by: Nikolas <nikolaskomonen@gmail.com>
  • Loading branch information
angelozerr authored and NikolasKomonen committed May 29, 2019
1 parent f9d5253 commit bc45fa5
Show file tree
Hide file tree
Showing 13 changed files with 534 additions and 122 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ public class DOMAttr extends DOMNode implements org.w3c.dom.Attr {

private boolean hasDelimiter; // has '='

public static final String XMLNS_ATTR = "xmlns";
public static final String XMLNS_NO_DEFAULT_ATTR = "xmlns:";

class AttrNameOrValue extends DOMNode {

private final DOMAttr ownerAttr;
Expand Down Expand Up @@ -100,6 +103,15 @@ public String getName() {
return name;
}

@Override
public String getLocalName() {
int colonIndex = name.indexOf(":");
if(colonIndex > 0) {
return name.substring(colonIndex + 1);
}
return name;
}

/*
* (non-Javadoc)
*
Expand Down Expand Up @@ -238,6 +250,56 @@ public void setNodeAttrValue(DOMNode nodeAttrValue) {
public boolean valueContainsOffset(int offset) {
return nodeAttrValue != null && offset >= nodeAttrValue.getStart() && offset < nodeAttrValue.getEnd();
}

/**
* Returns true if attribute name is a xmlns attribute and false otherwise.
*
* @param attributeName
* @return true if attribute name is a xmlns attribute and false otherwise.
*/
public boolean isXmlns() {
return name.startsWith(XMLNS_ATTR);
}

/**
* Returns true if attribute name is the default xmlns attribute and false
* otherwise.
*
* @param attributeName
* @return true if attribute name is the default xmlns attribute and false
* otherwise.
*/
public boolean isDefaultXmlns() {
return name.equals(XMLNS_ATTR);
}

public String extractPrefixFromXmlns() {
if (isDefaultXmlns()) {
return name.substring(XMLNS_ATTR.length(), name.length());
}
return name.substring(XMLNS_NO_DEFAULT_ATTR.length(), name.length());
}

/**
* Returns the prefix if the given URI matches this attributes value.
*
* If the URI doesnt match, null is returned.
* @param uri
* @return
*/
public String getPrefixIfMatchesURI(String uri) {
if (isXmlns()) {
if (quotelessValue != null && quotelessValue.equals(uri)) {
if (isDefaultXmlns()) {
// xmlns="http://"
return null;
}
// xmlns:xxx="http://"
return extractPrefixFromXmlns();
}
}
return null;
}

/*
* (non-Javadoc)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
*/
package org.eclipse.lsp4xml.dom;

import static org.eclipse.lsp4xml.dom.DOMAttr.XMLNS_ATTR;
import static org.eclipse.lsp4xml.dom.DOMAttr.XMLNS_NO_DEFAULT_ATTR;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
Expand All @@ -25,8 +28,7 @@
*/
public class DOMElement extends DOMNode implements org.w3c.dom.Element {

private static final String XMLNS_ATTR = "xmlns";
private static final String XMLNS_NO_DEFAULT_ATTR = "xmlns:";


String tag;
boolean selfClosed;
Expand Down Expand Up @@ -148,20 +150,15 @@ public Collection<String> getAllPrefixes() {
for (DOMAttr attr : getAttributeNodes()) {
String attributeName = attr.getName();
if (isNoDefaultXmlns(attributeName)) {
prefixes.add(extractPrefixFromXmlns(attributeName));
prefixes.add(attr.extractPrefixFromXmlns());
}
}
return prefixes;
}
return Collections.emptyList();
}

private static String extractPrefixFromXmlns(String attributeName) {
if (isDefaultXmlns(attributeName)) {
return attributeName.substring(XMLNS_ATTR.length(), attributeName.length());
}
return attributeName.substring(XMLNS_NO_DEFAULT_ATTR.length(), attributeName.length());
}


/**
* Returns the xmlns prefix from the given namespave URI and null otherwise.
Expand All @@ -175,17 +172,9 @@ public String getPrefix(String namespaceURI) {
}
if (hasAttributes()) {
for (DOMAttr attr : getAttributeNodes()) {
String attributeName = attr.getName();
if (isXmlns(attributeName)) {
String namespace = attr.getValue();
if (namespace != null && namespace.equals(namespaceURI)) {
if (isDefaultXmlns(attributeName)) {
// xmlns="http://"
return "";
}
// xmlns:xxx="http://"
return extractPrefixFromXmlns(attributeName);
}
String prefix = attr.getPrefixIfMatchesURI(namespaceURI);
if(prefix != null) {
return prefix;
}
}
}
Expand All @@ -204,27 +193,7 @@ public String getPrefix(String namespaceURI) {
return null;
}

/**
* Returns true if attribute name is a xmlns attribute and false otherwise.
*
* @param attributeName
* @return true if attribute name is a xmlns attribute and false otherwise.
*/
private static boolean isXmlns(String attributeName) {
return attributeName.startsWith(XMLNS_ATTR);
}

/**
* Returns true if attribute name is the default xmlns attribute and false
* otherwise.
*
* @param attributeName
* @return true if attribute name is the default xmlns attribute and false
* otherwise.
*/
private static boolean isDefaultXmlns(String attributeName) {
return attributeName.equals(XMLNS_ATTR);
}


/**
* Returns true if attribute name is the no default xmlns attribute and false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@
*/
package org.eclipse.lsp4xml.extensions.contentmodel.participants;

import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collection;

import org.eclipse.lsp4j.CompletionItem;
Expand All @@ -33,7 +31,6 @@
import org.eclipse.lsp4xml.services.extensions.ICompletionResponse;
import org.eclipse.lsp4xml.settings.SharedSettings;
import org.eclipse.lsp4xml.uriresolver.CacheResourceDownloadingException;
import org.eclipse.lsp4xml.utils.StringUtils;

/**
* Extension to support XML completion based on content model (XML Schema
Expand Down Expand Up @@ -112,27 +109,9 @@ private void fillWithChildrenElementDeclaration(DOMElement element, Collection<C
CompletionItem item = new CompletionItem(label);
item.setFilterText(request.getFilterForStartTagName(label));
item.setKind(CompletionItemKind.Property);
StringBuilder sb = new StringBuilder();
String documentation;
String tempDoc = child.getDocumentation();
boolean tempDocHasContent = !StringUtils.isEmpty(tempDoc);
if(tempDocHasContent) {
sb.append(tempDoc);
}

if(schemaURI != null) {
if(tempDocHasContent) {
String lineSeparator = System.getProperty("line.separator");
sb.append(lineSeparator);
sb.append(lineSeparator);
}
Path schemaPath = Paths.get(schemaURI);
sb.append("Source: ");
sb.append(schemaPath.getFileName().toString());
}
documentation = sb.toString();
if (documentation != null && !documentation.isEmpty()) {
item.setDetail(documentation);
String detail = XMLGenerator.generateDocumentation(child.getDocumentation(), schemaURI);
if (detail != null) {
item.setDetail(detail);
}
String xml = generator.generate(child, prefix);
item.setTextEdit(new TextEdit(request.getReplaceRange(), xml));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
*/
package org.eclipse.lsp4xml.extensions.contentmodel.utils;

import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
Expand All @@ -19,6 +21,7 @@
import org.eclipse.lsp4xml.extensions.contentmodel.model.CMElementDeclaration;
import org.eclipse.lsp4xml.settings.SharedSettings;
import org.eclipse.lsp4xml.settings.XMLFormattingOptions;
import org.eclipse.lsp4xml.utils.StringUtils;
import org.eclipse.lsp4xml.utils.XMLBuilder;

/**
Expand Down Expand Up @@ -214,4 +217,35 @@ public static String generateAttributeValue(String defaultValue, Collection<Stri
return value.toString();
}

/**
* Returns a properly formatted documentation string with source.
*
* If there is no content then null is returned.
* @param documentation
* @param schemaURI
* @return
*/
public static String generateDocumentation(String documentation, String schemaURI) {
StringBuilder sb = new StringBuilder();
boolean tempDocHasContent = !StringUtils.isEmpty(documentation);
if(tempDocHasContent) {
sb.append(documentation);
}

if(schemaURI != null) {
if(tempDocHasContent) {
String lineSeparator = System.getProperty("line.separator");
sb.append(lineSeparator);
sb.append(lineSeparator);
}

sb.append("Source: ");

Path schemaPath = Paths.get(schemaURI);
sb.append(schemaPath.getFileName().toString());
}
String finalDocumentation = sb.toString();
return !finalDocumentation.isEmpty() ? finalDocumentation : null;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ public class CMDTDDocument extends XMLDTDLoader implements CMDocument {
private Set<String> hierarchies;
private String uri;


public CMDTDDocument() {}

public CMDTDDocument(String uri) {
Expand All @@ -68,11 +67,12 @@ public Collection<CMElementDeclaration> getElements() {
return elements;
}

@Override

/**
* Returns the URI of this document, is none was provided this
* returns null.
*/
@Override
public String getURI() {
return uri;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,7 @@ public CMDocument createCMDocument(String key) {
XSModel model = getLoader().loadURI(key);
if (model != null) {
// XML Schema can be loaded
CMXSDDocument document = new CMXSDDocument(model, key);
return document;
return new CMXSDDocument(model, key);
}
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,7 @@ public CMXSDDocument(XSModel model) {
}

public CMXSDDocument(XSModel model, String uri) {
this.model = model;
this.elementMappings = new HashMap<>();
this(model);
this.uri = uri;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
*/
package org.eclipse.lsp4xml.services;

import static org.eclipse.lsp4xml.utils.XMLPositionUtility.covers;
import static org.eclipse.lsp4xml.utils.XMLPositionUtility.doesTagCoverPosition;
import static org.eclipse.lsp4xml.utils.XMLPositionUtility.getTagNameRange;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
Expand All @@ -24,11 +28,8 @@
import org.eclipse.lsp4xml.dom.DOMDocument;
import org.eclipse.lsp4xml.dom.DOMElement;
import org.eclipse.lsp4xml.dom.DOMNode;
import org.eclipse.lsp4xml.dom.parser.Scanner;
import org.eclipse.lsp4xml.dom.parser.TokenType;
import org.eclipse.lsp4xml.dom.parser.XMLScanner;
import org.eclipse.lsp4xml.services.extensions.XMLExtensionsRegistry;

/**
* XML highlighting support.
*
Expand Down Expand Up @@ -91,11 +92,6 @@ public List<DocumentHighlight> findDocumentHighlights(DOMDocument xmlDocument, P
return Collections.emptyList();
}

private static boolean doesTagCoverPosition(Range startTagRange, Range endTagRange, Position position) {
return startTagRange != null && covers(startTagRange, position)
|| endTagRange != null && covers(endTagRange, position);
}

private static List<DocumentHighlight> getHighlightsList(Range startTagRange, Range endTagRange) {

List<DocumentHighlight> result = new ArrayList<>(2);
Expand All @@ -108,34 +104,4 @@ private static List<DocumentHighlight> getHighlightsList(Range startTagRange, Ra
return result;
}

private static boolean isBeforeOrEqual(Position pos1, Position pos2) {
return pos1.getLine() < pos2.getLine()
|| (pos1.getLine() == pos2.getLine() && pos1.getCharacter() <= pos2.getCharacter());
}

private static boolean covers(Range range, Position position) {
return isBeforeOrEqual(range.getStart(), position) && isBeforeOrEqual(position, range.getEnd());
}

private static Range getTagNameRange(TokenType tokenType, int startOffset, DOMDocument xmlDocument) {

Scanner scanner = XMLScanner.createScanner(xmlDocument.getText(), startOffset);

TokenType token = scanner.scan();
while (token != TokenType.EOS && token != tokenType) {
token = scanner.scan();
}
if (token != TokenType.EOS) {
try {
return new Range(xmlDocument.positionAt(scanner.getTokenOffset()),
xmlDocument.positionAt(scanner.getTokenEnd()));
} catch (BadLocationException e) {
LOGGER.log(Level.SEVERE,
"While creating Range in XMLHighlighting the Scanner's Offset was a BadLocation", e);
return null;
}
}
return null;
}

}
Loading

0 comments on commit bc45fa5

Please sign in to comment.