Skip to content

Commit

Permalink
Starts implementing XML completion based on internal DTD (see #251)
Browse files Browse the repository at this point in the history
  • Loading branch information
angelozerr committed Dec 5, 2018
1 parent 2cfa620 commit 8617a8e
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ public CMDocument findCMDocument(DOMElement element, String namespaceURI) {
}

public CMDocument findCMDocument(DOMDocument xmlDocument, String namespaceURI) {
ContentModelProvider modelProvider = getModelProviderByStandardAssociation(xmlDocument);
ContentModelProvider modelProvider = getModelProviderByStandardAssociation(xmlDocument, false);
String systemId = modelProvider != null ? modelProvider.getSystemId(xmlDocument, namespaceURI) : null;
return findCMDocument(xmlDocument.getDocumentURI(), namespaceURI, systemId, modelProvider);
}
Expand Down Expand Up @@ -122,6 +122,35 @@ private CMDocument findCMDocument(String uri, String publicId, String systemId,
return cmDocument;
}

public CMElementDeclaration findInternalCMElement(DOMElement element) throws Exception {
return findInternalCMElement(element, element.getNamespaceURI());
}

/**
* Returns the declared element which matches the given XML element and null
* otherwise.
*
* @param element the XML element
* @return the declared element which matches the given XML element and null
* otherwise.
*/
public CMElementDeclaration findInternalCMElement(DOMElement element, String namespaceURI) throws Exception {
CMDocument cmDocument = findInternalCMDocument(element, namespaceURI);
return cmDocument != null ? cmDocument.findCMElement(element, namespaceURI) : null;
}

public CMDocument findInternalCMDocument(DOMElement element, String namespaceURI) {
return findInternalCMDocument(element.getOwnerDocument(), namespaceURI);
}

public CMDocument findInternalCMDocument(DOMDocument xmlDocument, String namespaceURI) {
ContentModelProvider modelProvider = getModelProviderByStandardAssociation(xmlDocument, true);
if (modelProvider != null) {
return modelProvider.createInternalCMDocument(xmlDocument);
}
return null;
}

/**
* Returns the content model provider by using standard association
* (xsi:schemaLocation, xsi:noNamespaceSchemaLocation, doctype) an dnull
Expand All @@ -132,9 +161,9 @@ private CMDocument findCMDocument(String uri, String publicId, String systemId,
* (xsi:schemaLocation, xsi:noNamespaceSchemaLocation, doctype) an dnull
* otherwise.
*/
private ContentModelProvider getModelProviderByStandardAssociation(DOMDocument xmlDocument) {
private ContentModelProvider getModelProviderByStandardAssociation(DOMDocument xmlDocument, boolean internal) {
for (ContentModelProvider modelProvider : modelProviders) {
if (modelProvider.adaptFor(xmlDocument)) {
if (modelProvider.adaptFor(xmlDocument, internal)) {
return modelProvider;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,18 @@ public interface ContentModelProvider {
* otherwise.
*
* @param document
* @param internal
* @return the content model provider by using standard association
* (xsi:schemaLocation, xsi:noNamespaceSchemaLocation, doctype) an dnull
* otherwise.
*/
boolean adaptFor(DOMDocument document);
boolean adaptFor(DOMDocument document, boolean internal);

boolean adaptFor(String uri);

String getSystemId(DOMDocument xmlDocument, String namespaceURI);

CMDocument createCMDocument(String key);

CMDocument createInternalCMDocument(DOMDocument xmlDocument);
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,14 @@ public class ContentModelCompletionParticipant extends CompletionParticipantAdap
@Override
public void onTagOpen(ICompletionRequest request, ICompletionResponse response) throws Exception {
try {
DOMDocument document = request.getXMLDocument();
ContentModelManager contentModelManager = request.getComponent(ContentModelManager.class);
DOMElement parentElement = request.getParentElement();
if (parentElement == null) {
// XML is empty, in case of XML file associations, a XMl Schema/DTD can be bound
// check if it's root element (in the case of XML file associations, the link to
// XML Schema is done with pattern and not with XML root element)
CMDocument cmDocument = contentModelManager.findCMDocument(request.getXMLDocument(), null);
CMDocument cmDocument = contentModelManager.findCMDocument(document, null);
if (cmDocument != null) {
fillWithChildrenElementDeclaration(null, cmDocument.getElements(), null, false, request, response);
}
Expand Down Expand Up @@ -77,6 +78,13 @@ public void onTagOpen(ICompletionRequest request, ICompletionResponse response)
}
}
}
// Get internal content document (ex : internal DTD declared in XML)
CMElementDeclaration cmInternalElement = contentModelManager.findInternalCMElement(parentElement);
if (cmInternalElement != null) {
defaultPrefix = parentElement.getPrefix();
fillWithChildrenElementDeclaration(parentElement, cmInternalElement.getElements(), defaultPrefix, false,
request, response);
}
} catch (CacheResourceDownloadingException e) {
// XML Schema, DTD is loading, ignore this error
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import org.eclipse.lsp4xml.extensions.contentmodel.model.ContentModelProvider;
import org.eclipse.lsp4xml.uriresolver.URIResolverExtensionManager;
import org.eclipse.lsp4xml.utils.DOMUtils;
import org.eclipse.lsp4xml.utils.StringUtils;

/**
* DTD content model provider.
Expand All @@ -31,7 +32,11 @@ public CMDTDContentModelProvider(URIResolverExtensionManager resolverExtensionMa
}

@Override
public boolean adaptFor(DOMDocument document) {
public boolean adaptFor(DOMDocument document, boolean internal) {
if (internal) {
DOMDocumentType documentType = document.getDoctype();
return documentType != null && !StringUtils.isEmpty(documentType.getInternalSubset());
}
return document.hasDTD();
}

Expand Down Expand Up @@ -66,4 +71,20 @@ public CMDocument createCMDocument(String key) {
}
return null;
}

@Override
public CMDocument createInternalCMDocument(DOMDocument xmlDocument) {
try {
CMDTDDocument document = new CMDTDDocument();
document.setEntityResolver(resolverExtensionManager);
DOMDocumentType documentType = xmlDocument.getDoctype();
String internalSubset = documentType.getInternalSubset();
String baseSystemId = null;
String systemId = null;
document.loadInternalDTD(internalSubset, baseSystemId, systemId);
return document;
} catch (Exception e) {
return null;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
package org.eclipse.lsp4xml.extensions.dtd.contentmodel;

import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
Expand Down Expand Up @@ -116,6 +117,22 @@ public Grammar loadGrammar(XMLInputSource source) throws IOException, XNIExcepti
return grammar;
}

public void loadInternalDTD(String internalSubset, String baseSystemId, String systemId)
throws XNIException, IOException {
// Load empty DTD grammar
XMLInputSource source = new XMLInputSource("", "", "", new StringReader(""), "");
grammar = (DTDGrammar) loadGrammar(source);
// To get the DTD scanner to end at the right place we have to fool
// it into thinking that it reached the end of the internal subset
// in a real document.
fDTDScanner.reset();
StringBuilder buffer = new StringBuilder(internalSubset.length() + 2);
buffer.append(internalSubset).append("]>");
XMLInputSource is = new XMLInputSource(null, baseSystemId, null, new StringReader(buffer.toString()), null);
fEntityManager.startDocumentEntity(is);
fDTDScanner.scanDTDInternalSubset(true, false, systemId != null);
}

void collectElementsDeclaration(String elementName, List<CMElementDeclaration> elements) {
if (hierachiesMap == null) {
return;
Expand All @@ -134,7 +151,7 @@ void collectElementsDeclaration(String elementName, List<CMElementDeclaration> e

void collectAttributesDeclaration(CMDTDElementDeclaration elementDecl, List<CMAttributeDeclaration> attributes) {
int elementDeclIndex = grammar.getElementDeclIndex(elementDecl.name);
int index = grammar.getFirstAttributeDeclIndex(elementDeclIndex);
int index = grammar.getFirstAttributeDeclIndex(elementDeclIndex);
while (index != -1) {
CMDTDAttributeDeclaration attributeDecl = new CMDTDAttributeDeclaration();
grammar.getAttributeDecl(index, attributeDecl);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,10 @@ public CMXSDContentModelProvider(URIResolverExtensionManager resolverExtensionMa
}

@Override
public boolean adaptFor(DOMDocument document) {
public boolean adaptFor(DOMDocument document, boolean internal) {
if (internal) {
return false;
}
return document.hasSchemaLocation() || document.hasNoNamespaceSchemaLocation();
}

Expand Down Expand Up @@ -75,6 +78,11 @@ public CMDocument createCMDocument(String key) {
return null;
}

@Override
public CMDocument createInternalCMDocument(DOMDocument xmlDocument) {
return null;
}

public XSLoaderImpl getLoader() {
if (loader == null) {
loader = getSynchLoader();
Expand Down

0 comments on commit 8617a8e

Please sign in to comment.