Skip to content

Commit

Permalink
Validate XML with DTD/XML Schema by using xml-model
Browse files Browse the repository at this point in the history
See #633

Signed-off-by: azerr <[email protected]>
  • Loading branch information
angelozerr committed May 12, 2020
1 parent 25cf8e4 commit 9f85c03
Show file tree
Hide file tree
Showing 9 changed files with 568 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
import org.eclipse.lemminx.extensions.contentmodel.participants.DTDErrorCode;
import org.eclipse.lemminx.extensions.contentmodel.participants.XMLSchemaErrorCode;
import org.eclipse.lemminx.extensions.contentmodel.participants.XMLSyntaxErrorCode;
import org.eclipse.lemminx.services.extensions.xerces.AbstractLSPErrorReporter;
import org.eclipse.lemminx.extensions.xerces.AbstractLSPErrorReporter;
import org.eclipse.lsp4j.Diagnostic;
import org.eclipse.lsp4j.Range;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,14 @@

import org.apache.xerces.impl.dtd.XMLDTDValidator;
import org.apache.xerces.parsers.XIncludeAwareParserConfiguration;
import org.apache.xerces.xni.XMLDocumentHandler;
import org.apache.xerces.xni.XNIException;
import org.apache.xerces.xni.grammars.XMLGrammarPool;
import org.apache.xerces.xni.parser.XMLComponentManager;
import org.apache.xerces.xni.parser.XMLConfigurationException;
import org.apache.xerces.xni.parser.XMLDocumentSource;
import org.eclipse.lemminx.extensions.contentmodel.settings.XMLValidationSettings;
import org.eclipse.lemminx.extensions.xerces.xmlmodel.XMLModelHandler;

/**
* Custom Xerces XML parser configuration to :
Expand All @@ -34,6 +37,7 @@
class LSPXMLParserConfiguration extends XIncludeAwareParserConfiguration {

private final boolean disableDTDValidation;
private XMLModelHandler xmlModelHandler;

public LSPXMLParserConfiguration(XMLGrammarPool grammarPool, boolean disableDTDValidation,
XMLValidationSettings validationSettings) {
Expand Down Expand Up @@ -90,4 +94,43 @@ public boolean getFeature(String featureId) throws XMLConfigurationException {
}
}

@Override
protected void configurePipeline() {
super.configurePipeline();
configureXMLModelHandler();
}

@Override
protected void configureXML11Pipeline() {
super.configureXML11Pipeline();
configureXMLModelHandler();
}

private void configureXMLModelHandler() {
xmlModelHandler = new XMLModelHandler();
addComponent(xmlModelHandler);

// configure XML document pipeline: insert after DTDValidator and
// before XML Schema validator
XMLDocumentSource prev = null;
//if (fFeatures.get(XMLSCHEMA_VALIDATION) == Boolean.TRUE) {
if (false) {
// we don't have to worry about fSchemaValidator being null, since
// super.configurePipeline() instantiated it if the feature was set
prev = fSchemaValidator.getDocumentSource();
}
// Otherwise, insert after the last component in the pipeline
else {
prev = fLastComponent;
fLastComponent = xmlModelHandler;
}

XMLDocumentHandler next = prev.getDocumentHandler();
prev.setDocumentHandler(xmlModelHandler);
xmlModelHandler.setDocumentSource(prev);
if (next != null) {
xmlModelHandler.setDocumentHandler(next);
next.setDocumentSource(xmlModelHandler);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
* Contributors:
* Angelo Zerr <[email protected]> - initial API and implementation
*/
package org.eclipse.lemminx.services.extensions.xerces;
package org.eclipse.lemminx.extensions.xerces;

import java.util.List;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.eclipse.lemminx.services.extensions.xerces;
package org.eclipse.lemminx.extensions.xerces;

import static org.eclipse.lemminx.dom.parser.Constants.*;
import static org.eclipse.lemminx.utils.StringUtils.getString;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
package org.eclipse.lemminx.extensions.xerces.xmlmodel;

import java.io.IOException;
import java.lang.reflect.Field;

