diff --git a/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/dom/SchemaLocation.java b/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/dom/SchemaLocation.java index 98939a8546..7c9179192e 100644 --- a/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/dom/SchemaLocation.java +++ b/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/dom/SchemaLocation.java @@ -12,40 +12,57 @@ */ package org.eclipse.lemminx.dom; +import java.util.Collection; import java.util.HashMap; import java.util.Map; -import java.util.StringTokenizer; +import java.util.regex.Matcher; +import java.util.regex.Pattern; /** - * + * * The declared "xsi:schemaLocation" */ public class SchemaLocation { - private final Map schemaLocationValuePairs; + private final Map schemaLocationValuePairs; private final DOMAttr attr; + // The text to match is of the form: + // https://www.w3schools.com note.xsd https://www.w3schools.com note.xsd + private static final Pattern SCHEMA_LOCATION_PAIR_PATTERN = Pattern.compile("([^\\s]+)\\s+([^\\s]+)\\s*"); + public SchemaLocation(String base, DOMAttr attr) { this.attr = attr; this.schemaLocationValuePairs = new HashMap<>(); String value = attr.getValue(); - StringTokenizer st = new StringTokenizer(value); - do { - String namespaceURI = st.hasMoreTokens() ? st.nextToken() : null; - String locationHint = st.hasMoreTokens() ? st.nextToken() : null; + Matcher locPairMatcher = SCHEMA_LOCATION_PAIR_PATTERN.matcher(value); + while (locPairMatcher.find()) { + String namespaceURI = locPairMatcher.group(1); + String locationHint = locPairMatcher.group(2); if (namespaceURI == null || locationHint == null) break; - schemaLocationValuePairs.put(namespaceURI, locationHint); - } while (true); + DOMNode valNode = attr.getNodeAttrValue(); + // matcher matches 1 char ahead, but valNode's start is at beginning of " + int start = valNode.getStart() + locPairMatcher.start(2); + // matcher matches end correctly, but range needs to be one past end + // to highlight the end, and one to make up for " + int end = valNode.getStart() + locPairMatcher.end(2) + 2; + schemaLocationValuePairs.put(namespaceURI, + new SchemaLocationHint(start, end, locationHint, attr.getOwnerDocument())); + } } public String getLocationHint(String namespaceURI) { - return schemaLocationValuePairs.get(namespaceURI); + return schemaLocationValuePairs.get(namespaceURI).getHint(); } public DOMAttr getAttr() { return attr; } + public Collection getSchemaLocationHints() { + return schemaLocationValuePairs.values(); + } + } diff --git a/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/dom/SchemaLocationHint.java b/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/dom/SchemaLocationHint.java new file mode 100644 index 0000000000..21fb1b3936 --- /dev/null +++ b/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/dom/SchemaLocationHint.java @@ -0,0 +1,58 @@ +/** + * Copyright (c) 2018 Red Hat Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v2.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat Inc. - initial API and implementation + */ +package org.eclipse.lemminx.dom; + +public class SchemaLocationHint implements DOMRange { + + private final int start, end; + + private final String hint; + + private final DOMDocument document; + + public SchemaLocationHint(int start, int end, String hint, DOMDocument document) { + this.start = start; + this.end = end; + this.hint = hint; + this.document = document; + } + + /** + * Get the loation hint that was assigned to this + */ + public String getHint() { + return this.hint; + } + + /** + * Get the start character of this SchemaLocationHint in the document. + */ + @Override + public int getStart() { + return this.start; + } + + /** + * Get the end character of this SchemaLocationHint in the document. + */ + @Override + public int getEnd() { + return this.end; + } + + @Override + public DOMDocument getOwnerDocument() { + return document; + } + +} \ No newline at end of file diff --git a/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/extensions/contentmodel/participants/ContentModelDocumentLinkParticipant.java b/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/extensions/contentmodel/participants/ContentModelDocumentLinkParticipant.java index ce3392d9d2..5a4a924eb4 100644 --- a/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/extensions/contentmodel/participants/ContentModelDocumentLinkParticipant.java +++ b/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/extensions/contentmodel/participants/ContentModelDocumentLinkParticipant.java @@ -14,6 +14,7 @@ import static org.eclipse.lemminx.utils.XMLPositionUtility.createDocumentLink; +import java.util.Collection; import java.util.List; import org.apache.xerces.impl.XMLEntityManager; @@ -23,18 +24,21 @@ import org.eclipse.lemminx.dom.DOMDocumentType; import org.eclipse.lemminx.dom.DOMRange; import org.eclipse.lemminx.dom.NoNamespaceSchemaLocation; +import org.eclipse.lemminx.dom.SchemaLocation; +import org.eclipse.lemminx.dom.SchemaLocationHint; import org.eclipse.lemminx.dom.XMLModel; import org.eclipse.lemminx.services.extensions.IDocumentLinkParticipant; import org.eclipse.lsp4j.DocumentLink; /** * Document link for : - * + * *
    *
  • XML Schema xsi:noNamespaceSchemaLocation
  • *
  • DTD SYSTEM (ex : + *
  • XML Schema xsi:schemaLocation
  • *
- * + * * @author Angelo ZERR * */ @@ -88,11 +92,27 @@ public void findDocumentLinks(DOMDocument document, List links) { } } } + // Doc link for xsi:schemaLocation + SchemaLocation schemaLocation = document.getSchemaLocation(); + if (schemaLocation != null) { + try { + Collection schemaLocationHints = schemaLocation.getSchemaLocationHints(); + String location; + for (SchemaLocationHint schemaLocationHint : schemaLocationHints) { + location = getResolvedLocation(document.getDocumentURI(), schemaLocationHint.getHint()); + if (location != null) { + links.add(createDocumentLink(schemaLocationHint, location)); + } + } + } catch (BadLocationException e) { + // Do nothing + } + } } /** * Returns the expanded system location - * + * * @return the expanded system location */ private static String getResolvedLocation(String documentURI, String location) {