Skip to content

Commit

Permalink
XML completion based on DTD with XML catalog and PUBLIC declaration
Browse files Browse the repository at this point in the history
doesn't work

Fixes eclipse-lemminx#849

Signed-off-by: azerr <[email protected]>
  • Loading branch information
angelozerr committed Aug 20, 2020
1 parent f7fcd3d commit e80bdb8
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 22 deletions.
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);
}
}

0 comments on commit e80bdb8

Please sign in to comment.