Skip to content
This repository has been archived by the owner on Mar 1, 2024. It is now read-only.

Added document link for included schemas in .xsd #54

Merged
merged 1 commit into from
May 28, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,14 @@
import org.eclipse.lemminx.extensions.xsd.participants.XSDCodeLensParticipant;
import org.eclipse.lemminx.extensions.xsd.participants.XSDCompletionParticipant;
import org.eclipse.lemminx.extensions.xsd.participants.XSDDefinitionParticipant;
import org.eclipse.lemminx.extensions.xsd.participants.XSDDocumentLinkParticipant;
import org.eclipse.lemminx.extensions.xsd.participants.XSDHighlightingParticipant;
import org.eclipse.lemminx.extensions.xsd.participants.XSDReferenceParticipant;
import org.eclipse.lemminx.extensions.xsd.participants.XSDRenameParticipant;
import org.eclipse.lemminx.extensions.xsd.participants.diagnostics.XSDDiagnosticsParticipant;
import org.eclipse.lemminx.services.extensions.ICompletionParticipant;
import org.eclipse.lemminx.services.extensions.IDefinitionParticipant;
import org.eclipse.lemminx.services.extensions.IDocumentLinkParticipant;
import org.eclipse.lemminx.services.extensions.IHighlightingParticipant;
import org.eclipse.lemminx.services.extensions.IReferenceParticipant;
import org.eclipse.lemminx.services.extensions.IRenameParticipant;
Expand All @@ -51,6 +53,7 @@ public class XSDPlugin implements IXMLExtension {
private final ICodeLensParticipant codeLensParticipant;
private final IHighlightingParticipant highlightingParticipant;
private final IRenameParticipant renameParticipant;
private final IDocumentLinkParticipant documentLinkParticipant;
private XSDURIResolverExtension uiResolver;

private ContentModelManager modelManager;
Expand All @@ -63,6 +66,7 @@ public XSDPlugin() {
codeLensParticipant = new XSDCodeLensParticipant();
highlightingParticipant = new XSDHighlightingParticipant();
renameParticipant = new XSDRenameParticipant();
documentLinkParticipant = new XSDDocumentLinkParticipant();
}

@Override
Expand Down Expand Up @@ -94,6 +98,7 @@ public void start(InitializeParams params, XMLExtensionsRegistry registry) {
registry.registerCodeLensParticipant(codeLensParticipant);
registry.registerHighlightingParticipant(highlightingParticipant);
registry.registerRenameParticipant(renameParticipant);
registry.registerDocumentLinkParticipant(documentLinkParticipant);
}

@Override
Expand All @@ -106,5 +111,6 @@ public void stop(XMLExtensionsRegistry registry) {
registry.unregisterCodeLensParticipant(codeLensParticipant);
registry.unregisterHighlightingParticipant(highlightingParticipant);
registry.unregisterRenameParticipant(renameParticipant);
registry.unregisterDocumentLinkParticipant(documentLinkParticipant);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/**
* Copyright (c) 2020 Red Hat Inc. and others.
* All rights reserved. This program and the accompanying materials
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*
* Contributors:
* Red Hat Inc. - initial API and implementation
*/
package org.eclipse.lemminx.extensions.xsd.participants;

import static org.eclipse.lemminx.utils.XMLPositionUtility.createDocumentLink;

import java.util.List;
import java.util.Objects;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.apache.xerces.impl.XMLEntityManager;
import org.apache.xerces.util.URI.MalformedURIException;
import org.eclipse.lemminx.commons.BadLocationException;
import org.eclipse.lemminx.dom.DOMAttr;
import org.eclipse.lemminx.dom.DOMDocument;
import org.eclipse.lemminx.dom.DOMElement;
import org.eclipse.lemminx.dom.DOMNode;
import org.eclipse.lemminx.dom.DOMRange;
import org.eclipse.lemminx.extensions.xsd.utils.XSDUtils;
import org.eclipse.lemminx.services.extensions.IDocumentLinkParticipant;
import org.eclipse.lemminx.utils.StringUtils;
import org.eclipse.lsp4j.DocumentLink;
import org.w3c.dom.Element;

/**
*
* Implements document links in .xsd files for
* <ul>
* <li>xs:include schemaLocation</li>
* </ul>
*
*/
public class XSDDocumentLinkParticipant implements IDocumentLinkParticipant {

private static final Logger LOGGER = Logger.getLogger(XSDDocumentLinkParticipant.class.getName());

@Override
public void findDocumentLinks(DOMDocument document, List<DocumentLink> links) {
DOMElement root = document.getDocumentElement();
if (root == null || !XSDUtils.isXSSchema(root)) {
return;
}
String xmlSchemaPrefix = root.getPrefix();
List<DOMNode> children = root.getChildren();
for (DOMNode child : children) {
if (child.isElement() && XSDUtils.isXSInclude((Element) child)
&& Objects.equals(child.getPrefix(), xmlSchemaPrefix)) {
DOMElement includeElement = (DOMElement) child;
DOMAttr schemaLocationAttr = XSDUtils.getSchemaLocation(includeElement);
if (schemaLocationAttr != null && !StringUtils.isEmpty(schemaLocationAttr.getValue())) {
String location = getResolvedLocation(document.getDocumentURI(), schemaLocationAttr.getValue());
DOMRange schemaLocationRange = schemaLocationAttr.getNodeAttrValue();
try {
links.add(createDocumentLink(schemaLocationRange, location));
} catch (BadLocationException e) {
LOGGER.log(Level.SEVERE, "Creation of document link failed", e);
}
}
}
}
}

private static String getResolvedLocation(String documentURI, String location) {
if (location == null) {
return null;
}
try {
return XMLEntityManager.expandSystemId(location, documentURI, false);
} catch (MalformedURIException e) {
return location;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
import java.util.Vector;
import java.util.function.BiConsumer;

import com.google.common.base.Objects;

import org.apache.xerces.impl.xs.SchemaGrammar;
import org.apache.xerces.xs.StringList;
import org.eclipse.lemminx.dom.DOMAttr;
Expand All @@ -37,8 +39,6 @@
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.google.common.base.Objects;

/**
* XSD utilities.
*
Expand Down Expand Up @@ -404,6 +404,10 @@ public static boolean isXSAttribute(DOMElement element) {
return "attribute".equals(element.getLocalName());
}

public static boolean isXSSchema(Element element) {
return "schema".equals(element.getLocalName());
}

public static FilesChangedTracker createFilesChangedTracker(SchemaGrammar grammar) {
return createFilesChangedTracker(Collections.singleton(grammar));
}
Expand Down Expand Up @@ -444,4 +448,11 @@ private static void updateTracker(SchemaGrammar grammar, Set<SchemaGrammar> trac
}
}
}

public static DOMAttr getSchemaLocation(DOMElement includeElement) {
if (!isXSInclude(includeElement)) {
return null;
}
return includeElement.getAttributeNode("schemaLocation");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/**
* Copyright (c) 2020 Red Hat Inc. and others.
* All rights reserved. This program and the accompanying materials
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*
* Contributors:
* Red Hat Inc. - initial API and implementation
*/
package org.eclipse.lemminx.extensions.xsd;

import static org.eclipse.lemminx.XMLAssert.dl;
import static org.eclipse.lemminx.XMLAssert.r;

import org.eclipse.lemminx.XMLAssert;
import org.eclipse.lemminx.commons.BadLocationException;
import org.junit.jupiter.api.Test;

/**
* Tests for the docuement links in .xsd provided by <code>XSDDocumentLinkParticipant</code>
*
* @see org.eclipse.lemminx.extensions.xsd.participants.XSDDocumentLinkParticipant
*/
public class XSDDocumentLinkingExtensionsTest {

@Test
public void xsIncludeUsualNamespace() throws BadLocationException {
String xml = "<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\">\n" + //
" <xs:include schemaLocation=\"choice.xsd\"></xs:include>\n" + //
" <xs:element name=\"int\">\n" + //
" <xs:simpleType>\n" + //
" <xs:restriction base=\"xs:integer\"/>\n" + //
" </xs:simpleType>\n" + //
" </xs:element>\n" + //
"</xs:schema>";
XMLAssert.testDocumentLinkFor(xml, "src/test/resources/xsd/unnamed-integer.xsd",
dl(r(1, 32, 1, 42), "src/test/resources/xsd/choice.xsd"));
}

@Test
public void xsIncludeDifferentNamespace() throws BadLocationException {
String xml = "<schemanamespace:schema xmlns:schemanamespace=\"http://www.w3.org/2001/XMLSchema\">\n" + //
" <schemanamespace:include schemaLocation=\"choice.xsd\"></schemanamespace:include>\n" + //
" <schemanamespace:element name=\"int\">\n" + //
" <schemanamespace:simpleType>\n" + //
" <schemanamespace:restriction base=\"schemanamespace:integer\"/>\n" + //
" </schemanamespace:simpleType>\n" + //
" </schemanamespace:element>\n" + //
"</schemanamespace:schema>";
XMLAssert.testDocumentLinkFor(xml, "src/test/resources/xsd/unnamed-integer.xsd",
dl(r(1, 45, 1, 55), "src/test/resources/xsd/choice.xsd"));
}

@Test
public void xsIncludeEmptySchemaLocation() throws BadLocationException {
String xml = "<xs:schema xmlns:xs=\"http://example.org\">\n" + //
" <xs:include schemaLocation=\"\"></xs:include>\n" + //
" <xs:element name=\"int\">\n" + //
" <xs:simpleType>\n" + //
" <xs:restriction base=\"xs:integer\"/>\n" + //
" </xs:simpleType>\n" + //
" </xs:element>\n" + //
"</xs:schema>";
XMLAssert.testDocumentLinkFor(xml, "src/test/resources/xsd/unnamed-integer.xsd");
}

@Test
public void xsIncludeManyOccurences() throws BadLocationException {
String xml = "<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\">\n" + //
" <xs:include schemaLocation=\"choice.xsd\"></xs:include>\n" + //
" <xs:include schemaLocation=\"pattern.xsd\"></xs:include>\n" + //
" <xs:element name=\"int\">\n" + //
" <xs:simpleType>\n" + //
" <xs:restriction base=\"xs:integer\"/>\n" + //
" </xs:simpleType>\n" + //
" </xs:element>\n" + //
"</xs:schema>";
XMLAssert.testDocumentLinkFor(xml, "src/test/resources/xsd/unnamed-integer.xsd",
dl(r(1, 32, 1, 42), "src/test/resources/xsd/choice.xsd"),
dl(r(2, 32, 2, 43), "src/test/resources/xsd/pattern.xsd"));
}

@Test
public void xsIncludeNoSchemaLocation() throws BadLocationException {
String xml = "<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\">\n" + //
" <xs:include />\n" + //
" <xs:element name=\"int\">\n" + //
" <xs:simpleType>\n" + //
" <xs:restriction base=\"xs:integer\"/>\n" + //
" </xs:simpleType>\n" + //
" </xs:element>\n" + //
"</xs:schema>";
XMLAssert.testDocumentLinkFor(xml, "src/test/resources/xsd/unnamed-integer.xsd");
}

}