Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

XML completion based on DTD with XML catalog and PUBLIC declaration doesn't work #852

Merged
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 @@ -23,6 +23,7 @@
import org.apache.xerces.xni.grammars.XMLGrammarPool;
import org.eclipse.lemminx.dom.DOMDocument;
import org.eclipse.lemminx.dom.DOMElement;
import org.eclipse.lemminx.extensions.contentmodel.model.ContentModelProvider.Identifier;
import org.eclipse.lemminx.extensions.contentmodel.participants.diagnostics.LSPXMLGrammarPool;
import org.eclipse.lemminx.extensions.contentmodel.settings.XMLFileAssociation;
import org.eclipse.lemminx.extensions.contentmodel.uriresolver.XMLCacheResolverExtension;
Expand Down Expand Up @@ -116,10 +117,12 @@ public Collection<CMDocument> findCMDocument(DOMDocument xmlDocument, String nam
// The content model provider can collect the system ids
// ex for <?xml-model , the model provider which takes care of xml-model returns
// the href of xml-model.
Collection<String> systemIds = modelProvider.getSystemIds(xmlDocument, namespaceURI);
for (String systemId : systemIds) {
Collection<Identifier> identifiers = modelProvider.getIdentifiers(xmlDocument, namespaceURI);
for (Identifier identifier : identifiers) {
String systemId = identifier.getSystemId();
String publicId = identifier.getPublicId() != null ? identifier.getPublicId() : namespaceURI;
// get the content model document from the current system id
CMDocument cmDocument = findCMDocument(xmlDocument.getDocumentURI(), namespaceURI, systemId,
CMDocument cmDocument = findCMDocument(xmlDocument.getDocumentURI(), publicId, systemId,
modelProvider);
if (cmDocument != null) {
documents.add(cmDocument);
Expand Down Expand Up @@ -151,9 +154,11 @@ public boolean dependsOnGrammar(DOMDocument document, String grammarURI) {
}
for (ContentModelProvider modelProvider : modelProviders) {
if (modelProvider.adaptFor(document, false)) {
Collection<String> systemIds = modelProvider.getSystemIds(document, document.getNamespaceURI());
for (String systemId : systemIds) {
String key = resolverManager.resolve(document.getDocumentURI(), null, systemId);
Collection<Identifier> identifiers = modelProvider.getIdentifiers(document, document.getNamespaceURI());
for (Identifier identifier : identifiers) {
String publicId = identifier.getPublicId();
String systemId = identifier.getSystemId();
String key = resolverManager.resolve(document.getDocumentURI(), publicId, systemId);
if (grammarURI.equals(key)) {
return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,34 @@
*/
public interface ContentModelProvider {

public class Identifier {

private final String publicId;

private final String systemId;

public Identifier(String publicId, String systemId) {
this.publicId = publicId;
this.systemId = systemId;
}

public String getPublicId() {
return publicId;
}

public String getSystemId() {
return systemId;
}

}

/**
* Returns the content model provider by using standard association
* (xsi:schemaLocation, xsi:noNamespaceSchemaLocation, doctype) an dnull
* otherwise.
*
* @param document
* @param internal
* @param internal
* @return the content model provider by using standard association
* (xsi:schemaLocation, xsi:noNamespaceSchemaLocation, doctype) an dnull
* otherwise.
Expand All @@ -37,7 +58,7 @@ public interface ContentModelProvider {

boolean adaptFor(String uri);

Collection<String> getSystemIds(DOMDocument xmlDocument, String namespaceURI);
Collection<Identifier> getIdentifiers(DOMDocument xmlDocument, String namespaceURI);

CMDocument createCMDocument(String key);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,14 +72,15 @@ public boolean adaptFor(String uri) {
}

@Override
public Collection<String> getSystemIds(DOMDocument xmlDocument, String namespaceURI) {
public Collection<Identifier> getIdentifiers(DOMDocument xmlDocument, String namespaceURI) {
/*
* <!DOCTYPE catalog PUBLIC
* "-//OASIS/DTD Entity Resolution XML Catalog V1.0//EN"
* "http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd">
*/
DOMDocumentType documentType = xmlDocument.getDoctype();
return Collections.singleton(documentType.getSystemIdWithoutQuotes());
return Collections.singleton(
new Identifier(documentType.getPublicIdWithoutQuotes(), documentType.getSystemIdWithoutQuotes()));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,12 @@ public boolean adaptFor(String uri) {
}

@Override
public Collection<String> getSystemIds(DOMDocument xmlDocument, String namespaceURI) {
return xmlDocument.getXMLModels().stream().map(node -> node.getHref())
.filter(href -> !StringUtils.isEmpty(href)).collect(Collectors.toList());
public Collection<Identifier> getIdentifiers(DOMDocument xmlDocument, String namespaceURI) {
return xmlDocument.getXMLModels().stream() //
.map(node -> node.getHref()) //
.filter(href -> !StringUtils.isEmpty(href)) //
.map(href -> new Identifier(null, href)) //
.collect(Collectors.toList());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,13 @@ public boolean adaptFor(String uri) {
}

@Override
public Collection<String> getSystemIds(DOMDocument xmlDocument, String namespaceURI) {
Collection<String> systemIds = new ArrayList<>();
public Collection<Identifier> getIdentifiers(DOMDocument xmlDocument, String namespaceURI) {
Collection<Identifier> identifiers = new ArrayList<>();
SchemaLocation schemaLocation = xmlDocument.getSchemaLocation();
if (schemaLocation != null) {
String location = schemaLocation.getLocationHint(namespaceURI);
if (!StringUtils.isEmpty(location)) {
systemIds.add(location);
identifiers.add(new Identifier(null, location));
}
} else {
NoNamespaceSchemaLocation noNamespaceSchemaLocation = xmlDocument.getNoNamespaceSchemaLocation();
Expand All @@ -70,12 +70,12 @@ public Collection<String> getSystemIds(DOMDocument xmlDocument, String namespace
// xsi:noNamespaceSchemaLocation doesn't define namespaces
String location = noNamespaceSchemaLocation.getLocation();
if (!StringUtils.isEmpty(location)) {
systemIds.add(location);
identifiers.add(new Identifier(null, location));
}
}
}
}
return systemIds;
return identifiers;
}

@Override
Expand All @@ -94,7 +94,7 @@ public CMDocument createInternalCMDocument(DOMDocument xmlDocument) {
return null;
}

public XSLoaderImpl getLoader() {
public XSLoaderImpl getLoader() {
XSLoaderImpl loader = new XSLoaderImpl();
loader.setParameter("http://apache.org/xml/properties/internal/entity-resolver", resolverExtensionManager);
loader.setParameter(Constants.DOM_ERROR_HANDLER, new DOMErrorHandler() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@
*******************************************************************************/
package org.eclipse.lemminx.extensions.contentmodel;

import static org.eclipse.lemminx.XMLAssert.CDATA_SNIPPETS;
import static org.eclipse.lemminx.XMLAssert.COMMENT_SNIPPETS;
import static org.eclipse.lemminx.XMLAssert.DTDNODE_SNIPPETS;
import static org.eclipse.lemminx.XMLAssert.CDATA_SNIPPETS;
import static org.eclipse.lemminx.XMLAssert.PROCESSING_INSTRUCTION_SNIPPETS;
import static org.eclipse.lemminx.XMLAssert.c;
import static org.eclipse.lemminx.XMLAssert.te;
Expand Down Expand Up @@ -241,20 +241,42 @@ public void attributeCompletionWithDoctypeSubsetWithNoElements() throws BadLocat
"xmlns:xsi"));
}

@Test
public void completionWithCatalogAndPublic() throws Exception {
// This test uses the local DTD with catalog-public.xml by using the PUBLIC ID
// -//Sun Microsystems, Inc.//DTD Web Application 2.3//EN
// <public publicId="-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
// uri="../dtd/web-app_2_3.dtd" />
String xml = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?> \r\n" + //
"<!DOCTYPE web-app\r\n" + //
" PUBLIC \"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN\"\r\n" + //
" \"ABCD.dtd\">\r\n" + //
"\r\n" + //
"<web-app>|</web-app>";
testCompletionFor(xml, true, null, "catalog-public.xml",
c("icon", te(5, 9, 5, 9, "<icon>$1</icon>$0"), "icon"), //
c("display-name", te(5, 9, 5, 9, "<display-name>$1</display-name>$0"), "display-name"));
}

private void testCompletionFor(String xml, CompletionItem... expectedItems) throws BadLocationException {
testCompletionFor(xml, true, null, expectedItems);
}

private void testCompletionFor(String xml, boolean isSnippetsSupported, Integer expectedCount,
CompletionItem... expectedItems) throws BadLocationException {
testCompletionFor(xml, isSnippetsSupported, expectedCount, "catalog.xml", expectedItems);
}

private void testCompletionFor(String xml, boolean isSnippetsSupported, Integer expectedCount, String catalog,
CompletionItem... expectedItems) throws BadLocationException {
CompletionCapabilities completionCapabilities = new CompletionCapabilities();
CompletionItemCapabilities completionItem = new CompletionItemCapabilities(isSnippetsSupported); // activate
// snippets
completionCapabilities.setCompletionItem(completionItem);

SharedSettings sharedSettings = new SharedSettings();
sharedSettings.getCompletionSettings().setCapabilities(completionCapabilities);
XMLAssert.testCompletionFor(new XMLLanguageService(), xml, "src/test/resources/catalogs/catalog.xml", null,
null, expectedCount, sharedSettings, expectedItems);
XMLAssert.testCompletionFor(new XMLLanguageService(), xml, "src/test/resources/catalogs/" + catalog, null, null,
expectedCount, sharedSettings, expectedItems);
}
}