import org.apache.xerces.impl.Constants;
import org.apache.xerces.impl.XMLEntityManager;
import org.apache.xerces.impl.dtd.DTDGrammar;
import org.apache.xerces.impl.dtd.XMLDTDDescription;
import org.apache.xerces.impl.dtd.XMLDTDLoader;
import org.apache.xerces.impl.dtd.XMLDTDValidator;
import org.apache.xerces.util.SymbolTable;
import org.apache.xerces.xni.Augmentations;
import org.apache.xerces.xni.QName;
import org.apache.xerces.xni.XMLAttributes;
import org.apache.xerces.xni.XMLLocator;
import org.apache.xerces.xni.XNIException;
import org.apache.xerces.xni.parser.XMLComponentManager;
import org.apache.xerces.xni.parser.XMLConfigurationException;
import org.apache.xerces.xni.parser.XMLDTDScanner;
import org.apache.xerces.xni.parser.XMLInputSource;

public class XMLModelDTDValidator extends XMLDTDValidator implements XMLModelValidator {

/** Property identifier: entity manager. */
protected static final String ENTITY_MANAGER = Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_MANAGER_PROPERTY;

protected static final String DTD_SCANNER = Constants.XERCES_PROPERTY_PREFIX + Constants.DTD_SCANNER_PROPERTY;

private String href;
private boolean firstElement;
private XMLLocator locator;
private XMLDTDScanner fDTDScanner;
private XMLEntityManager fEntityManager;

public XMLModelDTDValidator() {
firstElement = true;
fDTDValidation = true;
}

@Override
public void setHref(String href) {
this.href = href;
}

@Override
public void setLocator(XMLLocator locator) {
this.locator = locator;
}

@Override
public void startElement(QName element, XMLAttributes attributes, Augmentations augs) throws XNIException {
if (firstElement) {
QName fRootElement = getRootElement();
String rootElement = element.localpart;

// save root element state
fSeenDoctypeDecl = true;
fRootElement.setValues(null, rootElement, rootElement, null);

String eid = null;
try {
eid = XMLEntityManager.expandSystemId(href, locator.getExpandedSystemId(), false);
} catch (java.io.IOException e) {
}
XMLDTDDescription grammarDesc = new XMLDTDDescription(null, href, locator.getExpandedSystemId(), eid,
rootElement);
// fDTDDescription.setValues(fDoctypePublicId, fDoctypeSystemId, null, null);
// fDTDDescription.setRootName(fDoctypeName);
// try {
// XMLInputSource xmlInputSource =
// fEntityManager.resolveEntity(grammarDesc);
// fDTDScanner.setInputSource(xmlInputSource);
// } catch (IOException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }

fDTDGrammar = fGrammarBucket.getGrammar(grammarDesc);
if (fDTDGrammar == null) {
// give grammar pool a chance...
//
// Do not bother checking the pool if no public or system identifier was
// provided.
// Since so many different DTDs have roots in common, using only a root name as
// the
// key may cause an unexpected grammar to be retrieved from the grammar pool.
// This scenario
// would occur when an ExternalSubsetResolver has been queried and the
// XMLInputSource returned contains an input stream but no external identifier.
// This can never happen when the instance document specified a DOCTYPE. --
// mrglavas
if (fGrammarPool != null && (href != null)) {
fDTDGrammar = (DTDGrammar) fGrammarPool.retrieveGrammar(grammarDesc);
}
}
if (fDTDGrammar == null) {

XMLDTDLoader loader = new XMLDTDLoader(fSymbolTable, fGrammarPool);
loader.setEntityResolver(fEntityManager);
try {
fDTDGrammar = (DTDGrammar) loader.loadGrammar(new XMLInputSource(null, eid, null));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else {
// we've found a cached one;so let's make sure not to read
// any external subset!
fValidationManager.setCachedDTD(true);
}
firstElement = false;
}
super.startElement(element, attributes, augs);
}

private QName getRootElement() {
try {
Field f = XMLDTDValidator.class.getDeclaredField("fRootElement");
f.setAccessible(true);
QName fRootElement = (QName) f.get(this);
return fRootElement;
} catch (Exception e) {
return null;
}
}

@Override
public void reset(XMLComponentManager componentManager) throws XMLConfigurationException {
fDTDScanner = (XMLDTDScanner) componentManager.getProperty(DTD_SCANNER);
fEntityManager = (XMLEntityManager) componentManager.getProperty(ENTITY_MANAGER);

super.reset(componentManager);
}
}
Loading

0 comments on commit 9f85c03

Please sign in to comment.